Hoe kan ek 'n lambda (Prok) in Ruby veiligheidsbeampte?
-
09-06-2019 - |
Vra
Joe Van Dyk gevra die Ruby poslys :
Hi,
In Ruby, ek dink jy kan 'n lambda / proc voorwerp nie beampte, reg? is wat moontlik in lisp of ander tale?
Wat ek probeer doen:
l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)
So, Ek stuur BackgroundJob n lambda voorwerp, wat die bevat konteks /-kode vir wat om te doen. Maar, dink dit nie moontlik was. Ek beland Kombineer 'n normale robyn voorwerp wat instruksies vervat vir wat om te doen na die program hardloop.
Joe
Oplossing
Jy kan 'n Lambda of Proc nie veiligheidsbeamptes gebruik nie. Dit is omdat beide van hulle word beskou as sluitings, wat beteken dat hulle toe te maak om die geheue waarop hulle gedefinieer en kan dit verwys. (Ten einde hulle veiligheidsbeampte jy wil hê om al die geheue wat hulle kon bekom ten tyde hulle geskape Marshal.)
As Gaius het daarop gewys al is, kan jy gebruik ruby2ruby om 'n houvas van die string van die kry program. Dit wil sê, jy kan die string wat die robyn kode verteenwoordig veiligheids- dan herevalueer dit later.
Ander wenke
jy kan ook gaan net jou kode as 'n string:
code = %{
lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}
dan voer dit met eval
eval code
wat sal 'n robyn Lamda terugkeer.
met behulp van die %{}
formaat ontsnap 'n string, maar net sluit op 'n onvergelykbare stut. maw jy kan nes draadjies soos hierdie %{ [] {} }
en dit is nog steeds ingesluit.
die meeste teks sintaksis highlighters nie besef dit is 'n string, so nog vertoon gereelde kode beklemtoon.
As jy belangstel om 'n string weergawe van Ruby-kode behulp Ruby2Ruby is, kan jy wil hierdie draad .
Probeer ruby2ruby
Ek het proc_to_ast gevind om die beste werk te doen: https://github.com/joker1007/proc_to_ast'n>.
Werk vir seker in robyn 2+, en ek het 'n PR vir Ruby 1.9.3+ verenigbaarheid geskep ( https://github.com/joker1007/proc_to_ast/pull/3 )
As processed in 'n lêer word gedefinieer, U kan die lêer ligging van processed kry dan afleveringen dit, dan na deserialize gebruik die plek om terug na die proc weer kry
proc_location_array = proc.source_location
na deserialize:
FILE_NAME = 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]
processed = eval ( "lambda # {proc_hash_string}")
Eens op 'n tyd, dit was moontlik die gebruik van Ruby-interne juweel ( https://github.com / cout / Ruby-interne ), bv:
p = proc { 1 + 1 } #=> #<Proc>
s = Marshal.dump(p) #=> #<String>
u = Marshal.load(s) #=> #<UnboundProc>
p2 = u.bind(binding) #=> #<Proc>
p2.call() #=> 2
Daar is 'n paar voorbehoude, maar dit het baie jare en ek kan nie onthou die besonderhede. As 'n voorbeeld, ek is nie seker wat gebeur as 'n veranderlike is 'n dynvar in die binding waar dit gestort en 'n plaaslike in die binding waar dit weer gebind. Serializeren n AST (op MRI) of bytecode (op YARV) is nie-triviale.
Die bogenoemde kode werk op YARV (tot 1.9.3) en MRI (tot 1.8.7). Daar is geen rede waarom dit nie gedoen kan word om te werk op Ruby 2.x, met 'n klein hoeveelheid moeite.