Pergunta

Joe Van Dyk perguntou a lista de discussão Ruby:

Oi,

Em Ruby, acho que você não pode empacotar um objeto lambda/proc, certo?Isso é possível em Lisp ou outros idiomas?

O que eu estava tentando fazer:

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

Então, estou enviando um objeto Lambda, que contém o contexto/código para o que fazer.Mas, acho que isso não foi possível.Acabei organizando um objeto Ruby normal que continha instruções para o que fazer após a execução do programa.

Joe

Foi útil?

Solução

Você não pode empacotar um Lambda ou Proc.Isso ocorre porque ambos são considerados fechamentos, o que significa que fecham em torno da memória na qual foram definidos e podem referenciá-la.(Para organizá-los, você teria que empacotar toda a memória que eles poderiam acessar no momento em que foram criados.)

Como Gaius apontou, você pode usar ruby2ruby para obter a string do programa.Ou seja, você pode empacotar a string que representa o código Ruby e reavaliá-la posteriormente.

Outras dicas

você também pode simplesmente inserir seu código como uma string:

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

então execute-o com eval

eval code

que retornará um lamda Ruby.

usando o %{} format escapa de uma string, mas fecha apenas em uma chave sem correspondência.ou sejavocê pode aninhar chaves assim %{ [] {} } e ainda está fechado.

a maioria dos realçadores de sintaxe de texto não percebe que se trata de uma string, portanto ainda exibe realce de código regular.

Se você estiver interessado em obter uma versão string do código Ruby usando Ruby2Ruby, você pode gostar este tópico.

Tentar ruby2ruby

Descobri que proc_to_ast faz o melhor trabalho: https://github.com/joker1007/proc_to_ast.

Funciona com certeza em Ruby 2+, e criei um PR para compatibilidade com Ruby 1.9.3+ (https://github.com/joker1007/proc_to_ast/pull/3)

Se proc for definido em um arquivo, você poderá obter a localização do arquivo de proc, serializá-lo e, após desserializar, usar o local para voltar ao proc novamente

proc_location_array = proc.source_location

depois de desserializar:

nome_arquivo = proc_location_array[0]

número_linha = proc_location_array[1]

proc_line_code = IO.readlines(nome_do_arquivo)[número_da_linha - 1]

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

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

Era uma vez, isso era possível usando a gema interna do Ruby (https://github.com/cout/ruby-internal), por exemplo.:

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

Há algumas ressalvas, mas já se passaram muitos anos e não consigo me lembrar dos detalhes.Por exemplo, não tenho certeza do que acontece se uma variável for um dynvar na ligação onde é despejada e um local na ligação onde é religada.Serializar um AST (em MRI) ou bytecode (em YARV) não é trivial.

O código acima funciona em YARV (até 1.9.3) e MRI (até 1.8.7).Não há razão para que ele não possa funcionar em Ruby 2.x, com um pequeno esforço.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top