Вопрос

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

Привет,

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

То, что я пытался сделать:

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

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

Джо

Это было полезно?

Решение

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

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

Другие советы

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

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

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

eval code

который вернет ruby lamda.

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

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

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

Попробуй ruby2руби

Я обнаружил, что 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 определен в файле, вы можете получить местоположение файла proc, затем сериализовать его, а затем после десериализации использовать местоположение, чтобы снова вернуться к процессу

proc_location_array = proc.source_location

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

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

номер строки = proc_location_array[1]

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

proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.длина]

proc = eval("лямбда #{proc_hash_string}")

Когда-то давно это было возможно с помощью ruby-internal gem (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 (на MRI) или байт-кода (на YARV) нетривиальна.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top