2010-10-06 17 views
11

In un test di unità ho bisogno di verificare se i metodi alias definiti da alias_method sono stati definiti correttamente. Potrei semplicemente utilizzare gli stessi test sugli alias utilizzati per i loro originali, ma mi chiedo se esista una soluzione più definitiva o più efficiente. Ad esempio, esiste un modo per 1) dereferenziare un metodo alias e restituire il nome originale, 2) ottenere e confrontare qualche tipo di identificatore o indirizzo del metodo sottostante, oppure 3) ottenere e confrontare le definizioni dei metodi? Ad esempio:Esiste un modo elegante per verificare se un metodo di istanza è un alias per un altro?

class MyClass 
    def foo 
    # do something 
    end 

    alias_method :bar, :foo 
end 

describe MyClass do 
    it "method bar should be an alias for method foo" do 
    m = MyClass.new 
    # ??? identity(m.bar).should == identity(m.foo) ??? 
    end 
end 

Suggerimenti?

+0

possibile duplicato [E 'possibile identificare i metodi alias in Ruby?] (Http://stackoverflow.com/questions/3676834/is-it-possible-to -identify-aliased-methods-in-ruby) –

risposta

18

Secondo la documentazione per Method,

due oggetti metodi sono uguali se sono legati allo stesso oggetto e contengono lo stesso corpo.

Calling Object#method e confrontando i Method oggetti che restituisca verificherà che i metodi sono equivalenti: metodo

m.method(:bar) == m.method(:foo) 
+0

Ero sicuro di aver ricordato che non funzionava, ma l'ho appena provato per confermare e funziona costantemente in Ruby 1.8, 1.9 e MacRuby. Ma continuo a non vederlo in RubySpec, quindi molto probabilmente non funzionerà su un'implementazione non correlata. – Chuck

+2

Inoltre, in generale, i metodi che hanno solo corpi identici ma non sono copiati l'uno dall'altro sono enfaticamente * non * uguali. Prova: 'Classe.nuova {def foo() end; barra def() fine; puts instance_method (: foo) == instance_method (: bar)} ' – Chuck

+0

@Chuck: Grazie per averlo indicato. Avrei dovuto provarlo – bk1e

3

di bk1e funziona la maggior parte del tempo, ma mi è capitato di colpire il caso in cui esso doesn 't lavoro:

class Stream 
    class << self 
    alias_method :open, :new 
    end 
end 

open = Stream.method(:open) 
new = Stream.method(:new) 
p open, new     # => #<Method: Stream.new>, #<Method: Class#new> 
p open.receiver, new.receiver # => Stream, Stream 
p open == new     # => false 

l'uscita è prodotta in Ruby 1.9, non so se si tratta di un bug o no dal momento che Ruby 1.8 produce true per l'ultima Li ne. Quindi, se stai usando 1.9, fai attenzione se stai facendo l'aliasing di un metodo di classe ereditato (come Class # nuovo), Questi due metodi sono legati allo stesso oggetto (l'oggetto classe Stream), ma sono considerati non equivalenti da Ruby 1.9 .

mia soluzione è semplice - alias il metodo originale di nuovo e verificare l'uguaglianza delle due alias:

class << Stream; alias_method :alias_test_open, :new; end 
open = Stream.method(:open) 
alias_test_open = Stream.method(:alias_test_open) 
p open, alias_test_open     # => #<Method: Stream.new>, #<Method: Stream.new> 
p open.receiver, alias_test_open.receiver # => Stream, Stream 
p open == alias_test_open     # => true 

Spero che questo aiuti.

UPDATE:

Vedi http://bugs.ruby-lang.org/issues/7613

Così Method#== dovrebbe restituire false in questo caso, poiché una chiamata super sarebbe invocare metodi diversi; Non è un errore.

1

Chiamando MyClass.instance_method(:foo) risultante l'istanza UnboundMethod, che ha il metodo eql?.

Quindi la risposta è:

describe MyClass do 
    subject { described_class } 

    specify do 
    expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar)) 
    end 
end 
Problemi correlati