Есть ли элегантный способ проверить, является ли один метод экземпляра псевдонимом для другого?
В unit test мне нужно проверить, правильно ли определены методы псевдонимов, определенные alias_method. Я мог бы просто использовать те же тесты для псевдонимов, которые использовались для их оригиналов, но мне интересно, существует ли более решительное или эффективное решение. Например, существует ли способ 1) разыменовать псевдоним метода и вернуть его исходное имя, 2) получить и сравнить какой-то базовый идентификатор или адрес метода, или 3) получить и сравнить определения методов? Например:
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
Предложения?
Ответы
Ответ 1
В соответствии с документацией для Method,
Два объекта метода равны, если связаны с одним и тем же объектом и содержат одно и то же тело.
Вызов Object#method
и сравнение возвращаемых объектов Method
подтвердят, что методы эквивалентны:
m.method(:bar) == m.method(:foo)
Ответ 2
Метод bk1e работает большую часть времени, но я просто попал в случай, когда он не работает:
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
Вывод производится в Ruby 1.9, не уверен, что это ошибка или нет, поскольку Ruby 1.8 производит true
для последней строки. Итак, если вы используете 1.9, будьте осторожны, если вы наследуете метод унаследованного класса (например, Class # new). Эти два метода привязаны к одному и тому же объекту (объект класса Stream
), но они считаются не эквивалентными по Ruby 1.9.
Мое обходное решение прост - повторите первоначальный метод и проверьте равенство двух псевдонимов:
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
Надеюсь, что это поможет.
UPDATE:
См. http://bugs.ruby-lang.org/issues/7613
Итак, Method#==
должен возвращать false в этом случае, так как вызов super
вызывал разные методы; это не ошибка.
Ответ 3
Вызов MyClass.instance_method(:foo)
приведет к UnboundMethod экземпляру, который имеет метод eql?
.
Итак, ответ:
describe MyClass do
subject { described_class }
specify do
expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
end
end