我有2个类,其对象应该充当“伙伴”。第一个是我的Thing
类,其实例应该充当宝石RubyTree的Tree::TreeNode
。
基本上,可以使用Forwardable
:
class Thing < NoClassInheritancePlease
extend Forwardable
def initialize(title = "node")
@node = Tree::TreeNode.new title
# Collect node methods that should be delegated
node_methods = @node.public_methods(false)
node_methods += @node.protected_methods
node_methods -= (public_methods(false) + protected_methods(false) + private_methods) # own methods should not been delegated
# Set up delegation of specified node methods as singleton methods
for method in node_methods
Base.def_delegator :@node, method
end
end
end
问题:
许多TreeNode
方法都引用self
。例如:
def each(&block) # :yields: node
yield self
children { |child| child.each(&block) }
end
因此,my_thing.each {...}
会产生self
,即Tree::TreeNode
对象属于my_thing
但不属于Thing
对象本身。
另一个例子:
siblings = []
parent.children {|my_sibling| siblings << my_sibling if my_sibling != self}
siblings
parent.children返回一个Thing
的数组,因此条件永远不会计算为假,因为my_sibling
是Thing
(这很好),但self
是一个Tree::TreeNode
问题:如何在另一个类(例如Tree::TreeNode
)的上下文中评估类的实例方法(例如Thing
)? (“覆盖自己”)
我尝试使用UnboundMethods,但您只能将原始接收类的实例绑定到未绑定的方法。
答案 0 :(得分:1)
如果你真的想要,you could use evil-ruby来解决这个问题。
require 'evil'
class A; def m; self; end; end
class B; end
A.instance_method(:m).force_bind(B.new).call
答案 1 :(得分:1)
您可能想要使用instance_exec
。
来自文档:
在接收器(obj)的上下文中执行给定的块。为了设置上下文,在代码执行时将变量self设置为obj,使代码可以访问obj的实例变量。参数作为块参数传递。
class KlassWithSecret
def initialize
@secret = 99
end
end
k = KlassWithSecret.new
k.instance_exec(5) {|x| @secret+x } #=> 104
http://ruby-doc.org/core-1.8.7/Object.html#method-i-instance_exec
在您的情况下,您可以使用instance_exec来产生自我。
def each(&block)
instance_exec{ yield self }
children { |child| child.each(&block) }
end
答案 2 :(得分:0)
我不确定你是否可以。也许使用instance_eval {unboundmethod.to_proc}或其他东西?