有時你可以看到:如何在Ruby中的塊中提供類/對象方法?
do_this do
available_method1 "arg1"
available_method2 "arg1"
end
當我使用塊從do_this方法然後我得到了一些方法,我可以說塊內使用。
我想知道這是如何完成的?代碼如何看起來像在幕後?
我希望能夠通過塊提供一些方法。
有時你可以看到:如何在Ruby中的塊中提供類/對象方法?
do_this do
available_method1 "arg1"
available_method2 "arg1"
end
當我使用塊從do_this方法然後我得到了一些方法,我可以說塊內使用。
我想知道這是如何完成的?代碼如何看起來像在幕後?
我希望能夠通過塊提供一些方法。
它被稱爲域特定語言(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
這通常通過使用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。
這種例子有什麼資源嗎?用這樣的ruby代碼來描述各種設計模式是很好的。 – 2010-08-29 03:56:50