Question

In a unit test I need to test whether alias methods defined by alias_method have been properly defined. I could simply use the same tests on the aliases used for their originals, but I'm wondering whether there's a more definitive or efficient solution. For instance, is there a way to 1) dereference a method alias and return its original's name, 2) get and compare some kind of underlying method identifier or address, or 3) get and compare method definitions? For example:

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

Suggestions?

Was it helpful?

Solution

According to the documentation for Method,

Two method objects are equal if that are bound to the same object and contain the same body.

Calling Object#method and comparing the Method objects that it returns will verify that the methods are equivalent:

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

OTHER TIPS

bk1e's method works most of the time, but I just happened to hit the case where it doesn't work:

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

The output is produced in Ruby 1.9, not sure if it's a bug or not since Ruby 1.8 produces true for the last line. So, if you are using 1.9, be careful if you are aliasing an inherited class method (like Class#new), These two methods are bound to the same object (the class object Stream), but they are considered not equivalent by Ruby 1.9.

My workaround is simple - alias the original method again and test the equality of the two aliases:

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

Hope this helps.

UPDATE:

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

So Method#== should return false in this case since a super call would invoke different methods; it is not a bug.

Calling MyClass.instance_method(:foo) will result UnboundMethod instance, which has eql? method.

So the answer is:

describe MyClass do
  subject { described_class }

  specify do
    expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top