Existe uma maneira elegante de testar se um método de instância é um alias para outro?

StackOverflow https://stackoverflow.com/questions/3869668

  •  28-09-2019
  •  | 
  •  

Pergunta

Em um teste de unidade, preciso testar se os métodos de alias definidos por alias_method foram definidos corretamente.Eu poderia simplesmente usar os mesmos testes nos aliases usados ​​nos originais, mas estou me perguntando se existe uma solução mais definitiva ou eficiente.Por exemplo, existe uma maneira de 1) desreferenciar um alias de método e retornar o nome original, 2) obter e comparar algum tipo de identificador ou endereço de método subjacente ou 3) obter e comparar definições de método?Por exemplo:

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

Sugestões?

Foi útil?

Solução

De acordo com a documentação de Método,

Dois objetos do método são iguais se estão ligados ao mesmo objeto e contêm o mesmo corpo.

Chamando Object#method e comparando o Method objetos que ele retorna verificarão se os métodos são equivalentes:

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

Outras dicas

O método do bk1e funciona na maioria das vezes, mas aconteceu de eu encontrar um caso em que ele não funciona:

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

A saída é produzida em Ruby 1.9, não tenho certeza se é um bug ou não, já que Ruby 1.8 produz true para a última linha.Portanto, se você estiver usando 1.9, tome cuidado se estiver criando um alias para um método de classe herdado (como Class#new). Esses dois métodos estão vinculados ao mesmo objeto (o objeto de classe Stream), mas eles não são considerados equivalentes pelo Ruby 1.9.

Minha solução alternativa é simples - alias ao método original novamente e teste a igualdade dos dois alias:

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

Espero que isto ajude.

ATUALIZAR:

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

Então Method#== deve retornar falso neste caso, pois um super call invocaria métodos diferentes;Não é um inseto.

Chamando MyClass.instance_method(:foo) resultará Método não consolidado exemplo, que tem eql? método.

Então a resposta é:

describe MyClass do
  subject { described_class }

  specify do
    expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
  end
end
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top