包含模块时__callee__的意外值 - 这是一个Ruby错误吗?

时间:2016-02-09 00:00:15

标签: ruby inheritance metaprogramming alias-method

当通过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

apache commons beanutils试图挑起答案。

更新2

显然,我posted this to the Ruby bug tracker对这个问题感到惊讶。我想知道not the only one(意图解决Revision 50728)是否可能是相关的。

2 个答案:

答案 0 :(得分:2)

您可以在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__查找最近调用方法的id __callee__调用。在eval.c第848行到第906行中可以更好地看到这一点:在<something> -> called_id<something> -> def->original_id类似的返回调用中查找两种方法的区别。

另外,如果从版本1.9.3查看内核,您将看到两个方法最初是相同的。所以,在某些时候,两者之间有了一个有目的的变化。

答案 1 :(得分:1)

这是一个错误,它在3天前被关闭with this note

  

似乎由r56592确定。