Ruby Modules


Modules serve two functions in Ruby, namespacing and mix-in functionality. Namespacing is a programming concept that separates and organizes code to avoid global collisions. This is similar to the idea of avoiding global variables as to not pollute the global namespace. By creating a module named 'x', you can organize all of the associated code under the 'x' namespace.

Modules also provide an option for mixing in functionality. As discussed previously, Ruby is a single inheritance language. In order to "mix in" other functionality we can include modules. By including modules we gain all of the associated methods within those modules. This allows us to share common methods across multiple classes or modules. The enumerable mix-in module is one example of sharing methods, as we'll explore in detail in the chapter, Enumerable.

Modules are defined by the module keyword, followed by the name of the module. The module ends with the keyword end.

module A
# here is all the code for module A
end

Modules can be mixed-in classes that reside in the same file using the include keyword. By mixing a module into a class, the class will gain access to all of the methods defined in the module. These methods will be available to the instances of the class.

module A
  def say_hello(name)
    puts "hello " + name
  end
end

class User
include A # mix-in module A
end

>> user = User.new
>> user.say_hello("Bob")
hello Bob

The 'User' class has no methods defined but gained the "say_hello" method through the mix-in of module 'A'. Note: the method would be available on all instances of the 'User' class. Also, all code in the example is in the same file. If module 'A' were located in a separate file it could not be mixed-in with the keyword include. In that case, we would need to use the keyword require. This loads the module from another file and remembers that it is loaded. The keyword load would also work but it doesn't track if the file has already been loaded. To summarize, in cases where the modules are in the same file, use include. If the modules are in separate files, use require.

Modules are particularly handy when you have one method that is repeated in multiple classes. In order to follow the DRY principle, (Don't Repeat Yourself) the method can be extracted into a separate module and then included in the classes where it's needed. Consider the following example:

class Comment < ActiveRecord::Base
  def word_count
    body.split.count
  end
end

class Article < ActiveRecord::Base
  def word_count
    body.split.count
  end
end

# both classes contain the word_count method
# we can refactor and improve this code by creating a module

module TextContent
  def word_count
    body.split.count
  end
end
# once created, we can rewrite our Comment and Article classes

class Comment < ActiveRecord::Base
  include TextContent
end
class Article < ActiveRecord::Base
  include TextContent
end

# we can call the method in the same way, article.word_count

Our example uses one rather simple method but the context should be clear. Now, if we need to make a change to the 'word_count' method we only have to change it in one place. This allows us to write better, more maintainable code.

results matching ""

    No results matching ""