
Classes and Modules in ruby have always intrigued me!
So, I thought I’ll write some code to understand what they were.
Besides the standard Class aspects of ruby, there are a lot of interesting things that can be done with them – like singleton objects.
Modules, of course, give another level of flexibility.
Class
class variables
class Entity
@@instances = 0
def initialize
@@instances += 1
@number = @@instances
end
def who_am_i
"I'm #{@number} of #{@@instances}"
end
def self.total
@@instances
end
def modify_class_variable
@@instances = 100
end
end
create some entities
entities = Array.new(9) { Entity.new }
p entities[6].who_am_i # => "I'm 7 of 9"
p Entity.total # => 9
class variables can be modified by their instances
entities[3].modify_class_variable p Entity.total p entities[3].who_am_i # => "I'm 4 of 100"
class instance variables
In the code below, @instances is a class instance variable. It does not belong to an instance of class Entity, but to the class object Entity, which is an instance of class Class.
Class instance variables are directly accessible only within class methods of the class.
class Entity
@instances = 0
class << self
attr_accessor :instances # provide class methods for reading/writing
end
def initialize
self.class.instances += 1
@number = self.class.instances
end
def who_am_i
"I'm #{@number} of #{self.class.instances}"
end
def self.total
@instances
end
def modify_class_variable
self.class.instances = 100
end
end
This gives us the following output
entities = Array.new(9) { Entity.new }
p entities[6].who_am_i # => "I'm 7 of 9"
p Entity.instances # => 9
p Entity.total # => 9
class instance variables can also be modified by their instances
entities[3].modify_class_variable p Entity.total p entities[3].who_am_i # => "I'm 4 of 100"
class and instance methods
This one is pretty straightforward. Add self. before any method to make it a class method.
class Foo
def self.test
"this is from Foo class"
end
def mytest
"this is from an instance"
end
end
This gives us the following output
foo = Foo.new p Foo.test # => "this is from Foo class" p foo.mytest # => "this is from an instance" p foo.test # => private method 'test' called
singleton class
Per the definition –
A singleton class is an anonymous class that is created by subclassing the class associated with a particular object. Singleton classes are another way of extending the functionality associated with just one object.
Here is a standard class and object …
class Moo
def hello
"hello"
end
end
and it’s output …
moo = Moo.new p moo.hello # => "hello"
And here’s a singleton class.
class << moo
attr_accessor :name
def hello
"hello, I'm #{name}"
end
end
and it’s output …
moo.name = "Tom" p moo.hello # => "hello, I'm Tom" p moo.class # => MOo noo = Moo.new p noo.hello # => "hello"
However, this feels more like adding methods directly into objects (which actually it is!)
Note: moo instance has been customized without changing Moo class
singleton object
This is a singleton object, which I find very interesting!
foo = Class.new
class << foo
attr_accessor :name
def hello
"hello, I'm #{name}"
end
end
The output, looks like this!
foo.name = "Tom" p foo.hello # => "hello, I'm Tom" p foo.class # => Class
auto executing object
x = Class.new do
def run!
p "job done"
end
end.new.run!
The output, obviously, looks like this!
"job done"
object specific classes
And finally, what if I could have a string which can have it’s own custom methods!
a = "Tom"
class <<a
def hello
"hello I'm #{self}"
end
end
p a # => "Tom" p a.hello # => "hello, I'm Tom"
Module
Modules in ruby are pretty simple. But then we can do some other stuff with it also.
Examples from Ruby Lang
Module functions
Modules basically can have methods inside them, which can be called directly. Provided the module_function has been set.
module Foo
def hello
"hello"
end
# * has to be defined after the method!!
module_function :hello
end
The output –
p Foo.hello # => "hello"
Module constants
Modules can also have constants defined within them. They are only available within the module.
module Foo
# * can be assigned anywhere, either at the top or at the bottom
NAME = "Tom"
def hello
"hello, I'm #{NAME}"
end
module_function :hello
end
The output then, looks like this.
p Foo.hello # => "hello, I'm Tom" p NAME # => uninitialized constant NAME p Foo.NAME # => undefined method `NAME' for Foo:Module
Module mixins using ‘include’
So basically we can club a bunch of methods together into a module and then can include them in any class where I need them.
NOTE: In this case we cannot define the module method as a module function
module Foo
def hello
"hello, I'm #{NAME}"
end
NAME = "Tom"
end
class Moo
include Foo
def bye
"bye from #{NAME}"
end
end
Output –
moo = Moo.new p moo.hello # => "hello, I'm Tom" p moo.bye # => "bye from Tom"
Module ‘extend’ – extend object functionality
But what if we only want to extend the functionality of only a single object?
module Foo
NAME = "Jerry"
def hello
"hello, I'm #{@name}"
end
def hellojerry
"hello from #{NAME}"
end
end
class Moo
def initialize(name)
@name = name
end
def bye
"bye from #{@name}"
end
end
In this case the functionality of the moo object is extended with the module Moo
moo = Moo.new('Tom')
moo.extend(Foo)
p moo.hello # => "hello, I'm Tom"
p moo.bye # => "bye from Tom"
p moo.hellojerry # => "hello from Jerry"