Джо Ван Дайк спросил список рассылки Ruby :
Здравствуй,
В Ruby, я полагаю, вы не можете маршалировать объект лямбда / процесс, верно? Это возможно в lisp или других языках?
Что я пытался сделать:
l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)
Итак, я отправляю BackgroundJob лямбда-объект, который содержит контекст / код для того, что делать. Но, думаю, это было невозможно. Я закончил маршалингом обычного объекта ruby, который содержал инструкции о том, что делать после запуска программы.
Джо
Вы не можете маршалировать лямбда или проц. Это потому, что оба они считаются замыканиями, что означает, что они закрывают память, в которой они были определены, и могут ссылаться на нее. (Для того, чтобы их маршалировать, вам нужно было бы маршалу всю память, к которой они могли получить доступ во время их создания.)
Однако, как отметил Гай, вы можете использовать ruby2ruby, чтобы взять строку программы. Таким образом, вы можете упорядочить строку, которая представляет код ruby, а затем пересмотреть ее позже.
Попробуй ruby2ruby
Если вы заинтересованы в получении строковой версии кода Ruby с использованием Ruby2Ruby, вам может понравиться этот поток .
Вы также можете просто ввести свой код в виде строки:
code = %{
lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}
затем выполнить его с помощью eval
eval code
который вернет рубиновую лямду.
использование %{}
формата экранирует строку, но закрывает только непревзойденную фигурную скобку. то есть вы можете вложить такие скобки, %{ [] {} }
и они все еще закрыты.
большинство текстовых подсветок синтаксиса не понимают, что это строка, поэтому все равно отображают обычную подсветку кода.
Я нашел 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 )
Если в файле определен 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}")
Когда-то это было возможно с использованием гема ruby-internal ( https://github.com/cout/ruby-internal ), например:
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) и МРТ (до 1.8.7). Нет никаких причин, по которым он не может работать на Ruby 2.x с небольшими усилиями.