Modules & Classes

Classes

Class is a built-in Ruby object which inherits from the Module class, another built-in Ruby object.

The Ruby Class object can be used to create Ruby classes that is objects with the ability of instantiation.

class Animal
end

Animal.class # => Class

Instances

To initialize an instance of a given class the static method :new is called. The arguments (zero or more) and behaviour of :new method is defined using initialize method.

class Animal
  def initialize(species:, name:)
    @species = species
    @name = name
  end
end

Animal.new(species: 'fish', name: 'Wanda').class # => Animal

Methods & Self

Methods defined within a class are instance methods not the class object's (aka static) methods unless they are defined on the class object itself using def self.foo (or def Bar.foo) or an idiom class << self is used.

class Thing
  def inspect_instance_self
    puts self
  end

  def self.inspect_class_self # == def Thing.inspect_class_self
    puts self
  end
end

Thing.inspect_instance_self # NoMethodError (undefined method `inspect_self' for Thing:Class)
Thing.inspect_class_self # => Thing

Thing.new.inspect_instance_self # => #<Thing:0x00007fa25187e808>
Thing.new.inspect_class_self # => NoMethodError (undefined method `inspect_class_self' for #<Thing:0x00007fa25500d418>)

When the idiom class << self is used the methods defined within its block are the class static methods.

class Item
  class << self
    def inspect_self
      puts self
    end
  end
end

Item.inspect_self # Item 
Item.new.inspect_self # NoMethodError (undefined method `inspect_self' for #<Item:0x00007fcf8c0845e0>)

Each Object Has Two Classes

It is sometimes inaccurately said that in Ruby a given object has only one class. In Ruby each object has exactly one named class - its direct ancestor - and the second one - existing beside the direct ancestor class - called a singleton or an eigenclass class. Methods defined with self.foo or << self are defined as methods of the eigenclass and used as singleton methods.

Inheritance

Each class in Ruby inherits from some other class - its direct ancestor. Methods and constants defined within a given class ancestor and ancestors of its ancestor are available within the class.

class Airplane
  def self.inspect
    'Inspecting'
  end

  def fly
    'Flying'
  end
end

class Jet < Airplane
end

Jet.inspect # "Inspecting"
Jet.new.fly # "Flying"

Instance Variables

Instance variables are denoted with @ and assigned to a specific instance of a Ruby class.

class Animal
  def initialize(species:, name:)
    @species = species
    @name = name
  end
end

an_animal = Animal.new(species: 'horse', name: 'Roach') # => <Animal:0x00007fd4801896e0 @name="Roach", @species="horse">

If a get method is defined within the class of the instance then it is possible to get a specific instance variable through sending a message with the name of the get method to the instance.

If a set method is defined within the class of the instance it is possible to set a specific instance variable through sending a message with the name of the set method to the instance (syntactic sugar for = can be used).

class Animal
  def initialize(species:, name:)
    @species = species
    @name = name
  end

  # get method
  def name
    @name
  end

  # set method
  def name=(name)
    @name = name
  end
end

an_animal = Animal.new(species: 'horse', name: 'Roach') # => <Animal:0x00007fd4801896e0 @name="Roach", @species="horse">

an_animal.name # => "Roach"
an_animal.name = "Kelpie"
an_animal.name # => "Kelpie"

attr_reader :name can be used instead of def name, attr_writer :name can be used instead of def name=(name). attr_accessor combines attr_reader and attr_writer.

Modules

The Module class is a built-in Ruby object instances of which 1) provide namespaces allowing for collision-free defining of constants and methods, 2) enable broadening of classes' functionalities through mixins.

Creation of a module is signalled by the module reserved word.

module CustomMath
  def sum(a, b)
    a + b
  end
end

Including Modules

When a class includes a module with an include keyword the non-static methods defined in the module become the class'es instance methods.

class SimpleMath
  include CustomMath
end

simple_math = SimpleMath.new # => <SimpleMath:0x00007fd630054700>
simple_math.sum(2, 2) # => 4

Prepending Modules

prepend works similarly to include and the difference between the two is that prepend gives precedence to methods defined in the module to those defined directly in the class.

Extending Classes with Modules

Extending a class with a module with an extend keyword makes the non-static methods defined in the module to be available within the class as the class methods.