如何使用两个不同命名空间中的方法?
class Bar
def self.configure &block
new.instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure do
method1
method2
end
end
end
Foo.new.start
在上面的示例中,无法调用method1,因为它不是来自Bar范围。如何从两个范围同时调用方法?
答案 0 :(得分:3)
诀窍是将缺少的方法调用转发给Foo
的实例:
class Bar
def self.configure(&block)
o = new
context = eval('self', block.binding)
class << o; self; end.send(:define_method, :method_missing) do |meth, *args|
context.send(meth, *args)
end
o.instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure do
method1
method2
end
end
end
Foo.new.start #=> "from Foo"
#=> "from Bar"
答案 1 :(得分:1)
试试这个:
class Bar
def initialize(foo)
puts "init"
@f = foo
end
def self.configure(foo, &block)
new(foo).instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure(self) do
@f.method1
method2
end
end
end
这使@f成为Bar的类级实例变量,在Bar.configure中使用new(foo)初始化Bar的对象时设置。传递的块假定存在@f,它包含对类Foo的对象的引用。
这是一种令人费解的方式 - 尽管如此,我想不出更好的事情。了解用例会很有趣。
答案 2 :(得分:1)
也许,这是最简单的方法。它不需要修改Bar。
class Bar
def self.configure &block
new.instance_eval &block
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
foo = self # add
Bar.configure do
foo.method1 # modify
method2
end
end
end
Foo.new.start
答案 3 :(得分:1)
我会按如下方式简化您的代码:
class Bar
def self.configure &block
obj = new
block.call(obj)
obj
end
def method2
puts "from Bar"
end
end
class Foo
def method1
puts "from Foo"
end
def start
Bar.configure do |obj|
method1
obj.method2
end
end
end
Foo.new.start
块逻辑很干净,实现不需要上下文切换。您正在使用将参数传递给块的标准ruby功能。