TheDeveloperBlog.com


Ruby Class Examples: Self, Super and Module

Classes abound in Ruby. Even primitive types such as numbers are classes. But we can create still more classes. These are conceptual units, building blocks.


With classes, we construct complex models. Classes in Ruby have constructors: this is the initialize method. We invoke "initialize" with new() calls.


First example. Here we use a custom class called Box. We add a constructor to this class. In Ruby, the constructor is called initialize(). The one here receives two arguments.

Initialize: In this method, assign two fields (@width and @height) to the arguments. Fields use a leading @ character.

New: When we call new, the initialize method is run. The arguments are stored in the memory of the class fields.

Info: We call the constructor by using the class name (Box) and the new method. Box.new returns a new instance of the Box class.

Based on:

Ruby 2

Ruby program that uses class

class Box
    # The constructor.
    def initialize(width, height)
	# Assign fields from arguments.
	@width = width
	@height = height
    end

    # A custom method.
    def display()
	puts @width
	puts @height
    end
end

# Create a new Box.
x = Box.new(10, 5)

# Call the display method.
puts x.display()

Output

10
5

Get, set. Classes use getters and setters to control access to their fields. This improves program design. It makes classes more separated from external code that uses them.

And: If the internals change, we can modify just get and set. When fewer code changes are made, fewer things are likely to break.

Getter: A custom syntax exists for getters and setters. In a getter, we have no arguments and a single statement—the return value.

Setter: In a setter, we use the equals sign at the end of the name. Then in the body, we assign the targeted field.

Ruby program that uses getter, setter

class Box
    # Getter.
    def size
	@size
    end

    # Setter.
    def size=(number)
	@size = number
    end
end

# Create a new Box.
x = Box.new()

# Use setter.
x.size = 10

# Use getter and display.
puts x.size

Output

10

To_s. Each class can have a to_s method defined. This method should return a string that contains the class data. We can specify a string, and this is automatically returned as the result.

String

Here: We specify the to_s method on the Box class. The @width and @height fields are inserted into the string.

Info: When a class is passed to a method like puts, the to_s method is automatically invoked. This all happens implicitly.

Tip: We have no need to call to_s in many program contexts. But to_s can be directly called.

Ruby program that defines to_s

class Box
    def initialize(width, height)
	# Initialize the class.
	@width = width
	@height = height
    end

    def to_s
	# Return this string.
	"Box, width: #@width, height: #@height"
    end
end

# Create new Box.
b = Box.new(10, 20)

# Display it (calls to_s).
puts b

Output

Box, width: 10, height: 20

Inheritance. One class can inherit from another. The derived class, a subclass, gains the abilities (like methods) from the parent class. The "less than" operator indicates a subclass.

Super: With a call to super() we invoke a same-named method from the class' parent. So from Square's super() we invoke Shape display().

Ruby program that uses inheritance, super

class Shape
    def display()
	puts("Shape display")
    end
end

# This class inherits from Shape.
class Square < Shape
    def display()
	puts("Square display")
	# Call superclass method of the same name.
	super()
    end
end

# Create the class.
item = Square.new()
item.display()

Output

Square display
Shape display

Self. The self object is available in all classes. It refers to the immediate class instance. We can access methods with self, or pass self to an external method.

Here: We call test() and pass it the self instance. The self variable evaluates to an object.

This: The self instance is the same thing as a "this" instance in other languages like C# or Java.

Ruby program that uses self

def test(s)
    # See if the Shape's color is red.
    puts(s.color == "red")
end

class Shape
    def initialize(color)
	@color = color
    end

    def color
	@color
    end

    def analyze()
	# Pass this object to another method.
	test(self)
    end
end

# Create Shape and call the analyze method.
s = Shape.new("red")
s.analyze()

Output

true

Public, private. Methods can be modified with visibilities. Public things can be called from external locations, outside of the class. Something private is only used inside the class.

Protected: This is a hybrid of public and private—it means public only to subclasses, private to everything else.

Ruby program that uses public, private

class Navigator
    def initialize(location)
	@location = location
    end

    def location()
	update()
	@location
	puts @location
    end

    def update()
	@location = @location.upcase()
    end

    public :location
    private :update
end

# Create new class instance and call location public method.
n = Navigator.new("japan")
n.location()

Output

JAPAN

Private method error. Let us get into some mischief. Here we try to call a private method, update() from the same class as above. We get a NoMethodError. And the program terminates.

Example that calls private method: Ruby

n = Navigator.new("japan")
n.update()

Output

/Users/sam/Documents/test.rb:24:in '<main>':
private method 'update' called for #<Navigator:0x007fa3cb082200
@location="japan"> (NoMethodError)

Module. This is an organization unit, much like a namespace in other languages. We use modules to organize classes and methods. To use a module in our file, we use the "include" keyword.

Reopen: Modules can be reopened and changed many times. We can modify them. We just specify the module another time to make changes.

Syntax: We can access a method or type (like a class) within a module with two ":" characters. We access "Cat::meow" as an example.

Ruby that uses module, include

module Cat
    def pet()
	puts "Cat petted"
    end
end

# Reopen and change the module (use mix-in).
module Cat
    def meow()
	puts "Cat meows"
    end
end

# Include the module and call its methods.
include Cat

Cat::pet()
Cat::meow()

Output

Cat petted
Cat meows

Built around classes, Ruby has robust support for object-oriented programming. Classes encapsulate functionality and data. They reside in memory.


Classes, by hiding information, tame the dragon of complexity. Understanding OOP is important when considering advanced program design. And it helps to know when OOP is not needed.

OOP