Подтвердить что ты не робот

Есть ли элегантный способ проверить, является ли один метод экземпляра псевдонимом для другого?

В 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

Предложения?

4b9b3361

Ответ 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