如何在当前上下文中评估另一个类的方法?

时间:2010-08-05 13:41:23

标签: ruby reflection delegates metaprogramming

我有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_siblingThing(这很好),但self是一个Tree::TreeNode

问题如何在另一个类(例如Tree::TreeNode)的上下文中评估类的实例方法(例如Thing)? (“覆盖自己”)

我尝试使用UnboundMethods,但您只能将原始接收类的实例绑定到未绑定的方法。

3 个答案:

答案 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}或其他东西?