2010-10-06 23 views
11

In einem Komponententest muss ich testen, ob Alias-Methoden, die durch alias_method definiert sind, richtig definiert wurden. Ich könnte einfach die gleichen Tests für die Aliase verwenden, die für ihre Originale verwendet werden, aber ich frage mich, ob es eine definitivere oder effizientere Lösung gibt. Gibt es zum Beispiel eine Möglichkeit, 1) den Alias ​​einer Methode zu dereferenzieren und den Namen des Originals zurückzugeben, 2) eine Art von zugrunde liegenden Methodenidentifikator oder -adresse abzurufen und zu vergleichen oder 3) Methodendefinitionen abzurufen und zu vergleichen? Zum Beispiel:Gibt es eine elegante Möglichkeit zu testen, ob eine Instanzmethode ein Alias ​​für eine andere ist?

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 

Vorschläge?

+0

möglich Duplikat [Ist es möglich, aliased Methoden in Ruby zu identifizieren?] (Http://stackoverflow.com/questions/3676834/is-it-possible-to -identify-aliased-methods-in-ruby) –

Antwort

18

Nach der Dokumentation für Method,

Zwei sind Verfahren Objekte gleich ob die auf dasselbe Objekt gebunden sind und den gleichen Körper enthalten.

Aufruf Object#method und den Vergleich der Method Objekte, die es überprüfen gibt, dass die Methoden gleichwertig sind:

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

Ich war sicher, dass ich mich daran erinnerte, dass das nicht funktionierte, aber ich versuchte es einfach zu bestätigen und es funktioniert konsistent in Ruby 1.8, 1.9 und MacRuby. Aber ich sehe es immer noch nicht in RubySpec, daher wird es sehr wahrscheinlich nicht bei einer nicht verwandten Implementierung funktionieren. – Chuck

+2

Auch Methoden, die nur identische Körper haben, aber nicht von einander kopiert werden, sind im Allgemeinen ausdrücklich * nicht * gleich. Beweis: 'Klasse.neues {def foo() Ende; Def bar() Ende; puts instance_method (: foo) == instance_method (: bar)} ' – Chuck

+0

@Chuck: Danke, dass du darauf hingewiesen hast. Ich hätte es versuchen sollen. – bk1e

3

bk1e Methode die meiste Zeit funktioniert, aber ich gerade passiert ist, den Fall zu treffen, wo es doesn ‚t Arbeit:

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 

der Ausgang in Ruby 1.9 erzeugt wird, nicht sicher, ob es ein Fehler oder nicht, da Ruby 1.8 produziert true für den letzt li ne. Also, wenn Sie 1.9 verwenden, seien Sie vorsichtig, wenn Sie eine geerbte Klassenmethode (wie Klasse # neu) Aliasing, Diese beiden Methoden sind an das gleiche Objekt gebunden (das Klassenobjekt Stream), aber sie gelten nicht als gleichwertig von Ruby 1.9 .

Meine Abhilfe ist einfach - alias der ursprünglichen Methode erneut und testen Sie die Gleichheit der beiden Aliase:

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 

Hoffnung, das hilft.

UPDATE:

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

So Method#== sollte in diesem Fall falsch zurückgeben, da eine super Aufruf verschiedene Methoden aufrufen würde; Es ist kein Fehler.

1

Aufruf MyClass.instance_method(:foo) wird Ergebnis UnboundMethod Instanz, die eql? Methode hat.

Die Antwort ist also:

describe MyClass do 
    subject { described_class } 

    specify do 
    expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar)) 
    end 
end 
Verwandte Themen