133

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).

4 Answers 4

188

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"
Sign up to request clarification or add additional context in comments.

8 Comments

+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: It's somewhat misleading, but it's what Ruby itself uses: defined?(@@foo) => "class variable".
Or they could be called static fields. Seems that's what they are.
@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.
why the different calls at the end: T.get and T::get ?
|
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.

Comments

27

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"

3 Comments

+1, but I'll just emphasize that class instance variables are different to class variables.
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 not sure what you mean, this is just an example and you can use attr_accessor or attr_reader depending on your use case
12

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

4 Comments

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 This creates a class instance variable (since Modules are classes), right? Not sure how this breaks encapsulation...
Metaprogramming is an antipattern, that brakes the encapsulation principle.
Simple, easy to understand, good enough for government work

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.