2016-02-09 16 views
14

Quando viene richiamato tramite un metodo creato da alias_method, __callee__ ignora il nome del vecchio metodo (qui xxx) e restituisce il nome del nuovo metodo, come di seguito:Valore inatteso di __callee__ quando si include un modulo - si tratta di un bug di Ruby?

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

Foo.new.foo # => :foo 

Questo comportamento vale anche quando xxx viene ereditato da una superclasse:

class Sup 
    def xxx() __callee__ end 
end 

class Bar < Sup 
    alias_method :bar, :xxx 
end 

Bar.new.bar # => :bar 

Dato sia di quanto sopra, mi sarei aspettato che lo stesso comportamento sarebbe tenere quando xxx è incluso tramite un modulo. Tuttavia, questo non è il caso:

module Mod 
    def xxx() __callee__ end 
end 

class Baz 
    include Mod 
    alias_method :baz, :xxx 
end 

Baz.new.baz # => :xxx 

mi aspetto che il valore di ritorno per essere :baz, non :xxx.


Il codice precedente è stato eseguito utilizzando Ruby 2.3.1p112. Si tratta di un bug nell'implementazione di __callee__? O forse di alias_method? E se no, qualcuno può spiegare perché l'inclusione del modulo si comporta diversamente?


UPDATE 1

ho posted this to the Ruby bug tracker per cercare di suscitare una risposta.


UPDATE 2

A quanto pare, io sono not the only one di essere sorpresi da questo problema. Mi chiedo se Revision 50728 (che doveva risolvere Bug 11046: __callee__ returns incorrect method name in orphan proc) possa essere correlato.

+2

Molto interessante, decisamente cambiato tra 2.2 e 2.3. Lo stesso per '__method__'. –

+0

@NilsLandt Puoi dare un esempio del comportamento di '__method__'? Ho sostituito '__callee__' con' __method__' e ho ottenuto 'xxx' restituito per tutti e 3 i casi. È diverso in Ruby 2.2? –

risposta

1

È possibile visualizzare la differenza tra __callee__ e __method__ nel modulo Kernel di Ruby.

La differenza sono le chiamate prev_frame_callee() e prev_frame_func(), rispettivamente. Ho trovato queste definizioni di funzioni su http://rxr.whitequark.org/mri/source/eval.c

In breve, Foo e Bar chiamano immediatamente i metodi con alias foo e bar (che sono nomi per xxx), mentre Baz deve trovare Mod e chiamare xxx da Mod. __method__ cerca l'id del metodo chiamato originale, mentre __callee__ cerca l'id del metodo chiamato più vicino alla chiamata __callee__. Ciò è meglio visibile in eval.c alle righe da 848 a 906: cercare la differenza nei due metodi sulle chiamate di ritorno simili a <something> -> called_id rispetto a <something> -> def->original_id.

Inoltre, se si guarda il kernel dalla versione 1.9.3, si vedrà che i due metodi originariamente erano gli stessi. Quindi, ad un certo punto, c'è stato un cambiamento significativo tra i due.

1

Questo è stato un errore, ed era chiuso 3 giorni fa with this note:

sembra fissata dal r56592.

Problemi correlati