2009-11-10 6 views
3

instance_exec (Rails 2.3.2를 통해)을 사용하여 클래스의 범위 내에서 블록을 정의하고 호출 할 수 있도록 허용해야합니다. 그러나 일부 블록은 일부 상황에서 일찍 돌아와야하므로 문제가됩니다.주어진 블록에서 instance_exec로 조기 반환하기

내 응용 프로그램은 루비 1.8.6을 사용하여 만들었지 만 1.8.7에서도 실행해야합니다. 두 버전 사이에서 람다에서 돌아 오는 능력이 제거 된 것 같습니다. 1.8.7에서 다음 1.8.6에서 작동하지만 LocalJumpError (예상치 못한 수익을) 던졌습니다 :

class Foo 
    def square(n) 
    n ** 2 
    end 

    def cube(n) 
    n ** 3 
    end 

    def call_block(*args, &block) 
    instance_exec *args, &block 
    end 
end 

block = lambda { |n| 
    return square(n) if n < 5 
    cube(n) 
} 

f = Foo.new 
f.call_block(5, &block) # returns 125 
f.call_block(3, &block) # returns 9 in 1.8.6, throws a LocalJumpError in 1.8.7 

나는, 내가 next 내 블록에 return을 교체하는 경우는 1.8.7에서 작업 얻을 수 있다고 판단 next square(n) if n < 5의 결과는 1.8.6에서 nil입니다.

1.8.6 및 1.8.7에서이 작업을 수행 할 수있는 방법이 있습니까? 조기 반환 대신 분기를 사용하도록 블록을 재구성 할 수 있지만 일부 블록은보다 복잡하고 조기 반환이 필요한 여러 상황이 있음을 알고 있습니다.

또한 루비 1.9에서 코드를 실행하려면이 방법이 더 변경 될 예정입니까?

편집 : 나는 그것이 1.8.6에서 작동하지 1.8.7 이유는 1.8.6가 레일 '구현을 사용하면서 1.8.7가, C 소스에서 instance_exec 자신을 정의하는 것을 발견했습니다. 레일즈 버전으로 1.8.7에서 instance_exec을 오버라이드하면, 그 버전에서도 동작합니다.

답변

1

설명 후 편집 자세한 내용은 post을 참조하십시오. 아무것도에서

class Foo 

    def square(n) 
    n ** 2 
    end 

    def cube(n) 
    n ** 3 
    end 

    def call_block(*args, &block) 
     instance_exec *args, &block 
    end 
end 




def a 
    block = lambda { | n| 
    return square(n) if n < 5 
    cube(n) 
    } 
f = Foo.new 
puts f.call_block(3, &block) # returns 125 
puts "Never makes it here in 1.8.7" 
puts f.call_block(5, &block) # returns 9 in 1.8.6, returns nothing in 1.8.7 
end 

a 

이 코드는 결과가 박았 문 밖에서 반환하기 때문이다.

procs와 lambda의 작동 방식이 1.9에서 변경되었습니다. 그래서 무슨 일이 벌어 지는지 설명하는 데 도움이됩니다.

원래

나는 코드를 리팩토링과 모든 3 VM 년대에서 일했다. 흥미롭게도 예외없이 코드가 1.9 미만으로 실행되었습니다.

class Foo 

    def square(n) 
    n ** 2 
    end 

    def cube(n) 
    n ** 3 
    end 

    def call_block(*args, &block) 
    block.call(self, *args) 
    end 
end 

block = lambda { |obj, n| 
    return obj.square(n) if n < 5 
    obj.cube(n) 
} 

f = Foo.new 
puts f.call_block(5, &block) # returns 125 
puts f.call_block(3, &block) # returns 9 

post은 통찰력이 있습니다.

+0

귀하의 리펙토링이 작동하기 때문에 이것을 투표했습니다. 그러나 instance_exec 사용의 요점은 객체가 블록으로 전달 될 필요가 없기 때문입니다. 이것은 (코드의) 사용자가 자신의 명령을 생성 할 수있는 템플릿 엔진의 일부이므로 최대한 간단하게 만들고 싶었습니다. –

+0

알겠습니다. 이해합니다. 사용자가 블록을 정의합니다. 루비 1.9에서는 코드가 잘 작동했지만 1.8.7에서는 문제가 없다는 것이 흥미 롭습니다. Instance_exec는 1.8.7 및 1.9에만 존재합니다. Rails는 Active_support에서 자체 버전을 추가하여 1.8.6에서 사용할 수있었습니다. – coreypurcell

+0

지금 무슨 일이 벌어지고 있는지 이해하고 있다고 생각합니다. 편집을 참조하십시오. – coreypurcell