Esiste un metodo alias per un metodo di classe?


10

Considera la seguente 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

Questo non è un problema e puoi chiamare Foo.new.a_new_inst_methodsenza problemi.

Mi piacerebbe avere la possibilità di avere un metodo di classe simile Foo.add_widget(*items)e alias in modo da poter fare qualcosa di simile:

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

Quindi essenzialmente ha uno "stile rubino" 1.minutee 2.minutesquindi voglio un alias che una Foo.add_widgetchiamata Foo.add_widgetschiama esattamente lo stesso metodo. So che potrei avvolgerlo, ma sento che dovrei essere in grado di farlo in modo più pulito.

Considera il mio tentativo di provare qualcosa del genere:

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

Tuttavia, viene visualizzato il seguente errore:

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

E quindi sembra che questo non funzioni con i metodi di classe. Come procedo a fare questo?

Risposte:


9

alias_methodalias un metodo di istanze del ricevitore. I metodi di classe sono in realtà metodi di istanza definiti sulla classe singleton di una 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

Per alias un metodo di istanza definito sulla classe singleton è possibile aprirlo utilizzando la class << objectsintassi.

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Oppure puoi fare riferimento ad esso direttamente usando il singleton_classmetodo

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Se sei ancora all'interno del contesto della classe, selfti riferirai alla classe. Quindi quanto sopra potrebbe anche essere scritto come:

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 combinazione dei due.


5

Puoi racchiudere i metodi di classe e le loro alias_methodchiamate in un modulo separato e incorporare quel modulo nella tua classe tramite 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

Hey! Ho dimenticato la extend ClassMethodssoluzione. +1
aarona,

4

La cosa importante da capire è che non esiste un metodo di classe in Ruby.

Un metodo di classe è in realtà solo un metodo singleton. Non c'è niente di speciale nei metodi di classe. Ogni oggetto può avere metodi singleton. Li chiamiamo semplicemente "metodi di classe" quando l'oggetto è un Class"metodo singleton di un'istanza di Class" troppo lungo e ingombrante.

Aspettare! Ho detto "metodo singleton"?

Un'altra cosa importante da capire è che non esiste un metodo singleton in Ruby.

Un metodo singleton è in realtà solo un normale metodo noioso della vecchia istanza della classe singleton. Non c'è niente di speciale nei metodi singleton. Sono solo metodi di istanza come qualsiasi altro metodo di istanza.

In realtà, Ruby ha solo metodi di istanza. Nessuna funzione, nessun costruttore, nessun metodo statico, nessun metodo di classe, nessuna funzione di modulo, nessun metodo singleton.

La domanda non è "è un metodo di classe, è un metodo singleton", ma piuttosto "in quale modulo è definito questo metodo?"

I "metodi Singleton" sono in realtà metodi di istanza definiti nella classe singleton. La sintassi per accedere alla classe singleton di fooè

class << foo
end

Esiste anche un metodo Object#singleton_classche restituisce la classe singleton di un oggetto.

Perché sto martellando così aggressivamente sul fatto che ogni metodo è un metodo di istanza e che i metodi di classe non esistono? Perché significa che il modello a oggetti di Ruby è molto più semplice di quanto la gente pensi che sia! Dopotutto, nella tua domanda, mostri già che sai come alias metodi di istanza, ma dici che non sai come alias metodi di classe. Ma è sbagliato! Si fa sapere come metodi di classe alias, perché sono solo metodi di istanza . Se ti fosse stato insegnato questo fatto correttamente, non avresti mai avuto bisogno di porre questa domanda!

Una volta compreso che ogni metodo è un metodo di istanza e che quelli che chiamiamo "metodi singleton" sono solo metodi di istanza della classe singleton, la soluzione diventa chiara:

singleton_class.alias_method :a_new_class_method, :a_class_method

Nota: quando ho scritto sopra che "non esiste una cosa come X", intendevo dire che "non esiste una cosa come X nel linguaggio Ruby ". Ciò non significa che quei concetti non esistano nella comunità di Ruby .

Parliamo regolarmente di "metodi singleton" e "metodi di classe", semplicemente perché è più facile che parlare di "metodi di istanza della classe singleton" o "metodi di istanza della classe singleton di un oggetto che risulta essere un'istanza della Classclasse ". Ci sono metodi anche come Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, e Module#module_functionnella libreria di base di Ruby. Ma è sempre importante ricordare che quelli non sono concetti linguistici. Questi sono concetti di comunità che esistono solo nelle nostre teste e nei nomi di alcuni metodi di biblioteca.


2

OK, sembra che io possa fare qualcosa del genere e funzionerà:

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 qualcuno ha informazioni utili sulla lingua di Ruby qui e desidera inviare una risposta completa, ti darò un +1.


1
Quando lo fai, class << selfsegui alias_method :a_new_class_method, :a_class_methodeffettivamente alias_methodla classe singleton di Foo. Un altro modo di scrivere questo è: singleton_class.alias_method :a_new_class_method, :a_class_methodnel contesto di classe.
3limin4t0r

Cosa vuoi di più da una risposta? Voglio dire, questa è probabilmente la soluzione più pulita.
Dave Newton,

@ 3limin4t0r se fai una risposta, la +1. Grazie per queste informazioni extra.
aarona,

@DaveNewton hai ragione, ma perché ho anche una filosofia secondo cui se qualcuno può fornire ulteriori informazioni significative a un problema anche se risolve indirettamente il problema, penso che dovrebbe essere premiato.
aarona,

2

alias_methodopera sull'istanza, quindi è necessario approfondire un livello e operare Classsull'istanza o sulla metaclasse della classe . Ruby ha un modello a oggetti selvaggi che può essere una specie di rottura del cervello, ma ti dà anche un sacco di potere:

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

Ho lavorato con Ruby in un contesto di binari per circa un decennio, ma solo di recente ho iniziato a fare un tuffo nel modello di oggetti. Ci sono così tante cose interessanti disponibili!
aarona,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.