Wie kann ich die Instanzvariablen eines Moduls in Ruby initialisieren?

80

Ich habe einige Module, in denen ich Instanzvariablen verwenden möchte. Ich initialisiere sie derzeit wie folgt:

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

Ich könnte auch eine init-Methode aufrufen, um sie zu initialisieren:

def init
  @var = 0
end

aber das würde bedeuten, dass ich daran denken muss, es immer zu nennen.

Gibt es einen besseren Weg, dies zu tun?

Geo
quelle
3
Setzt der erste Codeblock nicht eine Modulinstanz-Variable (eine Variable im Bereich des MyModule-Typobjekts), während der zweite eine "einfache" Instanz-Variable (eine Variable im Bereich einer Instanz, die das Modul enthält) festlegt? Ich denke, dass diese beiden Codeblöcke nicht dasselbe tun ...
Boris B.

Antworten:

109

Initialisieren Sie sie in der Moduldefinition.

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

Dadurch werden die Instanzvariablen festgelegt, wenn das Modul definiert wird. Denken Sie daran, dass Sie das Modul jederzeit wieder öffnen können, um weitere Instanzvariablen und Methodendefinitionen hinzuzufügen oder vorhandene neu zu definieren:

# 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
quelle
12
Es ist schon eine Weile her, aber ja :). Außerdem habe ich das Gefühl, dass alles, was über die Herren Foo und Bar gesagt werden muss, gesagt wurde.
Rampion
Sind an dieser Stelle also keine Instanzvariablen, sondern Instanzmethoden?
Nipponese
nipponese: Was sind keine Instanzvariablen?
Rampion
5

Sie können verwenden:

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

Und es wird standardmäßig 0 sein, wenn Sie nichts übergeben.

Wenn Sie es nicht jedes Mal aufrufen müssen möchten, können Sie Folgendes verwenden:

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

end
Brian
quelle
Muss ich diese Funktion also noch aufrufen, bevor ich etwas mit dem Modul mache?
Geo
Ich habe einen zweiten Weg hinzugefügt, um dieses Problem zu vermeiden - es stammt aus dem Rails-Code
Brian
2

Für eine Klasse würde ich Folgendes sagen, da die Initialisierung immer dann aufgerufen wird, wenn Sie eine neue Instanz der Klasse erstellen.

def initialize
   @var = 0
end

von Practical Ruby :

Es heißt weiter, dass die Initialisierung eines Moduls aufgerufen wird, wenn die Initialisierung einer eingeschlossenen Klasse super aufruft, aber nicht erwähnt, dass dies eine Folge davon ist, wie super überall funktioniert, und keine spezielle Behandlung für die Initialisierung. (Warum könnte man annehmen, dass Initialisierung eine spezielle Behandlung erhält? Weil es eine spezielle Behandlung in Bezug auf die Sichtbarkeit erhält. Sonderfälle sorgen für Verwirrung.)


quelle
1
Wird die Initialisierung aufgerufen, da es sich um ein Modul handelt? Das war meine erste Antwort. Ich habe die zweite hinzugefügt, um zu berücksichtigen, dass sie nicht aufgerufen wird.
Brian
1
OP speziell erwähnte Module, keine Klassen
Zensaburou
2

i beantwortet eine ähnliche Frage , die Sie festlegen können Variablen Klasseninstanz dies zu tun

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
quelle
2

Anscheinend ist es eine schlechte Form, Instanzvariablen in einem Modul in Ruby zu initialisieren. (Aus Gründen, die ich nicht vollständig verstehe, die sich jedoch auf die Reihenfolge beziehen, in der die Dinge instanziiert werden.)

Es scheint, dass die beste Vorgehensweise darin besteht, Accessoren mit verzögerter Initialisierung zu verwenden, wie folgt:

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

Dann varals Getter für verwenden @var.

Andy
quelle
4
Beachten Sie, dass Sie @var niemals auf niloderfalse
stahl