有时你可以看到:如何在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