【问题标题】:Unexpected value of __callee__ when including a module – is this a Ruby bug?包含模块时 __callee__ 的意外值 - 这是 Ruby 错误吗?
【发布时间】:2016-05-18 19:44:45
【问题描述】:

当通过alias_method创建的方法调用时,__callee__会忽略旧方法的名称(此处为xxx)并返回新方法的名称,如下所示:

class Foo
  def xxx() __callee__ end
  alias_method :foo, :xxx
end

Foo.new.foo # => :foo

即使xxx 是从超类继承的,这种行为仍然存在:

class Sup
  def xxx() __callee__ end
end

class Bar < Sup
  alias_method :bar, :xxx
end

Bar.new.bar # => :bar

鉴于上述两种情况,我希望通过模块包含 xxx 时会保持相同的行为。然而,事实并非如此:

module Mod
  def xxx() __callee__ end
end

class Baz
  include Mod
  alias_method :baz, :xxx
end

Baz.new.baz # => :xxx

我希望返回值是:baz,而不是:xxx


以上代码是使用 Ruby 2.3.1p112 执行的。这是__callee__ 实现中的错误吗?或者可能是alias_method?如果不是,谁能解释为什么模块包含的行为不同?


更新 1

我已经posted this to the Ruby bug tracker 试图激起答案。


更新 2

显然,我 not the only one 对这个问题感到惊讶。我想知道Revision 50728(这是为了解决Bug 11046: __callee__ returns incorrect method name in orphan proc)是否可能相关。

【问题讨论】:

  • 非常有趣,肯定在 2.2 和 2.3 之间发生了变化。 __method__ 也一样。
  • @NilsLandt 你能举一个__method__ 行为的例子吗?我用__method__ 替换了__callee__ 并为所有3 个案例返回了xxx。 Ruby 2.2 有什么不同吗?

标签: ruby inheritance metaprogramming alias-method


【解决方案1】:

您可以在 Ruby 的内核模块中看到 __callee____method__ 之间的区别。

区别在于分别调用prev_frame_callee()prev_frame_func()。我在http://rxr.whitequark.org/mri/source/eval.c 找到了这些函数定义

简而言之,Foo 和 Bar 会立即调用别名方法 foo 和 bar(它们是 xxx 的名称),而 Baz 必须找到 Mod 并从 Mod 调用 xxx。 __method__ 查找原始被调用方法的 id,而__callee__ 查找最接近 __callee__ 调用的被调用方法的 id。这在第 848 到 906 行的 eval.c 中更好地看到:在类似于 &lt;something&gt; -&gt; called_id&lt;something&gt; -&gt; def-&gt;original_id 的返回调用中寻找两种方法的区别。

此外,如果您查看 1.9.3 版本的内核,您会发现这两种方法最初是相同的。因此,在某些时候,两者之间发生了有目的的变化。

【讨论】:

    【解决方案2】:

    这是一个错误,3天前已关闭with this note

    似乎已被r56592 修复。

    【讨论】:

      猜你喜欢
      • 2021-05-17
      • 2017-06-10
      • 1970-01-01
      • 2016-02-24
      • 2011-04-27
      • 1970-01-01
      • 2017-01-08
      • 2018-10-10
      相关资源
      最近更新 更多