14

通过创建的方法调用时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

我已将此发布到 Ruby 错误跟踪器,以试图激起答案。


更新 2

显然,我不是唯一一个对这个问题感到惊讶的人。我想知道修订版 50728(旨在解决错误 11046:__callee__在 orphan proc 中返回不正确的方法名称)是否相关。

4

2 回答 2

2

您可以看到Ruby 的 Kernel 模块__callee__之间的区别。__method__

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

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

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

于 2016-05-19T12:57:04.090 回答
1

这是一个错误,并在 3 天前关闭,并附有以下说明

似乎由r56592 修复

于 2017-01-20T20:45:28.573 回答