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"