I'm making a utility module that have some simple functions - I want the module to extend self so it does not need to be instantiated. A coworker and I were discussing various ways to store data in these types of modules, and one example he provided was this, using an instance variable:
module ExampleModule
extend self
@my_instance_variable = "Hello from module"
def do_thing
puts "**** #{@my_instance_variable}"
@my_instance_variable
end
end
This isn't an approach we decided to use, but I wanted to get a better understanding of why it works / best alternatives. So, a few questions:
Why does this work? How can a module method called without an instance access instance variables? Could you point me to any ruby docs / articles discussing this behavior?
Thoughts on if / when this is an appropriate pattern? (i'm not a fan since it seems counterintuitive for a module like this to have instance variables)
Should a class variable be used here instead? Our rubocop flags @@foo class variables as a code smell
In Ruby modules can have instance variables. This goes for classes as well as they are a kind of module. If you use the
Module.newmethod instead of the keyword this becomes even more apparent:The only real difference between the example above and your code is that you're using
extend self- which causesdo_thingto be callable on the module and not just classes which include the module.I'm not a huge fan of this and IMHO it would be better to just define the methods explicitly with
def self.method_namewhich is clearer about intent and can be picked up by static analysis.One very common use for module instance variables is the configuration pattern:
Here a set of gem specific settings are stored in
@configuration. You then set this in a initializer file which is loaded when booting the app:This allows app wide settings without relying on globals.
Module/class instance variables can be confusing if you're new to Ruby but remember that in Ruby everything is an object and that instance variables are not defined properties of a class. They are just variables which are lexically scoped to an instance of something which can be a module, class or an instance of a class.
Class variables in Ruby have a lot of unexpected behaviors and for that reason are usually best avoided. For example they are shared between a class and all of it's subclasses.