Ruby에서 람다(Proc)를 어떻게 마샬링합니까?
-
09-06-2019 - |
문제
조 반 다이크 Ruby 메일링 리스트에 질문했습니다.:
안녕,
Ruby에서는 람다/proc 개체를 마샬링할 수 없는 것 같습니다. 그렇죠?LISP 또는 다른 언어로 가능합니까?
내가 하려고 했던 것:
l = lamda { ... }
Bj.submit "/path/to/ruby/program", :stdin => Marshal.dump(l)
그래서 저는 BackgroundJob에 Lambda 객체를 보내고 있습니다. 여기에는해야 할 일에 대한 컨텍스트/코드가 포함되어 있습니다.하지만, 그건 불가능했을 것 같아요.나는 프로그램이 실행 된 후해야 할 일에 대한 지침이 포함 된 일반 루비 객체를 마샬링했습니다.
조
해결책
Lambda 또는 Proc을 마샬링할 수 없습니다.이는 둘 다 클로저로 간주되기 때문입니다. 즉, 정의된 메모리 주변을 닫고 이를 참조할 수 있다는 의미입니다.(마샬링하려면 생성 당시 액세스할 수 있는 모든 메모리를 마샬링해야 합니다.)
Gaius가 지적했듯이 다음을 사용할 수 있습니다. 루비2루비 프로그램의 문자열을 얻으려면.즉, 루비 코드를 나타내는 문자열을 마샬링한 다음 나중에 다시 평가할 수 있습니다.
다른 팁
코드를 문자열로 입력할 수도 있습니다.
code = %{
lambda {"hello ruby code".split(" ").each{|e| puts e + "!"}}
}
그런 다음 eval로 실행하십시오.
eval code
그러면 루비 람다가 반환됩니다.
사용하여 %{}
format은 문자열을 이스케이프하지만 일치하지 않는 중괄호에서만 닫힙니다.즉.이렇게 중괄호를 중첩할 수 있습니다 %{ [] {} }
그리고 그것은 여전히 동봉되어 있습니다.
대부분의 텍스트 구문 강조 표시기는 이것이 문자열임을 인식하지 못하므로 여전히 일반 코드 강조 표시를 표시합니다.
Ruby2Ruby를 사용하여 문자열 버전의 Ruby 코드를 얻는 데 관심이 있다면 다음을 참조하세요. 이 스레드.
노력하다 루비2루비
나는 proc_to_ast가 최고의 작업을 수행한다는 것을 알았습니다. https://github.com/joker1007/proc_to_ast.
Ruby 2+에서는 확실히 작동하며 Ruby 1.9.3+ 호환성에 대한 PR을 만들었습니다(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(파일_이름)[line_number - 1]
proc_hash_string = proc_line_code[proc_line_code.index("{")..proc_line_code.length]
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에서 작동하지 못할 이유가 없습니다.