¿Hay un método alias_ para un método de clase?

10

Considere la siguiente clase:

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

Esto no es un problema y puede llamar Foo.new.a_new_inst_methodsin problemas.

Me gustaría tener un método de clase como Foo.add_widget(*items)y alias para poder hacer algo como:

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

Así que, esencialmente, tiene un "estilo rubí" similar 1.minutey, 2.minutespor lo tanto, quiero usar un alias Foo.add_widgetpara llamar a las Foo.add_widgetsllamadas exactamente el mismo método. Sé que podría envolverlo, pero siento que debería poder hacerlo de una manera más limpia.

Considere mi intento de intentar algo como esto:

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

Sin embargo, me sale el siguiente error:

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

Y parece que esto no funciona para los métodos de clase. ¿Cómo voy a hacer esto?

aarona
fuente

Respuestas:

9

alias_methodalias un método de instancias del receptor. Los métodos de clase son en realidad métodos de instancia definidos en la clase singleton de una clase.

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 crear un alias de un método de instancia definido en la clase singleton, puede abrirlo utilizando la class << objectsintaxis.

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

O puede referirse a él directamente utilizando el singleton_classmétodo.

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Si todavía está dentro del contexto de la clase, selfse referirá a la clase. Entonces, lo anterior también podría escribirse como:

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

O

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

O una combinación de los dos.

3limin4t0r
fuente
5

Puede incluir los métodos de clase y sus alias_methodllamadas en un módulo separado e incorporar ese módulo a su clase a través de 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
fuente
¡Oye! Olvidé la extend ClassMethodssolución. +1
aarona
4

Lo importante a entender es que no existe un método de clase en Ruby.

Un método de clase es realmente solo un método singleton. No hay nada especial sobre los métodos de clase. Cada objeto puede tener métodos singleton. Simplemente los llamamos "métodos de clase" cuando el objeto es Classporque "el método singleton de una instancia de Class" es demasiado largo y difícil de manejar.

¡Espere! ¿Dije "método singleton"?

Otra cosa importante a entender es que no existe el método singleton en Ruby.

Un método singleton es realmente un método de instancia antiguo aburrido de la clase singleton. No hay nada especial sobre los métodos singleton. Son solo métodos de instancia como cualquier otro método de instancia.

De hecho, Ruby solo tiene métodos de instancia. Sin funciones, sin constructores, sin métodos estáticos, sin métodos de clase, sin funciones de módulo, sin métodos singleton.

La pregunta no es "¿es este un método de clase, es un método singleton", sino "en qué módulo se define este método?"

Los "métodos Singleton" son realmente métodos de instancia definidos en la clase Singleton. La sintaxis para acceder a la clase singleton de fooes

class << foo
end

También hay un método Object#singleton_classque devuelve la clase singleton de un objeto.

¿Por qué estoy insistiendo tan agresivamente en el hecho de que cada método es un método de instancia y que los métodos de clase no existen? ¡Porque significa que el modelo de objetos de Ruby es mucho más simple de lo que la gente piensa! Después de todo, en su pregunta, ya muestra que sabe cómo alias métodos de instancia, pero dice que no sabe cómo alias métodos de clase. ¡Pero eso está mal! Usted hace saber cómo los métodos de clase alias, ya que son métodos de instancia sólo . Si te hubieran enseñado este hecho correctamente, ¡nunca hubieras necesitado hacer esta pregunta!

Una vez que comprenda que cada método es un método de instancia, y que lo que llamamos "métodos singleton" son solo métodos de instancia de la clase singleton, la solución queda clara:

singleton_class.alias_method :a_new_class_method, :a_class_method

Nota: cuando escribí anteriormente que "no hay tal cosa como X", lo que quise decir fue que "no hay tal cosa como X en el lenguaje Ruby ". Eso no significa que esos conceptos no existan en la comunidad Ruby .

Hablamos regularmente de "métodos singleton" y "métodos de clase", simplemente porque es más fácil que hablar de "métodos de instancia de la clase singleton" o "métodos de instancia de la clase singleton de un objeto que resulta ser una instancia de la Classclase ". Hay incluso métodos como Object#define_singleton_method, Object#singleton_method, Object#singleton_methods,Module#private_class_method , Module#public_class_method, y Module#module_functionen la biblioteca núcleo Ruby. Pero siempre es importante recordar que esos no son conceptos de lenguaje. Esos son conceptos comunitarios que solo existen en nuestras cabezas y en los nombres de algunos métodos de biblioteca.

Jörg W Mittag
fuente
2

OK, parece que puedo hacer algo como esto y 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"

Si alguien tiene información útil sobre el lenguaje Ruby aquí y desea enviar una respuesta completa, le daré un +1.

aarona
fuente
1
Cuando lo haces, class << selfen alias_method :a_new_class_method, :a_class_methodrealidad recurres alias_methoda la clase singleton de Foo. Otra forma de escribir esto es: singleton_class.alias_method :a_new_class_method, :a_class_methoden contexto de clase.
3limin4t0r
¿Qué más quieres de una respuesta? Quiero decir, esta es probablemente la solución más limpia.
Dave Newton
@ 3limin4t0r si respondes eso, lo haré +1. Gracias por esta información extra.
aarona
@DaveNewton tienes razón, pero porque también tengo la filosofía de que si alguien puede proporcionar información más significativa a un problema, incluso si indirectamente resuelve el problema, creo que también debería ser recompensado.
aarona
2

alias_methodopera en la instancia, por lo que debe ir un nivel más profundo y operar en la Classinstancia, o la metaclase de la clase . Ruby tiene un modelo de objeto salvaje que puede ser una especie de rompe cerebro, pero también te da un montón 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
fuente
He estado trabajando con Ruby en un contexto de rieles durante aproximadamente una década, pero solo recientemente comencé a profundizar en el modelo de objetos. ¡Hay tantas cosas geniales disponibles!
aarona