127

Is there any way to create a variable in a module in Ruby that would behave similar to a class variable? What I mean by this is that it would be able to be accessed without initializing an instance of the module, but it can be changed (unlike constants in modules).

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Mark Szymanski
  • 56,590
  • 24
  • 70
  • 87

4 Answers4

184

Ruby natively supports class variables in modules, so you can use class variables directly, and not some proxy or pseudo-class-variables:

module Site
  @@name = "StackOverflow"

  def self.setName(value)
    @@name = value
  end

  def self.name
    @@name
  end
end

Site.name            # => "StackOverflow"
Site.setName("Test")
Site.name            # => "Test"
coreyward
  • 77,547
  • 20
  • 137
  • 166
  • 7
    +1 Actually, I have been thinking that the term 'class variable' is misleading. Classes are special cases of modules, and class variables are definable on modules. They should be called module variables. – sawa Apr 17 '11 at 02:54
  • 4
    @sawa: It's somewhat misleading, but it's what Ruby itself uses: `defined?(@@foo) => "class variable"`. – Andrew Grimm Jan 09 '12 at 05:57
  • 1
    Or they could be called static fields. Seems that's what they are. – Peter Ajtai May 11 '12 at 01:11
  • 1
    @coreyward Hey my mistake. Why the need for two '@@' class variables? Isn't it considered a code smell, especially if the class is extended to use class variables? I was testing this and I realized I could get the same result from a single `@` instance variable. Is there a specific reason for using class variables? Thanks for the reply. – MrPizzaFace Jan 25 '14 at 02:14
  • @feed_me_code It's just a part of the language. A class variable is on the actual class, not an instance of the class. In most cases these will behave similarly, but not always. See http://stackoverflow.com/questions/5890118/what-does-variable-mean-in-ruby for a more in-depth explanation. – coreyward Jan 25 '14 at 20:08
  • 2
    why the different calls at the end: `T.get` and `T::get` ? – intrixius Aug 05 '14 at 10:05
  • @intrixius This being so long ago I'm not sure what prompted me to use the `::` notation, perhaps just an effort to show that there are multiple ways of accessing the methods. These two are essentially identical in behavior, but the dot notation is preferred. – coreyward Aug 05 '14 at 17:06
  • The only thing I probably remove is the Setter, that's breaking the Open/Close Principle from SOLID. If you need to mutate the value highly suggest to use a Instance Variable. – Julian Aug 16 '22 at 06:11
32

If you do not need to call it from within an instance, you can simply use an instance variable within the module body.

module SomeModule
  module_function
  def param; @param end
  def param= v; @param = v end
end

SomeModule.param
# => nil
SomeModule.param = 1
SomeModule.param
# => 1

The instance variable @param will then belong to the module SomeModule, which is an instance of the Module class.

sawa
  • 165,429
  • 45
  • 277
  • 381
25

you can set a class instance variable in the module.

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

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

MyModule.var    
=> "this is saved at @var"
Orlando
  • 9,374
  • 3
  • 56
  • 53
  • 2
    +1, but I'll just emphasize that class instance variables are different to class variables. – Andrew Grimm Jan 09 '12 at 05:58
  • Btw also the encapsulation of the ATTR should not be 'read and write' should be just 'read': class << self; attr_reader :var; end And even that is not the proper solution for this case – Julian Aug 16 '22 at 06:07
  • @Julian not sure what you mean, this is just an example and you can use `attr_accessor` or `attr_reader` depending on your use case – Orlando Aug 16 '22 at 19:26
9

You can also initialize value within module definition:

module MyModule
  class << self
    attr_accessor :my_variable
  end
  self.my_variable = 2 + 2
end

p MyModule.my_variable
Nakilon
  • 34,866
  • 14
  • 107
  • 142
  • I did not recommend to mutate a class variable, that's breaking the encapsulation rules. Also not following the Open/Close Principle from SOLID – Julian Aug 16 '22 at 06:09
  • @julian This creates a class instance variable (since Modules are classes), right? Not sure how this breaks encapsulation... – TenJack Apr 24 '23 at 21:36
  • Metaprogramming is an antipattern, that brakes the encapsulation principle. – Julian May 03 '23 at 21:47