Existe uma maneira elegante de testar se um método de instância é um alias para outro?
-
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?
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