Как мне организовать лямбду (Proc) в Ruby? - PullRequest
21 голосов
/ 23 августа 2008

Джо Ван Дейк спросил список рассылки Ruby :

Привет

В Ruby, я думаю, вы не можете маршалировать объект лямбда / процесс, верно? Является что можно на лиспе или других языках?

Что я пытался сделать:

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

Итак, я отправляю BackgroundJob лямбда-объект, который содержит контекст / код, что делать. Но, думаю, это было невозможно. я закончил маршалинг обычного объекта ruby, который содержал инструкции что делать после запуска программы.

Джо

Ответы [ 7 ]

21 голосов
/ 02 сентября 2008

Вы не можете маршалировать лямбду или проц. Это потому, что оба они считаются замыканиями, что означает, что они закрывают память, в которой они были определены, и могут ссылаться на нее. (Для того чтобы их маршалировать, вам нужно было бы маршалу использовать всю память, к которой они могли обращаться в момент их создания.)

Как указал Гай, вы можете использовать ruby2ruby , чтобы получить строку программы. Таким образом, вы можете упорядочить строку, представляющую код ruby, а затем пересмотреть ее позже.

11 голосов
/ 14 сентября 2010

Вы также можете просто ввести свой код в виде строки:

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

затем выполните его с помощью eval

eval code

, который вернет рубиновую лямду.

с использованием формата %{} экранирует строку, но закрывается только на непревзойденную фигурную скобку. то есть вы можете вкладывать фигурные скобки, как это %{ [] {} }, и они все еще закрыты.

большинство текстовых подсветок синтаксиса не понимают, что это строка, поэтому все равно отображают обычную подсветку кода.

4 голосов
/ 04 марта 2010

Если вы заинтересованы в получении строковой версии кода Ruby с использованием Ruby2Ruby, вам может понравиться эта тема .

3 голосов
/ 23 августа 2008

Попробуйте ruby2ruby

1 голос
/ 10 ноября 2015

Я нашел proc_to_ast для лучшей работы: https://github.com/joker1007/proc_to_ast.

Работает наверняка в ruby ​​2+, и я создал PR для совместимости с ruby ​​1.9.3+ (https://github.com/joker1007/proc_to_ast/pull/3)

0 голосов
/ 16 сентября 2018

Когда-то это было возможно с использованием внутреннего камня ruby ​​(https://github.com/cout/ruby-internal), например ::100100 *

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

Есть некоторые предостережения, но прошло много лет, и я не могу вспомнить детали. В качестве примера, я не уверен, что произойдет, если переменная является dynvar в привязке, где она выгружается, и локальной в привязке, где она перепривязывается. Сериализация AST (на МРТ) или байт-кода (на YARV) нетривиальна.

Приведенный выше код работает на YARV (до 1.9.3) и MRI (до 1.8.7). Нет причин, по которым он не может работать на Ruby 2.x при небольших затратах.

0 голосов
/ 11 апреля 2017

Если proc определен в файле, U может получить местоположение файла proc, затем сериализовать его, а затем после десериализации использовать местоположение, чтобы вернуться к proc снова

proc_location_array = proc.source_location

после десериализации:

имя_файла = proc_location_array [0]

line_number = proc_location_array [1]

proc_line_code = IO.readlines (имя_файла) [номер_строки - 1]

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

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

...