

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:
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.
