Classes

In an object-oriented programming language like Ruby, a class is a container that holds properties (class members) such as methods and variables. Classes can inherit properties from a parent or superclass, creating a hierarchy of classes with a base class at the root or top. In Ruby, the base class is Object. Ruby uses single inheritance—that is, a Ruby class can inherit the properties of only one parent class. (Multiple inheritance, as is used in C++, allows a class to inherit from more than one parent.) You can define more than one class in a single file in Ruby. A class itself is an object, even if you don't directly instantiate it. Classes are always open, so you can add to any class, even a built-in one.

A class is defined with a class keyword, and the definition concludes with an end:

class Hello

  def initialize( name )
    @name = name
  end

  def hello_matz
    puts "Hello, " + @name + "!"
  end

end

hi = Hello.new( "Matz" )
hi.hello_matz # => Hello, Matz!

The initialize method defines the instance variable @name by storing a copy of the name argument passed into the initialize method. The initialize method is a Ruby convention that acts like a class constructor in other languages, but not completely. At this point, the instance is already there, fully instantiated. initialize is the first code that is executed after the object is instantiated; you can execute just about any Ruby code in initialize. initialize is always private; that is, it is scoped only to the current object, not beyond it. You access the instance variable @name with the method hello_matz.

To add a method to an existing class, such as the built-in class Array, specify the following:

class Array
  def array_of_ten
    (1..10).to_a
  end

end

arr = Array.new
ten = arr.array_of_ten
p ten # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

As mentioned previously, an instance variable is a variable that is available from within an instance of a class, and is limited in scope because it belongs to a given object. An instance variable is prefixed by a single at sign (@), like:

@name = "Easy Jet"

You can define an instance variable inside a method or outside of one. You can only access an instance variable from outside an object via a method. You can, however, access an instance variable within the object without a method:

class Horse

  @name = "Easy Jet"

end

This works if you only want to reference @name from within the object. You have no way to retrieve the value of @name directly from outside of the object. You must define a getter (accessor) method to retrieve the value:

class Horse

  def name
    @name = "Easy Jet"
  end

end

h = Horse.new
h.name # => "Easy Jet"

You often want a setter in addition to a getter. A setter is an accessor method that sets the value of a variable:

class Horse

  def name
    @name
  end

  def name=( value )
    @name = value
  end

end

h = Horse.new
h.name= "Poco Bueno"
h.name # => "Poco Bueno"

The setter method name= follows a Ruby convention: the name of the method ends with an equals sign (=). This convention is not a requirement. You could call name= whatever you like, as long as the characters are legal. Here is another version of the class Horse that initializes the instance variable @name with the standard initialize method. Later the program creates an instance of the class by calling new, and then accesses the instance variable through the accessor method horse_name, via the instance horse:

class Horse

  def initialize( name )
    @name = name
  end

  def horse_name
    @name
  end

end

horse = Horse.new( "Doc Bar" )
puts horse.horse_name # => Doc Bar

Ruby simplifies the creation of getters and setters by meta-programming with the methods attr, attr_reader, attr_writer, and attr_accessor, all from the Module class. The attr method creates a single getter method, named by a symbol, with an optional setter method (if the second argument is true):

class Dog
  attr :bark, true
end

Dog.instance_methods - Object.instance_methods
# => ["bark", "bark="]

dog = Dog.new

dog.bark="Woof!"
puts dog.bark # => Woof!

By calling attr with :bark and true as arguments, the class Dog will have the instance methods bark and bark=. If you call attr with only the :bark argument, Dog would have only the getter method bark. (Notice that you can subtract out Object's instance methods with - when retrieving Dog's instance methods.)

The attr_reader and attr_writer methods accept as arguments the names of one or more instance variables, then create corresponding methods that return (attr_reader) or set (attr_writer) the values of each instance variable. (Instance variables are not actually created until you assign values to them.) Consider this example:

class Dog
  attr_reader :bark # getter
  attr_writer :bark # setter
end

dog = Dog.new

dog.bark="Woof!"
puts dog.bark # => Woof!

dog.instance_variables.sort # => ["@bark"]
Dog.instance_methods.sort - Object.instance_methods
# => [ "bark", "bark=" ]

Calling the attr_accessor method does the same job as calling both attr_reader and attr_writer together, for one or more instance variables:

class Gaits
  attr_accessor :walk, :trot, :canter
end

Gaits.instance_methods.sort - Object.instance_methods # =>
["canter", "canter=", "trot", "trot=", "walk", "walk="]

A class variable is shared among all instances of a class, so only one copy of a class variable exists for a given class. In Ruby, a class variable is prefixed by two at signs (@@). You must initialize a class attribute before you use it, such as @@times = 0.

class Repeat
  @@total = 0
  def initialize( string, times )
    @string = string
    @times = times
  end
  def repeat
    @@total += @times
    return @string * @times
  end
  def total
    "Total times, so far: " + @@total.to_s
  end
end

data = Repeat.new( "ack ", 8 )
ditto = Repeat.new( "Again! ", 5 )
ditty = Repeat.new( "Rinse. Lather. Repeat. ", 2 )

puts data.repeat # => ack ack ack ack ack ack ack ack
puts data.total # => Total times, so far: 8

puts ditto.repeat # => Again! Again! Again! Again! Again!
puts ditto.total # => Total times, so far: 13

puts ditty.repeat
# => Rinse. Lather. Repeat. Rinse. Lather. Repeat.
puts ditty.total # => Total times, so far: 15

