2010-08-08 194 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

這種例子有什麼資源嗎?用這樣的ruby代碼來描述各種設計模式是很好的。 – 2010-08-29 03:56:50

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的值在塊內外發生變化,因爲它與當前值self相關。

有關更多討論和詳細信息,請參見Daniel Azuma's excellent article

相關問題