¿Cómo puedo inicializar las variables de instancia de un módulo en Ruby?

80

Tengo algunos módulos en los que me gustaría usar variables de instancia. Actualmente los estoy inicializando así:

module MyModule
  def self.method_a(param)
    @var ||= 0
    # other logic goes here
  end
end

También podría llamar a un método init para inicializarlos:

def init
  @var = 0
end

pero esto significaría que tengo que recordar llamarlo siempre.

¿Existe una forma mejor de hacer esto?

Geo
fuente
3
¿No establece el primer bloque de código una var de instancia de módulo (una var en el alcance del objeto de tipo de MyModule), mientras que el segundo establece una var de instancia "simple" (una var en el alcance de una instancia que incluye el módulo)? Creo que estos dos bloques de código no hacen lo mismo ...
Boris B.

Respuestas:

109

Inicialícelos en la definición del módulo.

module MyModule
  # self here is MyModule
  @species = "frog"
  @color = "red polka-dotted"
  @log = []

  def self.log(msg)
    # self here is still MyModule, so the instance variables are still available
    @log << msg
  end
  def self.show_log
    puts @log.map { |m| "A #@color #@species says #{m.inspect}" }
  end
end

MyModule.log "I like cheese."
MyModule.log "There's no mop!"
MyModule.show_log #=> A red polka-dotted frog says "I like cheese."
                  #   A red polka-dotted frog says "There's no mop!"

Esto establecerá las variables de instancia cuando se defina el módulo. Recuerde, siempre puede volver a abrir el módulo más tarde para agregar más variables de instancia y definiciones de métodos, o para redefinir las existentes:

# continued from above...
module MyModule
  @verb = "shouts"
  def self.show_log
    puts @log.map { |m| "A #@color #@species #@verb #{m.inspect}" }
  end
end
MyModule.log "What's going on?"
MyModule.show_log #=> A red polka-dotted frog shouts "I like cheese."
                  #   A red polka-dotted frog shouts "There's no mop!"
                  #   A red polka-dotted frog shouts "What's going on?"
rampion
fuente
12
Ha pasado un tiempo, pero sí :). Además, creo que se ha dicho todo lo que hay que decir sobre los Sres. Foo y Bar.
rampion
Entonces, en este punto, ¿no son variables de instancia, sino métodos de instancia?
nipponese
nipponese: ¿qué no son variables de instancia?
rampion
5

Puedes usar:

def init(var=0)
 @var = var
end

Y se establecerá por defecto en 0 si no pasa nada.

Si no quiere tener que llamarlo cada vez, puede usar algo como esto:

module AppConfiguration
   mattr_accessor :google_api_key
   self.google_api_key = "123456789"
...

end
Brian
fuente
Entonces, ¿todavía necesito llamar a esta función antes de hacer algo con el módulo?
Geo
Agregué una segunda forma de evitar ese problema: es del código de rieles
Brian
2

para una clase, diría lo siguiente, ya que se llama a initialize cada vez que usted.

def initialize
   @var = 0
end

de Practical Ruby :

Continúa diciendo que se llamará a la inicialización de un módulo si la inicialización de una clase incluida llama a super, pero no menciona que esto es una consecuencia de cómo funciona super en todas partes, no un manejo especial para la inicialización. (¿Por qué se puede suponer que initialize recibe un tratamiento especial? Porque recibe un tratamiento especial con respecto a la visibilidad. Los casos especiales crean confusión).


fuente
1
Dado que es un módulo, ¿se llamará a initialize? Esa fue mi primera respuesta. Agregué el segundo para tener en cuenta que no se llamó.
Brian
1
OP mencionó específicamente módulos, no clases
Zensaburou
2

Respondí una pregunta similar , puede establecer variables de instancia de clase haciendo esto

module MyModule
  class << self; attr_accessor :var; end
end

MyModule.var
=> nil

MyModule.var = 'this is saved at @var'
=> "this is saved at @var"

MyModule.var    
=> "this is saved at @var"
Orlando
fuente
2

Aparentemente, es una mala forma inicializar variables de instancia en un módulo en Ruby. (Por razones que no entiendo completamente, pero relacionadas con el orden en el que se instancian las cosas).

Parece que la mejor práctica es usar accesores con inicialización perezosa, así:

module MyModule
  def var
    @var ||= 0 
  end
end

Luego utilícelo varcomo getter para @var.

Andy
fuente
4
Tenga en cuenta que esto nunca le permitirá establecer @var en nilofalse
acero