【问题标题】:How to evaluate methods of another class in current context?如何在当前上下文中评估另一个类的方法?
【发布时间】:2010-08-05 13:41:22
【问题描述】:

我有 2 个类,它们的对象应该充当“合作伙伴”。第一个是我的Thing 类,它的实例应该充当宝石RubyTree 的Tree::TreeNodes。

基本上,这个委托可以使用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,即属于my_thingTree::TreeNode 对象,但不属于Thing 对象本身。

另一个例子:

siblings = []
parent.children {|my_sibling| siblings << my_sibling if my_sibling != self}
siblings

parent.children 返回一个 Things 数组,因此条件永远不会评估为 false,因为 my_siblingThing(这很好)但 selfTree::TreeNode

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

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

【问题讨论】:

  • 你确定没有别的办法吗?你的方法似乎……有缺陷。
  • 好吧,除了复制和粘贴或不使用这些方法之外别无他法。我想我有一天会分叉 RubyTree 以使其可委托。

标签: ruby reflection delegates metaprogramming


【解决方案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

【讨论】:

  • 谢谢!所以我知道我的选择。多么邪恶的图书馆! xD Even 允许多重继承。我想我有一天会分叉 RubyTree 以使其可委托。可能是不那么邪恶的解决方案。
【解决方案2】:

您可能想使用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

【讨论】:

    【解决方案3】:

    我不确定你是否可以。也许用 instance_eval {unboundmethod.to_proc} 之类的?

    【讨论】:

    • 显然,您不能将 UnboundMethod 强制为 Proc。 NoMethodError: undefined method to_proc' for #`
    猜你喜欢
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2012-07-05
    • 2020-11-21
    • 2023-03-18
    相关资源
    最近更新 更多