想象一下,我们有三个班级:
class SomeClass
def container_class
# ...
end
end
class Container
attr_accessor :property
end
class Container2
attr_accessor :lalala
end
# now I create instances
p = SomeClass.new
c = Container.new
c.property = p
c.property.container_class # => should return Container
c2 = Container2.new
c2.lalala = p
c2.lalala.container_class # => should return Container2
问题: 如何使用ruby元编程来编写方法container_class,以便返回调用此方法的实例的容器(组合)类?
您只能使用元编程。不应手动更改容器类。
答案 0 :(得分:1)
我从here那里得到了这个答案。以下是获取调用者绑定的方法:
require 'continuation'
def caller_binding
cc = nil # must be present to work within lambda
count = 0 # counter of returns
set_trace_func lambda { |event, file, lineno, id, binding, klass|
# First return gets to the caller of this method
# (which already know its own binding).
# Second return gets to the caller of the caller.
# That's we want!
if count == 2
set_trace_func nil
# Will return the binding to the callcc below.
cc.call binding
elsif event == "return"
count += 1
end
}
# First time it'll set the cc and return nil to the caller.
# So it's important to the caller to return again
# if it gets nil, then we get the second return.
# Second time it'll return the binding.
return callcc { |cont| cc = cont }
end
现在,您可以按如下方式定义班级SomeClass
:
class SomeClass
def container_class
return unless bnd = caller_binding
bnd.eval "self.class"
end
end
答案 1 :(得分:0)
您可以使用它,我不是使用最漂亮的方式,但您可以编写一个注入该方法的新访问器。
类:
class Container
def property=(arg)
arg.called_from = self.class
@arg = arg
end
def property
@arg
end
end
class SomeClass
def container_class
@klass
end
def called_from=(klass)
@klass = klass
end
end
规格:
require_relative 'container'
describe Container do
let(:container) { Container.new }
it 'passes message' do
container.property = SomeClass.new
expect(container.property.container_class).to eq Container
end
end