We've previously learned about modules (like Enumerable), the nice packages of methods that you can mix into classes. But if you're using a class mostly so your objects can get access to a bunch of methods anyway, what's the difference?
In this very brief lesson, we'll look at the difference between classes and modules and how you can use modules to supercharge classes. Focus on understanding the conceptual difference between the two and not on memorizing the different ways of combining them. There will be plenty of time for that later.
Basically, a class can be instantiated but a module cannot. A module will never be anything other than a library of methods. A class can be so much more -- it can hold its state (by keeping track of instance variables) and be duplicated as many times as you want. It's all about objects.
If you need to instantiate something or otherwise have it exist over time, that's when you need to use a class instead of a module.
As a brief review, we'll look at how to include a module (library) of methods into your classes. This should be more useful now because it's different depending on whether you want the module's methods to become instance methods or class methods.
Including a module of methods in your project is as easy as it gets -- just literally
include it directly into one of your classes and your class will have access to all its methods as instance methods. Instant functionality!
class YourClass include YourModule end
including the module, you can (less commonly) also
extend it. The difference is that
including the module makes all the module's methods instance methods whereas
extending the module makes all its methods class methods (e.g. as if it prepended each one of them with
class YourClass extend YourModule end
You can see both of these in action below:
module ModuleExample def foo 'foo' end end # Including modules binds the methods to the object instance class Person include ModuleExample end # Extending modules binds the methods to the class itself class Book extend ModuleExample end # IRB > Person.foo # => NoMethodError: undefined method `foo' for Person:Class > Person.new.foo # => 'foo' > Book.foo # => 'foo' > Book.new.foo # => NoMethodError: undefined method `foo'
When you're building smaller projects, it may not make a whole lot of sense to worry about modules. Your classes aren't (at first) likely to be large enough (or similar enough) to justify breaking out packages of methods into their own modules.
Web frameworks, though, often have different areas of responsibility that include a number of similar classes. In Rails for instance, we use "Controller" classes to house the flow logic of the application. You'll commonly want to have a number of different Controllers defined, for instance one for your Blog pages, one for your Authentication system, one for your Product pages etc.
There are often similar "helper" methods that you want to be available across all of those classes without having to redefine them in each class (which would be terribly not DRY). These might be things like the
current_user method which returns the currently signed-in user of your app. To make this available to all your controllers, you would define it in a module like the
ApplicationController, which gets included in every controller by default.
Hopefully that sheds a bit of light on why modules are actually useful so you can safely tuck away the knowledge for later.
The important bits of code from this lesson
class YourClass # Include the methods within the class # as instance methods include SomeModule # Tell the class to extend the module, which # treats its methods as class methods extend SomeOtherModule end
Modules may seem a bit overkill for now but file them away in the back of your mind. As long as you understand that they're really just flat libraries of methods (sometimes capturing overflow from big classes) while classes are deep and dynamic tools, you've got the gist of it. You'll see modules crop up again later on and you'll be well prepared to roll with them.
As a final thought question...
If a hash (which has good data storage) and a module (which has good methods) had a love child, would it be a class (an object with methods)???