Есть ли элегантный способ проверить, если один метод экземпляра является псевдоним для другого?
-
28-09-2019 - |
Вопрос
В модульном тесте мне нужно проверить, были ли правильно определены методы псевдонима с помощью 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
Предложения?
Решение
Согласно документации для Метод,
Два объекта метода равны, если они связаны с тем же объектом и содержат одно и то же тело.
Призыв 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, будьте осторожны, если вы псевдоним методом унаследованного класса (например, класс # новый), эти два метода связаны с тем же объектом (объект класса 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#==
должен вернуть ложь в этом случае с super
вызов будет вызывать разные методы; Это не ошибка.
Призыв MyClass.instance_method(:foo)
приведет к Несообщение экземпляр, который имеет eql?
метод.
Так что ответ:
describe MyClass do
subject { described_class }
specify do
expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
end
end