A class method is a method that is associated with a class (and with a module in Ruby), not an instance of a class. You can invoke class methods by prefixing the name of the method with the name of the class to which it belongs, such as to Math.sqrt(36). Class methods are also called static methods. You can also associate the name of a module with a method name, just like with a class, but to use such a method, you must include the module in a class. To define a class method, you simply prefix the name of the method with the name of the class or module (or self) in the method definition:

class Area

# Use self.rect or Area.rect
# def self.rect( length, width, units="inches" )
  def Area.rect( length, width, units="inches" )
    area = length*width
    printf( "The area of this rectangle is %.2f %s.",
                 area, units )
    sprintf( "%.2f", area )
  end

end

Area.rect(12.5, 16) # => The area of this rectangle is
200.00 inches.

Another way you can define class methods is by using a class within a class and self—a singleton class. In basic terms, a singleton is designed so that it can only be instantiated once. It is often used like a global variable. Ruby has a class for defining singleton objects; see http://www.ruby-doc.org/core/classes/Singleton.html. Consider this example:

class Area

  class << self
    def rect( length, width, units="inches" )
      area = length*width
      printf( "The area of this rectangle is %.2f %s.",
                   area, units )
      sprintf( "%.2f", area )
    end

  end

end

Area.rect(10, 10) # The area of this rectangle is 100.00
inches.=> "100.00"

In this form, you don't have to prefix the method with the class name. A singleton class is tied to a particular object, can be instantiated only once, and is not distinguished by a prefixed name. The method rect is also effectively a singleton method because it is tied to the singleton class. Here is a way to define a singleton method, one that is tied to a single object:

class Singleton
end

s = Singleton.new
def s.handle
  puts "I'm a singleton method!"
end

s.handle # => I'm a singleton method!

As mentioned earlier, when a child class inherits or derives from a parent, it has access to the methods and properties of the parent class. Inheritance is accomplished with the < operator:

class Name

  attr_accessor :given_name, :family_name

end

class Address < Name
  attr_accessor :street, :city, :state, :country

end

a = Address.new
puts a.respond_to?(:given_name) # => true

If the class Name were in a different file, you'd just require that file first, and then the inheritance operation works.

The visibility or access of methods and constants may be set with the following methods:

Methods following the keywords private or protected will have the indicated visibility, until changed or until the definition ends:

class Names

  def initialize( given, family, nick, pet )
    @given = given
    @family = family
    @nick = nick
    @pet = pet
  end

# the methods are public by default

  def given
    @given
  end

  def family
    @family
  end

# all following methods private, until changed

  private

  def nick
    @nick
  end

# all following methods protected, until changed

  protected

  def pet
    @pet
  end

end

name = Names.new( "Klyde", "Kimball", "Abner", "Teddy
Bear" )

name.given # => "Klyde"
name.family # => "Kimball"

# see what happens when you call nick or pet

name.nick
name.pet

You can also call the methods after a definition (you must use symbols for method names):

def pet
  @pet
end

protected :pet

In addition to classes, Ruby also has modules. A module is like a class, but it cannot be instantiated like a class. A class can include a module so that when the class is instantiated, it gets the included module's methods and so forth. (The include method comes from the Module class: http://www.ruby-doc.org/core/classes/Module.html.) The methods from an included module become instance methods in the class that includes the module. This is called mixing in, and a module is referred to as a mixin. You can include more than one module (which is similar to multiple inheritance), but you can only inherit from one class (single inheritance). Because identifiers are overridden by the last definition of the identifier (e.g., for methods or constants), this scheme avoids name collision. A module is a form of a namespace in Ruby. A namespace is a set of names—such as method names—that have a scope or context. A Ruby class can also be considered a namespace.

A Ruby module associates a single name with a set of method and constant names. The module name can be used in classes or in other modules. Generally, the scope or context of such a namespace is the class or module where the namespace (module name) is included.

A module name must be a constant; that is, it must start with an uppercase letter. A module can contain methods, constants, other modules, and even classes. It can inherit from another module, but it may not inherit from a class. As a class may include a module, it may also include modules that have inherited other modules. Here's an example:

module Dice

  # virtual roll of a pair of dice
  def roll
    r_1 = rand(6); r_2 = rand(6)
    r1 = r_1>0?r_1:1; r2 = r_2>0?r_2:6
    total = r1+r2
    printf( "You rolled %d and %d (%d).\n", r1, r2, total )
    total
  end

end

class Game
 include Dice
end

g = Game.new
g.roll

If the module Dice and the class Game were in separate files, just require the file containing the module before including the module. The file containing the Dice module might look like this:

module Dice

  # virtual roll of a pair of dice
  def roll
    r_1 = rand(6); r_2 = rand(6)
    r1 = r_1>0?r_1:1; r2 = r_2>0?r_2:6
    total = r1+r2
    printf( "You rolled %d and %d (%d).\n", r1, r2, total )
    total
  end

end

And the file containing the Game class might look like this:

#!/usr/bin/env ruby

require 'dice'

class Game
 include Dice
end

g = Game.new
g.roll

When you define module methods like class methods—that is, prefixed with the module name (or with self)—you can call the method as shown here:

module Binary

# def self.to_bin( num )
  def Binary.to_bin( num )
    bin = sprintf("%08b", num)
  end

end

Binary.to_bin( 123 ) # => "01111011"