8.2 Modules as Namespaces

Collision course

Namespacing is a way of bundling logically related objects together. Modules serve as a convenient tool for this. This allows classes or modules with conflicting names to co-exist while avoiding collisions. Think of this as storing different files with the same names under separate directories in your filesystem.

Modules can also hold classes. In this example, we'll try and define an Array class under our Perimeter module from the last lesson. Notice how it does not affect Ruby's Array class at all.

Example Code:

Output Window

We have these two classes alongside each other. This is possible because we've namespaced our version of the Array class under the Perimeter module.

:: is a constant lookup operator that looks up the Array constant only in the Perimeter module.

What happens when we don't namespace our Array class?

Example Code:

Output Window

Because Ruby has open classes, doing this simply extends the Array class globally throughout the program, which is dangerous and of course not our intended behaviour.

The examples above are a bit contrived for the sake of simplicity. The real problem that namespacing solves is when you're loading libraries. If your program bundles libraries written by different authors, it is often the case that there might be classes or modules defined by the same name.

We're assuming these two libraries gym and dojo have classes as shown in the comment above them.

Example Code:

Output Window

As the dojo library is loaded after gym, it has overriden gym's class definition of Push and therefore creates an instance of Push defined in dojo.

The way to solve this problem is to wrap these classes in appropriate namespaces using modules.

Example Code:

Output Window

When you're creating libraries with Ruby, it is a good practice to namespace your code under the name of your library or project.

Constant lookup

We used the constant lookup (::) operator in the last section to scope our class to the module. As the name suggests, you can scope any constant using this operator and not just classes.
Example Code:

Output Window

There are a few things going on the example above.

  • Constant A is scoped within Dojo and accessing it via :: works as expected.
  • Same for constant B which is nested further inside Kata.
  • Class ScopeIn is nested even deeper inside Roulette which has a method returning 15.

This tells us two important things. One, we can nest constant lookups as deep as we want. Second, we aren't restricted to just classes and modules.

You are given a library called RubyMonk. It contains a module Parser which defines a class CodeParser. Write another class TextParser in the same namespace that parses a string and returns an array of capitalized alphabets.

Output Window

If you prepend a constant with :: without a parent, the scoping happens on the topmost level. In this exercise, change push to return 10 as per A = 10 in the topmost level, outside the Kata module.

Output Window

Using modules and namespacing is the standard way of organizing libraries with Ruby. It's a good practice to keep this in mind while writing one.

Congratulations, guest!


% of the book completed

or

This lesson is Copyright © 2011-2024 by Sidu Ponnappa and Jasim A Basheer