Question

Joe Van Dyk a demandé à la liste de diffusion Ruby:

Salut,

Dans Ruby, je suppose que vous ne pouvez pas rassembler un objet lambda/proc, n'est-ce pas ?Est-ce possible dans LISP ou d'autres langues?

Ce que j'essayais de faire :

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

Donc, j'envoie des antécédents à un objet Lambda, qui contient le contexte / le code pour quoi faire.Mais je suppose que ce n’était pas possible.Je a fini par marshaler un objet Ruby normal qui contenait des instructions pour savoir ce qu’il faut faire après l’exécution du programme.

Joe

Était-ce utile?

La solution

Vous ne pouvez pas rassembler un Lambda ou un Proc.En effet, les deux sont considérés comme des fermetures, ce qui signifie qu'ils se ferment autour de la mémoire sur laquelle ils ont été définis et peuvent y faire référence.(Pour les rassembler, vous devrez rassembler toute la mémoire à laquelle ils pouvaient accéder au moment de leur création.)

Comme Gaius l'a souligné, vous pouvez utiliser rubis2rubis pour mettre la main sur la chaîne du programme.Autrement dit, vous pouvez rassembler la chaîne qui représente le code Ruby, puis la réévaluer ultérieurement.

Autres conseils

vous pouvez également simplement saisir votre code sous forme de chaîne :

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

puis exécutez-le avec eval

eval code

ce qui renverra un lamda rubis.

en utilisant le %{} format échappe à une chaîne, mais se ferme uniquement sur une accolade sans correspondance.c'est à dire.vous pouvez imbriquer des accolades comme ceci %{ [] {} } et il est toujours fermé.

la plupart des surligneurs de syntaxe de texte ne réalisent pas qu'il s'agit d'une chaîne, ils affichent donc toujours une surbrillance normale du code.

Si vous souhaitez obtenir une version chaîne du code Ruby en utilisant Ruby2Ruby, vous aimerez peut-être ce fil.

Essayer rubis2rubis

J'ai trouvé que proc_to_ast faisait le meilleur travail : https://github.com/joker1007/proc_to_ast.

Fonctionne à coup sûr dans Ruby 2+, et j'ai créé un PR pour la compatibilité Ruby 1.9.3+ (https://github.com/joker1007/proc_to_ast/pull/3)

Si proc est défini dans un fichier, vous pouvez obtenir l'emplacement du fichier proc puis le sérialiser, puis après la désérialisation, utiliser l'emplacement pour revenir à nouveau au proc

proc_location_array = proc.source_location

après désérialisation :

nom_fichier = proc_location_array[0]

numéro_ligne = 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}")

Il était une fois, cela était possible en utilisant une gemme interne au rubis (https://github.com/cout/ruby-internal), par exemple.:

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

Il y a quelques réserves, mais cela fait de nombreuses années et je ne me souviens pas des détails.À titre d'exemple, je ne suis pas sûr de ce qui se passe si une variable est une dynvar dans la liaison où elle est sauvegardée et une variable locale dans la liaison où elle est liée à nouveau.La sérialisation d'un AST (sur IRM) ou d'un bytecode (sur YARV) n'est pas triviale.

Le code ci-dessus fonctionne sur YARV (jusqu'à 1.9.3) et MRI (jusqu'à 1.8.7).Il n'y a aucune raison pour que cela ne puisse pas fonctionner sur Ruby 2.x, avec un petit effort.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top