RORGURU.COM
 

Classes and Objects

 

As Ruby is a genuine object oriented language, Ruby has its classes and objects to make things happen for you. In this chapter we'll explore how to use Ruby is classes and objects to develop any Ruby application.

Creating a Class :

The name of a class should be short but should also reflect the functionality of the class. Being choosy with the name of the class will make your code more reflective in nature. The class name should be constructed using Camel case. The underscore is a big no-no for class names, because it is conventionally used for method names. In the Camel case naming convention, the name of a class name should be like MyFirstApplication which means that the camelized names should start with a capital letter and as a new word is appended after that should also be capitalized.

A sample class declaration is as follows:

class MyFirstApplication
end

This is a very simple class declaration. The first thing that should strike you here is the absence of curly braces or semicolons in the class declaration. This is a deliberate effort to make Ruby more dynamic. In fact, you'll never use semicolon in Ruby and there'll be very few places where curly braces are used.

Creating an object:

The new method is used to construct an object in Ruby. For example, to create an object of the Pet class, the syntax will be:

class Pet

def initialize(name)

@pet_name = name

end

def my_dog

"My dog's name is : #@pet_name"

end

end

my_pet = Pet.new("Max")

puts my_pet.my_dog

Output: My dog's name is : Max

Here we've created two methods, initialize and my_dog. The first method is a special method in Ruby. Whenever a new object is created, some space is created in the memory to hold the newly created object and then the initialize method is called, passing all the parameters that were passed to new.

Now here we have created a new object my_pet of the class Pet and the argument Max is sent to the initialize method. This initialize method stores the value in the @pet_name instance variable (we need the instance variable here to carry the value in different method calls). As we call the my_dog method of Pet class using the object my_pet, the method my_dog interpolates the value of the instance variable @pet_name and returns the value to puts method which will eventually give you the output.

Attributes of Ruby:

The object we've created in our earlier program has an internal state i.e. no other objects can access this objects instance variables. This is OK till a certain stage, but most of the times we want such methods that lets us alter the state of its objects. For doing this we have attributes in Ruby.

Ruby has three types of attributes:

  1. Readable attributes
  2. Writable attributes
  3. Readable/Writable attributes

Readable attributes: Just to read the state of the instance variables of a method we've attr_reader attribute, through which the objects can access the state of the instance variables. The sample code is as follows:

class Pet

attr_reader :pet_name

def initialize(name)

@pet_name = name

end

end

my_pet = Pet.new("Max")

puts "My dog's name is :" + my_pet.pet_name

Output: My dog's name is :Max


Writable attributes: If we also want to change the value of an object at runtime, we've attr_writer. The sample code is given below:

class Pet

attr_reader :pet_name

attr_writer :pet_name

def initialize(name)

@pet_name = name

end

my_pet = Pet.new("Max")

puts "My dog's name is :" + my_pet.pet_name

my_pet.pet_name = "Rocky"

puts "My other dog's name is :" + my_pet.pet_name

Output: My dog's name is :Max

My other dog's name is :Rocky

Readable/Writable attributes: Ruby provides us the attr_reader for making readable attributes while the attr_writer for writable attributes. There is also an attribute to make an attribute both readable and writable. attr_accessor will do the work for us i.e. if we use attr_accessor then we dont need to use attr_reader / attr_writer. Sample code is given below:

The best way to explain anything is through example, so here is your code for inheritance:

class Pet

def initialize(fname)

@fname = fname

end

def pet_fname

return @fname

end

end

class OtherPet<Pet

def initialize(fname,sname)

super(fname)

@sname = sname

end

def pet_sname

return @sname

end

end

my_pet = OtherPet.new("Max","Spike")

puts "My first dog's name is :" + my_pet.pet_fname

puts "My second dog's name is :" + my_pet.pet_sname

Output :My first dog's name is :Max

My second dog's name is :Spike

Clearly, from the code, we can see that there are two different classes; the first class(here parent class) is Pet and the other class is OtherPet (the child class). The child class is inheriting the properties from parent class. Thus when we try to print by using the object my_pet , we just need to access the methods like my_pet.pet_sname

Method visibility in Ruby:

Ruby has a different method visibility compared to other OO languages because in other OO languages, private methods can only be accessed within the scope of the current class, whereas the protected methods can only be within the scope of the defining class or any of its subclasses. Ruby has a different approach to this. The private and public methods in Ruby can be accessed from the instances of the classes and the subclasses. A very simple example is given below:

class User

def public_method(access)

def public_method(access)

end

private

def private_method(access)

"@access = access

end


protected

def protected_method(access)

@access = access

end

end

puts User.new.public_method("public")

puts User.new.private_method("private")

puts User.new.protected_method("protected")

Output : public

private method `private_method' called for # (NoMethodError)

Clearly, we can access the private methods from anywhere, but the public and private methods cant be accessed without the scope of the class.

Modules:

Till now you must be thinking that class is the basic building block of Ruby applications…not really. Ruby classes are just a type of module and you would be surprised to know that Class class is nothing but a subclass of class Module.

A module looks much like a class:

module MyPet

def sample

puts "Hello Tommy !!!"

end

end

So, that looks much like a class, so why should bother about a class. Wait…a module can never has its instances. That what looks module very useless…right? Actually, module is present in Ruby for some different purpose. Previously, we said that Ruby has a tricky way to manage multiple inheritance and module is the thing that Ruby provides us to make it happen. We can have only one parent class, but we can any number modules. So that is what we call mix in modules into classes. Here is your sample code for module:


module MyPet

def sample

puts "Hello Tommy !!!"

end

end


class Pet

include MyPet

end


Pet.new.sample

Output: Hello Tommy !!!


Class variable:

In Ruby, class variables are created by prefixing the variables with @@. We are already having our good old instance variables, so why bother about class variable? Actually, class variable is shared by all the instances of a class. This is unlike our instance variable where the instance variables state is internal to the object. The code is given below :


class Pet

@@name = "Max"

def self.name

@@name

end

end


class Dog < Pet

@@name = "Tommy"

end

puts Pet.name

puts Dog.name


Output: Tommy

Tommy

As you can see from the output, as we change the value of the class variable, all the instances of that variable has changed.

Class method :

Ruby provides a special type of method named as class method. The main advantage of class method is that you don't need to create an object of these methods to use them. The sample code given below:


class Pet

ddef self.name

"Tommy"

end

end

puts Pet.name

Output : Tommy

As you can see, we haven't created any instance of name method.