Есть ли элегантный способ проверить, является ли один метод экземпляра псевдонимом для другого?
В модульном тесте мне нужно проверить, правильно ли определены методы псевдонимов, определенные 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
Предложения?
3 ответа
Согласно документации для метода,
Два объекта метода равны, если они связаны с одним и тем же объектом и содержат одно и то же тело.
призвание Object#method
и сравнивая Method
объекты, которые он возвращает, проверят, что методы эквивалентны:
m.method(:bar) == m.method(:foo)
Метод 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
Надеюсь это поможет.
ОБНОВИТЬ:
Смотрите http://bugs.ruby-lang.org/issues/7613
Так Method#==
должен вернуть false в этом случае, так как super
вызов будет вызывать разные методы; это не ошибка.
Призвание 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