Programmer.new
Taking it One Line at A Time

Modules And Other Concerns

First technical post. Yes, this is my first post where I actually take my instructor’s advice, which is to blog about the things in Ruby and Rails I am least certain about in an effort to better understand them.

One thing that I’m pretty sure is going to come in handy but don’t feel comfortable with is the Ruby Module. Let’s start simple and then extract. Module - what is it?

“Same, same, Class but different”

Just like a class it is a:

  1. Object - just like everything else in Ruby
  2. Constant

And maybe other stuff, but I said I’d keep it simple for your sake of course (cough cough and mine).

Ok so let’s just write some code:

1
2
3
4
5
6
7
8
9
10
11
module Singlish

  def possible?
    "Can, lah!?"
  end

  def available?
    "Have?"
  end

end

Ok so say you’re at 7/11 but in SINGAPORE or something and you want to find out if they sell Thai Redbull - very common situation. So you want to mixin your Singlish module into your English class so that you can call on some instance methods which basically translate your English to Singlish for you. We mixin the Singlish module by using the Ruby “include” keyword:

Can, la!

1
2
3
4
5
class English

include Singlish

end

Now you can do this:

1
2
2.1.2 :030 > English.new.possible?
 => "Can, lah!?"

Ok, easy right? But what if we want our module to have a little more functionality?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module Singlish
  module ClassMethods

    def translations
      "I extended the Singlish module"

    end
  end

  module InstanceMethods

    def possible?
      "Can, lah!?"
    end

    def available?
      "Have?"
    end
  end

end

Now within our Singlish module, we have both class and instance methods that we can mixin to our English class. But how do we do that, you ask? We continue to use the “include” keyword to include the module’s instance methods in the English class. To mixin the Singlish modules’s class methods, however, we must use the “extend” keyword.

1
2
3
4
5
6
7
class English

include Singlish::InstanceMethods

extend Singlish::ClassMethods

end

Now, look what we can (and can’t) do!

1
2
3
4
5
6
7
8
9
10
11
12
#calling the class method, made possible by extend
2.1.2 :028 > English.translations
 => "I extended the Singlish module"
 #trying to call the class method on an instance of English does not work
2.1.2 :029 > English.new.translations
NoMethodError: undefined method `translations' for #<English:0x007fab3c0a7078>

#but we can call the instance methods on instances of the English class!
2.1.2 :031 > English.new.available?
 => "Don't have" 
2.1.2 :032 > English.available?
NoMethodError: undefined method `available?' for English:Class

It doesn’t technically matter what you named the nested modules within the Singlish module. In my example, I name them (reasonably) “InstanceMethods” and “ClassMethods” but I could have named them “LeatherJacket” and “Tomato”. As long as I “include LeatherJacket” and “extend Tomato,” the class wil inherit LeatherJacket’s methods as instance methods and Tomato’s methods as class methods for the English class to use.