Неожиданное значение __callee__ при включении модуля - это ошибка Ruby?
При вызове с помощью метода, созданного 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
По-видимому, я не единственный, чтобы удивиться этой проблеме. Интересно, был ли Revision 50728 (который должен был решить Ошибка 11046: __callee__
возвращает неправильное имя метода в orphan proc) может быть связано.
Ответы
Ответ 1
Вы можете увидеть разницу между __callee__
и __method__
в модуле ядра Ruby.
Разница заключается в вызовах prev_frame_callee()
и prev_frame_func()
, соответственно. Я нашел эти определения функций в http://rxr.whitequark.org/mri/source/eval.c
Короче говоря, Foo и Bar немедленно вызывают псевдонимы foo и bar (которые являются именами для xxx), а Baz должен найти Mod и вызывать xxx из Mod. __method__
ищет оригинал с именем method id, а __callee__
ищет ближайший вызываемый метод id к вызову __callee__
. Это лучше видно в eval.c
на строках 848 - 906: найдите разницу в двух методах при обратных вызовах, похожих на <something> -> called_id
vs <something> -> def->original_id
.
Кроме того, если вы посмотрите на Ядро из версии 1.9.3, вы увидите, что оба метода изначально были одинаковыми. Итак, в какой-то момент произошли целенаправленные изменения между ними.
Ответ 2
Это была ошибка, и она была закрыта 3 дня назад с этим примечанием:
Кажется, исправлено r56592.