Frage

Joe Van Dyk fragte die Ruby-Mailingliste:

Hallo,

In Ruby kann man wohl kein Lambda/Proc-Objekt marshallen, oder?Ist das in Lisp oder anderen Sprachen möglich?

Was ich versucht habe:

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

Also sende ich Hintergrundjob ein Lambda -Objekt, das den Kontext/Code enthält, was zu tun ist.Aber ich schätze, das war nicht möglich.Am Ende habe ich ein normales Ruby -Objekt gesucht, das Anweisungen für das enthielt, was nach dem Programm geführt zu werden.

Joe

War es hilfreich?

Lösung

Sie können kein Lambda oder Proc bereitstellen.Dies liegt daran, dass beide als Abschlüsse betrachtet werden, was bedeutet, dass sie sich um den Speicher schließen, für den sie definiert wurden, und darauf verweisen können.(Um sie zu marshalieren, müssten Sie den gesamten Speicher marshalieren, auf den sie zum Zeitpunkt ihrer Erstellung zugreifen konnten.)

Wie Gaius jedoch betonte, können Sie Folgendes verwenden ruby2ruby um an die Zeichenfolge des Programms zu gelangen.Das heißt, Sie können die Zeichenfolge, die den Ruby-Code darstellt, Marshallen und ihn später erneut auswerten.

Andere Tipps

Sie können Ihren Code auch einfach als Zeichenfolge eingeben:

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

dann führe es mit eval aus

eval code

was ein rubinrotes Lamda zurückgibt.

Verwendung der %{} format maskiert eine Zeichenfolge, schließt jedoch nur mit einer nicht übereinstimmenden Klammer.d.h.Sie können Klammern so verschachteln %{ [] {} } und es ist immer noch eingeschlossen.

Die meisten Textsyntaxhervorhebungen erkennen nicht, dass es sich hierbei um eine Zeichenfolge handelt, und zeigen daher weiterhin die normale Codehervorhebung an.

Wenn Sie daran interessiert sind, mit Ruby2Ruby eine String-Version von Ruby-Code zu erhalten, könnte Sie das interessieren dieser Thread.

Versuchen ruby2ruby

Ich habe festgestellt, dass proc_to_ast die beste Arbeit leistet: https://github.com/joker1007/proc_to_ast.

Funktioniert auf jeden Fall in Ruby 2+ und ich habe eine PR für die Kompatibilität mit Ruby 1.9.3+ erstellt(https://github.com/joker1007/proc_to_ast/pull/3)

Wenn proc in einer Datei definiert ist, können Sie den Dateispeicherort von proc ermitteln, ihn dann serialisieren und nach der Deserialisierung den Speicherort verwenden, um wieder zum proc zurückzukehren

proc_location_array = proc.source_location

nach der Deserialisierung:

Dateiname = proc_location_array[0]

line_number = proc_location_array[1]

proc_line_code = IO.readlines(file_name)[line_number - 1]

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

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

Es war einmal, dass dies mit einem Rubin-internen Edelstein möglich war (https://github.com/cout/ruby-internal), z.B.:

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

Es gibt einige Vorbehalte, aber es ist viele Jahre her und ich kann mich nicht an die Details erinnern.Ich bin mir beispielsweise nicht sicher, was passiert, wenn eine Variable ein Dynvar in der Bindung ist, in der sie abgelegt wird, und eine lokale Variable in der Bindung, in der sie erneut gebunden wird.Die Serialisierung eines AST (bei MRI) oder Bytecodes (bei YARV) ist nicht trivial.

Der obige Code funktioniert auf YARV (bis 1.9.3) und MRI (bis 1.8.7).Es gibt keinen Grund, warum es nicht mit geringem Aufwand auf Ruby 2.x zum Laufen gebracht werden kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top