Ruby modules are awesome
Monday, January 12th, 2009If 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.