문제

루비 코드에 람다/프로 크를 쓸 수 있고, 디스크에 쓸 수 있도록 직렬화 한 다음 나중에 람다를 실행할 수 있기를 원합니다. 일종의 ...

x = 40
f = lambda { |y| x + y }
save_for_later(f)

나중에, 루비 통역사의 별도의 실행에서 나는 말할 수 있기를 원한다 ...

f = load_from_before
z = f.call(2)
z.should == 42

Marshal.dump는 Procs에서 작동하지 않습니다. 나는 Perl이 가지고 있다는 것을 알고 있습니다 데이터 :: 덤프 :: 스 트리머, 그리고 lisp에서 이것은 사소합니다. 그러나 루비에서 할 수있는 방법이 있습니까? 다시 말해, 구현은 무엇입니까 save_for_later?

편집하다: 아래의 대답 좋지만 무료 변수 (예 : x) 그리고 람다와 함께 직렬화하십시오. 그래서 내 예에서 ...

x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n  (x + y)\n}"

... 문자열 출력에는에 대한 정의가 포함되어 있지 않습니다. x. 기호 테이블을 직렬화하여이를 고려하는 솔루션이 있습니까? 루비에서 액세스 할 수 있습니까?

편집 2: Serializing 로컬 변수를 통합하기 위해 답변을 업데이트했습니다. 이것은 받아 들여질 것 같습니다.

도움이 되었습니까?

해결책

Ruby2Ruby를 사용하십시오

def save_for_later(&block)
  return nil unless block_given?

  c = Class.new
  c.class_eval do
    define_method :serializable, &block
  end
  s = Ruby2Ruby.translate(c, :serializable)
  s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1|').sub(/end$/, '}')
end

x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n  (x + y)\n}"
g = eval(s)
# => #<Proc:0x4037bb2c@(eval):1>
g.call(2) 
# => 42

이것은 훌륭하지만 자유 변수에 비해 닫히지 않습니다 ( x) 그리고 람다와 함께 직렬화하십시오.

에게 변수 직렬화 또한 반복 할 수 있습니다 local_variables 그리고 그것들도 직렬화합니다. 그러나 문제는 그 것입니다 local_variables 안으로부터 save_for_later 만 액세스합니다 c 그리고 s 위의 코드에서 - 즉 발신자가 아닌 직렬화 코드에 로컬로 변수. 불행히도, 우리는 로컬 변수와 그 값의 값을 발신자에게 밀어야합니다.

어쩌면 이것은 좋은 일일 수 있습니다. 일반적으로 루비 코드에서 모든 자유 변수를 찾는 것은 명확하지 않습니다. 또한 이상적으로는 저장합니다 global_variables 그리고로드 된 클래스와 그 재정의 방법. 이것은 비현실적인 것 같습니다.

이 간단한 접근 방식을 사용하면 다음을 얻을 수 있습니다.

def save_for_later(local_vars, &block)
  return nil unless block_given?

  c = Class.new
  c.class_eval do
    define_method :serializable, &block
  end
  s = Ruby2Ruby.translate(c, :serializable)
  locals = local_vars.map { |var,val| "#{var} = #{val.inspect}; " }.join
  s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1| ' + locals).sub(/end$/, '}')
end

x = 40
s = save_for_later(local_variables.map{ |v| [v,eval(v)] }) { |y| x + y }
# => "lambda { |y| _ = 40; x = 40;\n  (x + y)\n}"

# In a separate run of Ruby, where x is not defined...
g = eval("lambda { |y| _ = 40; x = 40;\n  (x + y)\n}")
# => #<Proc:0xb7cfe9c0@(eval):1>
g.call(2)
# => 42

# Changing x does not affect it.
x = 7
g.call(3)
# => 43

다른 팁

사용 sourcify

이것은 루비 1.8 또는 1.9에서 작동합니다.

def save_for_later(&block)
  block.to_source
end

x = 40
s = save_for_later {|y| x + y }
# => "proc { |y| (x + y) }"
g = eval(s)
# => #<Proc:0x00000100e88450@(eval):1>
g.call(2) 
# => 42

보다 내 다른 대답 무료 변수를 캡처합니다.

업데이트: 이제 당신은 또한 사용할 수 있습니다 Serializable_proc Sourcify를 사용하고 로컬, 인스턴스, 클래스 및 글로벌 변수를 캡처하는 GEM.

답변을 확인하십시오 이 질문.

루비에는 전화 할 수있는 덤프 방법이있는 마샬 클래스가 있습니다.

여기를 참조하십시오.

http://rubylearning.com/satishtalim/object_serialization.html

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top