web-dev-qa-db-fra.com

Comment puis-je initialiser les variables d'instance d'un module dans Ruby?

J'ai certains modules dans lesquels j'aimerais utiliser des variables d'instance. Je les initialise actuellement comme ceci:

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

Je pourrais également appeler une méthode init pour les initialiser:

def init
  @var = 0
end

mais cela signifierait que je dois me rappeler de toujours l'appeler.

Existe-t-il une meilleure façon de le faire?

76
Geo

Initialisez-les dans la définition du module.

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!"

Cela définira les variables d'instance lorsque le module est défini. N'oubliez pas que vous pouvez toujours rouvrir le module ultérieurement pour ajouter d'autres variables d'instance et définitions de méthode, ou pour redéfinir celles existantes:

# 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?"
104
rampion

Vous pouvez utiliser:

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

Et il sera par défaut à 0 si vous ne passez rien.

Si vous ne voulez pas avoir à l'appeler à chaque fois, vous pouvez utiliser quelque chose comme ceci:

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

end
5
Brian

pour une classe, je dirais ce qui suit, puisque l'initialisation est appelée chaque fois que vous .new une nouvelle instance de la classe.

def initialize
   @var = 0
end

de Ruby pratique :

Il continue en disant que l'initialisation d'un module sera appelée si l'initialisation d'une classe incluant appelle super, mais ne mentionne pas que c'est une conséquence de la façon dont super fonctionne partout, pas une gestion spéciale pour l'initialisation. (Pourquoi pourrait-on supposer que l'initialisation reçoit un traitement spécial? Parce qu'il obtient un traitement spécial en ce qui concerne la visibilité. Les cas spéciaux créent de la confusion.)

2
consumer

j'ai répondu à une --- question similaire, vous pouvez définir les variables d'instance de classe en faisant cela

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"
2
Orlando

Apparemment, c'est une mauvaise forme d'initialiser des variables d'instance dans un module de Ruby. (Pour des raisons que je ne comprends pas bien, mais concernant l'ordre dans lequel les choses sont instanciées.)

Il semble que la meilleure pratique consiste à utiliser des accesseurs avec une initialisation paresseuse, comme ceci:

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

Utilisez ensuite var comme getter pour @var.

2
Andy