我想定义一组可以使用Mixin添加到类(示例中为C)的方法。这些方法可以由从另一个类继承的任何类(示例中的A)定义,并且应该能够调用接收器实例(C实例)中的方法。
我有这段代码:
M = Module.new
class A
class << self
def init(method)
if block_given?
M.send(:define_method, method) do
instance_exec &Proc.new
end
else
block = self.method(method).to_proc
M.send(:define_method, method) do
yield block.call
end
end
end
end
end
class B < A
init(:foo) do
"foo+".concat(c_method)
end
def self.bar
"bar+".concat(c_method)
end
init(:bar)
end
C = Class.new do
def c_method
"c_method"
end
end
c = C.new
c.extend(M)
puts c.foo
puts c.bar
使用块添加方法有效,但最后一行失败:(
foo+c_method
test.rb:28:in `bar': undefined local variable or method `c_method' for B:Class (NameError)
from test.rb:15:in `call'
from test.rb:15:in `block in init'
from test.rb:46:in `<main>'
我做错了什么?或者这没有意义?
由于
涓
答案 0 :(得分:1)
在instance_exec &Proc.new
语句中准备if
时,此语句在C
类的实例中作为上下文执行。您可以通过在puts self
的块内添加init(:foo)
来验证这一点。
另一方面,当你调用yield block.call
时,你将线程执行产生到B类对象的上下文中(当然不是这个类的实例:))。你的代码的这个地方对C :: c_method一无所知,这是错误原因。
答案 1 :(得分:0)
似乎我要做的就是取消绑定方法:从B栏中绑定并绑定到C,这是不允许的。您可以在this great post
中找到更多信息M = Module.new
class A
class << self
def init(method)
if block_given?
M.send(:define_method, method) do
instance_exec &Proc.new
end
else
block = self.method(method).unbind
M.send(:define_method, method) do
m = block.bind(self)
puts m
end
end
end
end
end
class B < A
init(:foo) do
"foo+".concat(c_method)
end
def self.bar
"bar+".concat(c_method)
end
init(:bar)
end
C = Class.new do
def c_method
"c_method"
end
end
c = C.new
c.extend(M)
puts c.foo
puts c.bar
foo+c_method
test.rb:16:in `bind': singleton method called for a different object (TypeError)
from test.rb:16:in `block in init'
from test.rb:48:in `<main>'