Ruby modules are awesome January 12, 2009 at 5:00 am

If you read my previous blog, well. I told you this was a roller coaster! I’m starting to feel manic.

Ruby, on the other hand, is pretty solid, well documented, and cool.

After fighting with stupid gems all day, I decided to just let people include their own with a simple wrapper. So I started playing with modules.

Modules really rock. They are so freakin simple it’s unbelievable. Modules are sort of like namespaces but you can build upon already loaded ones. Basically, what this means to me is that I can have a base/core module that loads all the files in some module directory, and then figures out dynamically what’s been loaded.

Here’s a practical example (from the previous blog).

Let’s say we want to be able to let a system administrator installing our software decide where users authenticate from. The avilable options *we* thought of were Active Directory, Local Database and Linux PAM. But the reality is not everyone will need all of these options, but someone might need two of them (like local DB and active directory – such that when A.D. is down you can still get into your machine). How do we do this?

First, the individual modules would look something like this:

module MyAuthFramework
  module AuthViaLDAP
    def Login
    # Do login validation here, possibly through a gem
    end
  end
end

You’d save that to a folder somewhere, along with maybe another module, like this:

module MyAuthFramework
  module AuthViaPAM
    def Login
    # Do login validation here, possibly through a gem
    end
  end
end

Note that the two modules share the same method name and base module, but the module namespace in the middle is different. Loading both the above files from the same Ruby script effectively mixes them together, creating this:

module MyAuthFramework
  module AuthViaPAM
    def Login
    # Do login validation here, possibly through a gem
    end
  end

  module AuthViaLDAP
    def Login
    # Do login validation here, possibly through a gem
    end
  end
end

Now, in a base file somewhere, we can use a nifty constants method built into modules to accurately see what’s loaded and cycle through each class, calling it’s login function with some credentials we received. Whoever returns a success could be declared the winner!

module MyAuthFramework
  def Login
    MyAuthFramework.constants.each do |modulename|   # Cycle through all modules
      mod = Object.const_get(modulename)                    # Instantiate the module
      mod.Login()    # Call the method in each module
  end
end

This routine will effectively call the Login() methods in both the included modules, LDAP and PAM.

cool, huh?

Check out the docs for more goodness.

Leave a Reply

You must be logged in to post a comment.