Domanda

Joe Van Dyk ha chiesto alla mailing list di Ruby:

CIAO,

In Ruby, immagino che non sia possibile eseguire il marshalling di un oggetto lambda/proc, giusto?È che è possibile in LISP o in altre lingue?

Quello che stavo cercando di fare:

l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)

Quindi, sto inviando a BackgroundJob un oggetto lambda, che contiene il contesto/codice per cosa fare.Ma immagino che non fosse possibile.Io ha finito per eseguire il marshalling di un normale oggetto Ruby che conteneva istruzioni per cosa fare dopo l'esecuzione del programma.

Joe

È stato utile?

Soluzione

Non è possibile effettuare il marshalling di un Lambda o di un Proc.Questo perché entrambi sono considerati chiusure, cioè si chiudono attorno alla memoria su cui sono stati definiti e possono fare riferimento ad essa.(Per effettuare il marshalling dovresti effettuare il marshalling di tutta la memoria a cui potrebbero accedere nel momento in cui sono stati creati.)

Come ha sottolineato Gaius, però, puoi usare rubino2ruby per ottenere la stringa del programma.Cioè, puoi effettuare il marshalling della stringa che rappresenta il codice Ruby e quindi rivalutarla in seguito.

Altri suggerimenti

potresti anche semplicemente inserire il tuo codice come una stringa:

code = %{
    lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}

quindi eseguilo con eval

eval code

che restituirà un lambda rubino.

usando il %{} format evita una stringa, ma si chiude solo con una parentesi graffa senza corrispondenza.cioè.puoi annidare le parentesi graffe in questo modo %{ [] {} } ed è ancora chiuso.

la maggior parte degli evidenziatori della sintassi del testo non si rendono conto che si tratta di una stringa, quindi visualizza comunque l'evidenziazione regolare del codice.

Se sei interessato a ottenere una versione stringa del codice Ruby utilizzando Ruby2Ruby, potrebbe piacerti questo filo.

Tentativo rubino2ruby

Ho trovato proc_to_ast per fare il lavoro migliore: https://github.com/joker1007/proc_to_ast.

Funziona sicuramente con Ruby 2+ e ho creato un PR per la compatibilità con Ruby 1.9.3+(https://github.com/joker1007/proc_to_ast/pull/3)

Se proc è definito in un file, U può ottenere il percorso del file di proc quindi serializzarlo, quindi dopo la deserializzazione utilizzare la posizione per tornare nuovamente a proc

proc_location_array = proc.source_location

dopo la deserializzazione:

nome_file = matrice_posizione_proc[0]

numero_linea = matrice_posizione_proc[1]

proc_line_code = IO.readlines(nome_file)[numero_riga - 1]

proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.length]

proc = eval("lambda #{proc_hash_string}")

Un tempo questo era possibile utilizzando la gemma interna del rubino (https://github.com/cout/ruby-internal), per esempio.:

p = proc { 1 + 1 }    #=> #<Proc>
s = Marshal.dump(p)   #=> #<String>
u = Marshal.load(s)   #=> #<UnboundProc>
p2 = u.bind(binding)  #=> #<Proc>
p2.call()             #=> 2

Ci sono alcuni avvertimenti, ma sono passati molti anni e non riesco a ricordare i dettagli.Ad esempio, non sono sicuro di cosa succede se una variabile è una dynvar nell'associazione in cui viene scaricata e una locale nell'associazione in cui viene riassociata.Serializzare un AST (su MRI) o un bytecode (su YARV) non è banale.

Il codice sopra funziona su YARV (fino a 1.9.3) e MRI (fino a 1.8.7).Non c'è motivo per cui non possa essere fatto funzionare su Ruby 2.x, con un piccolo sforzo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top