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
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"
8 Comments
sawa
+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.
Andrew Grimm
@sawa: It's somewhat misleading, but it's what Ruby itself uses:
defined?(@@foo) => "class variable".Peter Ajtai
Or they could be called static fields. Seems that's what they are.
MrPizzaFace
@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.intrixius
why the different calls at the end:
T.get and T::get ? |
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
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
Andrew Grimm
+1, but I'll just emphasize that class instance variables are different to class variables.
Julian
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
Orlando
@Julian not sure what you mean, this is just an example and you can use
attr_accessor or attr_reader depending on your use caseYou 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
Julian
I did not recommend to mutate a class variable, that's breaking the encapsulation rules. Also not following the Open/Close Principle from SOLID
TenJack
@julian This creates a class instance variable (since Modules are classes), right? Not sure how this breaks encapsulation...
Julian
Metaprogramming is an antipattern, that brakes the encapsulation principle.
Mike Slinn
Simple, easy to understand, good enough for government work