2010-08-08 6 views
2

때때로 당신은 볼 수 있습니다Ruby에서 블록의 클래스/객체 메소드를 제공하는 방법은 무엇입니까?

do_this do 
    available_method1 "arg1" 
    available_method2 "arg1" 
end 

을 그때 내가 그 블록 내에서 사용할 수있는 몇 가지 방법을 얻을 do_this 방법에서 블록을 사용합니다.

이것이 어떻게 이루어 졌는가? 코드는 어떻게 보이지 않는가?

블록을 통해 몇 가지 방법을 제공하고 싶습니다.

답변

4

도메인 별 언어 (DSL)라고합니다. Here's(Last archived version) 다양한 형태의 Ruby DSL 블록에 대한 훌륭한 정보.

정말 다른 구문으로,이 일에 대해 이동하는 방법은 두 가지가 있습니다

do_thing do |thing| # with a block parameter 
    thing.foo :bar 
    thing.baz :wibble 
end 

# versus 

do_thing do # with block-specific methods 
    foo :bar 
    baz :wibble 
end 

두 번째는 더 간결하면서 첫 번째는, 더 명시 적으로 실패 가능성이 적습니다.

제 단순히 yield 갖는 블록 파라미터로서 새로운 인스턴스를 전달하여, 그래서 다음과 같이 구현 될 수

:

class MyThing 
    def self.create 
    yield new 
    end 

    def foo(stuff) 
    puts "doing foo with #{stuff}" 
    end 
end 

MyThing.create do |thing| 
    thing.foo :bar 
end 

하고주는 새로운 개체의 컨텍스트의 블록을 실행하는 두 번째 self에 대한 액세스, 인스턴스 변수 및 방법 :

:

class MyThing 
    def self.create(&block) 
    new.instance_eval &block 
    end 

    def foo(stuff) 
    puts "doing foo with #{stuff}" 
    end 
end 

MyThing.create do 
    foo :bar 
end 

그리고 당신은 정말, MyThing.create를 호출하지 않고 그것을 수행하려는 경우

def create_thing(&block) 
    MyThing.create &block 
end 
+0

이런 종류의 예제가있는 소스가 있습니까? 이와 같이 루비 코드로 설명 된 다양한 디자인 패턴을 갖는 것이 좋을 것입니다. –

2

일반적으로 instance_eval을 사용하여 블록 내부의 self 값을 다른 객체로 변경하면 해당 객체 호출이 처리됩니다. 간단한 예를 들어

:

class ExampleReceiver 
    def available_method1 arg ; p [:available_method1, arg] ; end 
    def available_method2 arg ; p [:available_method2, arg] ; end 
end 
def do_this(&blk) ; ExampleReceiver.new.instance_eval(&blk) ; end 

do_this do 
    available_method1 "arg1" #=> [:available_method1, "arg1"] 
    available_method2 "arg1" #=> [:available_method2, "arg1"] 
end 

이 강력한 언어 기능, 그리고 큰 효과로 이전에 사용 하였지만는 여전히 좋은 생각이나하지 여부에 대한 논쟁이있다. 무슨 일이 일어나고 있는지 모르겠 으면 의 현재 값과 관련이 있으므로 @some_instance_variable 값이 블록 안팎에서 변경된다는 사실에 놀라실 수 있습니다.

자세한 내용과 자세한 내용은 Daniel Azuma's excellent article을 참조하십시오.

관련 문제