
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"
				
			