Existe um alias_method para um método de classe?

10

Considere a seguinte classe:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
end

Isso não é problema e você pode ligar Foo.new.a_new_inst_methodsem problemas.

Eu gostaria da capacidade de ter um método de classe Foo.add_widget(*items)e o apelido para que eu possa fazer algo como:

Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'

Então, basicamente, ele tem um estilo "ruby" 1.minutee, 2.minutespor isso, quero Foo.add_widgetchamar um apelido de chamado Foo.add_widgetsexatamente o mesmo método. Eu sei que poderia envolvê-lo, mas sinto que deveria ser capaz de fazer isso de uma maneira mais limpa.

Considere minha tentativa de tentar algo como isto:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
  alias_method :a_new_class_method, :a_class_method
end

No entanto, eu recebo o seguinte erro:

NameError (undefined method `a_class_method' for class `Foo')

E assim parece que isso não funciona para métodos de classe. Como faço para fazer isso?

aarona
fonte

Respostas:

9

alias_methodalias um método de instâncias do receptor. Métodos de classe são, na verdade, métodos de instância definidos na classe singleton de uma classe.

class MyClass
  def self.a
    "Hello World!"
  end
end

method_1 = MyClass.method(:a).unbind
method_2 = MyClass.singleton_class.instance_method(:a)

method_1 == method_2
#=> true

Para alternar um método de instância definido na classe singleton, você pode abri-lo usando a class << objectsintaxe.

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Ou você pode consultá-lo diretamente usando o singleton_classmétodo

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Se você ainda estiver dentro do contexto da classe self, consultará a classe. Portanto, o acima também poderia ser escrito como:

class MyClass
  class << self
    def a
      "Hello World!"
    end
    alias_method :b, :a
  end
end

Ou

class MyClass
  def self.a
    "Hello World!"
  end
  singleton_class.alias_method :c, :a
end

Ou uma combinação de ambos.

3limin4t0r
fonte
5

Você pode agrupar métodos de classe e suas alias_methodchamadas em um módulo separado e incorporar esse módulo à sua classe via extend:

class Foo
  def an_inst_method
    'instance method'
  end
  alias_method :a_new_inst_method, :an_inst_method

  module ClassMethods
    def a_class_method
      'class method'
    end
    alias_method :a_new_class_method, :a_class_method
  end

  extend ClassMethods
end
Stefan
fonte
Ei! Eu esqueci a extend ClassMethodssolução. +1
aarona em 21/04
4

O importante é entender que não existe um método de classe no Ruby.

Um método de classe é realmente apenas um método singleton. Não há nada de especial nos métodos de classe. Todo objeto pode ter métodos singleton. Apenas os chamamos de "métodos de classe" quando o objeto é um Class"método singleton de uma instância de Class" é muito longo e pesado.

Esperar! Eu disse "método singleton"?

Outra coisa importante a entender é que não existe um método singleton no Ruby.

Um método singleton é realmente apenas um método de instância antigo e chato da classe singleton. Não há nada de especial nos métodos singleton. Eles são apenas métodos de instância como qualquer outro método de instância.

De fato, Ruby possui apenas métodos de instância. Sem funções, sem construtores, sem métodos estáticos, sem métodos de classe, sem funções de módulo, sem métodos singleton.

A questão não é "este é um método de classe, é um método singleton", mas "em que módulo esse método está definido?"

"Métodos Singleton" são realmente métodos de instância definidos na classe singleton. A sintaxe para acessar a classe singleton de fooé

class << foo
end

Há também um método Object#singleton_classque retorna a classe singleton de um objeto.

Por que estou tão agressivamente insistindo no fato de que todo método é um método de instância e que métodos de classe não existem? Porque isso significa que o modelo de objetos de Ruby é muito mais simples do que as pessoas pensam! Afinal, na sua pergunta, você já mostra que sabe alias métodos de instância, mas diz que não sabe alias métodos de classe. Mas isso está errado! Você fazer saber como métodos de classe apelido, porque eles são apenas métodos de instância . Se você tivesse aprendido esse fato adequadamente, nunca precisaria fazer essa pergunta!

Depois que você entende que todo método é um método de instância e que chamamos de "métodos singleton" são apenas métodos de instância da classe singleton, a solução fica clara:

singleton_class.alias_method :a_new_class_method, :a_class_method

Nota: quando escrevi acima que "não existe X", o que eu quis dizer foi "não existe X na linguagem Ruby ". Isso não significa que esses conceitos não existam na comunidade Ruby .

Falamos regularmente sobre "métodos singleton" e "métodos de classe", simplesmente porque é mais fácil do que falar sobre "métodos de instância da classe singleton" ou "métodos de instância da classe singleton de um objeto que por acaso é uma instância da Classclasse " Há até mesmo métodos, como Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, e Module#module_functionna biblioteca núcleo Ruby. Mas é sempre importante lembrar que esses não são conceitos de linguagem. Esses são conceitos de comunidade que existem apenas em nossas cabeças e nos nomes de alguns métodos de biblioteca.

Jörg W Mittag
fonte
2

OK, parece que posso fazer algo assim e funcionará:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    alias_method :a_new_class_method, :a_class_method
  end
end

Foo.a_class_method # => "class method" 
Foo.a_new_class_method # => "class method"

Se alguém tiver alguma informação útil sobre o idioma Ruby aqui e quiser enviar uma resposta abrangente, darei um +1.

aarona
fonte
11
Quando você o class << selfsegue, alias_method :a_new_class_method, :a_class_methodvocê realmente chama alias_methoda classe singleton de Foo. Outra maneira de escrever isso é: singleton_class.alias_method :a_new_class_method, :a_class_methodno contexto da classe.
3limin4t0r 20/04
O que mais você quer de uma resposta? Quero dizer, esta é provavelmente a solução mais limpa.
Dave Newton
@ 3limin4t0r, se você der uma resposta, eu vou marcar com +1. Obrigado por esta informação extra.
aarona 20/04
@DaveNewton, você está certo, mas porque eu também tenho uma filosofia de que se alguém puder fornecer informações mais significativas a um problema, mesmo que indiretamente resolva o problema, acho que isso também deve ser recompensado.
aarona 20/04
2

alias_methodopera na instância, então você precisa ir um nível mais fundo e operar na Classinstância ou na metaclasse da classe . Ruby tem um modelo de objeto selvagem que pode ser uma espécie de quebra de cérebro, mas também oferece uma tonelada de poder:

class Foo
  def an_inst_method
    'instance method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    def a_class_method
      'class method'
    end

    alias_method :a_new_class_method, :a_class_method
  end
end
lobati
fonte
Trabalho com ruby ​​em um contexto de trilhos há cerca de uma década, mas apenas recentemente comecei a mergulhar profundamente no modelo de objetos. Há tantas coisas legais disponíveis!
aarona 20/04