2016-02-09 10 views
14

Wenn über eine Methode von alias_method erstellt aufgerufen, ignoriert __callee__ den Namen der alten Methode (hier xxx) und gibt den Namen des neuen Verfahrens, wie unten:Unerwarteter Wert von __callee__ beim Einbinden eines Moduls - ist das ein Ruby-Bug?

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

Foo.new.foo # => :foo 

Dieses Verhalten auch hält, wenn xxx vererbt wird von einer übergeordneten Klasse:

class Sup 
    def xxx() __callee__ end 
end 

class Bar < Sup 
    alias_method :bar, :xxx 
end 

Bar.new.bar # => :bar 

beide oben gegeben, würde ich erwarten, dass das gleiche Verhalten halten würde, wenn xxx über ein Modul enthalten ist. Das ist jedoch nicht der Fall:

module Mod 
    def xxx() __callee__ end 
end 

class Baz 
    include Mod 
    alias_method :baz, :xxx 
end 

Baz.new.baz # => :xxx 

I der Rückgabewert erwarten :baz zu sein, nicht :xxx.


Der obige Code wurde mit Ruby 2.3.1p112 ausgeführt. Ist das ein Fehler in der Implementierung von __callee__? Oder vielleicht von alias_method? Und wenn nicht, kann jemand erklären, warum sich Moduleinschlüsse anders verhalten?


UPDATE 1

Ich habe posted this to the Ruby bug tracker eine Antwort zu schüren zu versuchen.


UPDATE 2

Offenbar bin ich not the only one auf dieses Problem überrascht zu sein. Ich frage mich, ob Revision 50728 (die Bug 11046: __callee__ returns incorrect method name in orphan proc lösen sollte) verwandt sein könnte.

+2

Sehr interessant, definitiv zwischen 2,2 und 2,3 geändert. Gleiches gilt für "__method__". –

+0

@NilsLandt Kannst du ein Beispiel für das Verhalten von "__method__" geben? Ich habe "__callee__" durch "__method__" ersetzt und habe "xxx" für alle 3 Fälle zurückgegeben. Ist es in Ruby 2.2 anders? –

Antwort

1

Sie können den Unterschied zwischen __callee__ und __method__ in Rubys Kernel-Modul sehen. Der Unterschied besteht in den Aufrufen prev_frame_callee() bzw. prev_frame_func(). Ich find diese Funktionsdefinitionen bei http://rxr.whitequark.org/mri/source/eval.c

Kurz gesagt, rufen Foo und Bar sofort die Alias-Methoden foo und bar (die Namen für xxx sind), während Baz Mod finden und xxx von Mod aufrufen muss. __method__ sucht nach der ID der ursprünglichen aufgerufenen Methode, während __callee__ nach der ID der nächsten aufgerufenen Methode zum Aufruf __callee__ sucht. Dies ist besser in eval.c in den Zeilen 848 bis 906 zu sehen: Suchen Sie nach dem Unterschied in den beiden Methoden auf die Rückrufe ähnlich wie <something> -> called_id vs <something> -> def->original_id.

Wenn Sie den Kernel von Version 1.9.3 betrachten, sehen Sie, dass die beiden Methoden ursprünglich identisch waren. Irgendwann gab es einen gewollten Wechsel zwischen den beiden.

1

Das war ein Fehler, und es wurde vor 3 Tagen geschlossen with this note:

von r56592 fixiert zu sein scheint.