Last updated on July 28th, 2024 at 05:44 pm
Table of Contents
- Defining a Class
- Extending Existing Classes
- Class Initializers
- Instantiating the class
- Class Variables
- Using super
- What methods can my object access?
- Helper Classes
- Aborting Program Execution
Because Ruby treats everything as an object and objects are derived from classes, it makes sense that one of the first things you should know is how to create your own classes.
Defining a Class
For the purpose of clarity, it is always suggested that a class be named in a manner that suggests its purpose and the name be in CamelCase. Declaring a class is quite simple:
class ExampleClass
end
As with all other object oriented languages, Ruby classes can inherit from other classes.
class ExampleClass < InheritedClass
end
While Ruby does not have the ability to inherit from multiple classes, known as multiple inheritance, a class can include modules through what is called “MIXIN” functionality.
class ExampleClass < InheritedClass
Include MathFunctions
Include Persistence
end
What’s the difference between classes and modules? Classes can be defined repeatedly and expanded upon, whereas a module can only be defined once. As well, a module cannot be instantiated, whereas a class must be instantiated to be used. As well, you cannot inherit from one module to another. Instead, you would need to include the desired module into your new module.
If you ever want to know what a class is derived from, you can use the ancestors
method.
Extending Existing Classes
One of the more dangerous aspects of Ruby is that you can easily extend any class. Why is this dangerous? It allows you to overwrite methods that are already defined and it won’t tell you when this happens.
Extending a class is as simple as declaring the class without inheritance.
class MyClass
def method_one
puts "Method one"
end
def overwrite_me
puts "You shouldn't see me"
end
end
class MyClass
def method_two
puts "Method two"
end
def overwrite_me
puts "You should see me"
end
end
xx = MyClass.new
xx.method_one # Output: Method one
xx.overwrite_me # Output: You should see me
Class Initializers
It is very common in object oriented programming languages that a class has a default method that is executed when the class is instantiated. This is accomplished by having a method by the name initialize
, which can take parameters if required.
class ExampleClass
def initialize(param1, param2)
# Initialization code
end
end
Unlike some other object oriented programming languages which allow for overloading the initializer, Ruby only allows a single initialization method.
Instantiating the class
To use a class, it must be instantiated. This is done with the new
method.
instantiatedObject = ExampleClass.new
If the class has an initializer that requires parameters, simply provide those values when the object is instantiated.
instantiatedObject = ExampleClass.new(firstParameter, secondParameter)
Class Variables
Earlier in this guide we covered the topic of class variables. Here, we will expand on the topic a bit.
A class variable can be defined in any class method and will be specific to an object for the life of the object. Normally, a class variable will not exist until it is used. It is possible, however, to define class variables in a static manner and also to provide getter and setter routines for those variables.
In Ruby the class variable is called an attribute
. There are four methods that are used for defining attributes – attr
, attr_reader
, attr_writer
, and attr_accessor
.
Both the attr
and attr_reader
methods create an instance variable and a getter method for each attribute name passed as argument. An argument can be a Symbol
or a String
that will be converted to Symbol
class ExampleClass
attr: :attr1, 'attr2'
attr_reader: 'attr3' :attr4
end
This is the equivalent of making the variable read-only outside of the class. You can modify the variable as a class variable in any of your class methods, but the variable can only be read from class instances.
The attr_writer
method creates a setter method for the variable, but not a getter method.
attr_writer: :write_only_class_variable
The attr_accessor
method will create both getters and setters for each variable defined.
attr_accessor: :attr1
Using super
Every Class you define will have an inheritance chain that you can see with the ancestors
method. You can extend an ancestor’s methods by redefining them and then using super to call them from within the new methods.
class MyFirstClass
def words_of_wisdom
puts "Words from super class"
end
end
class MyNextClass < MyFirstClass
def words_of_wisdom
puts "words from my class"
super
end
end
MyNextClass.new.words_of_wisdom
What methods can my object access?
Sometimes it is helpful to get a list of which methods an object will respond to. This can be determined by applying the method methods
to the object. As you can see in the screen shot below, the output isn’t terribly readable.
You can quickly see that any class you define will automatically inherit methods that are common to all classes .
Additionally, on rare occasions it is helpful to know if an object has a given method. This can be determined with the respond_to?
method.
As well, sometimes you might want to know the class name of a given object, which can easily be determined with the methods “class.name”. You if you leave the method name
off, class will respond with the class of the object, as an object itself.
Helper Classes
It is not uncommon that you will run into situations where a method can and should be shared amongst more than one class. Ruby uses Helper Classes to house these methods. Have a quick look at this page on Ruby Guides for a little more detail.
Aborting Program Execution
Typically, you will want a program to execute to completion. However, there are instances where you will want to exit the program early. The statements available to you for this are raise
, exit
, exit!
, abort
and fail
.
The raise
statement is used to create an exception, which I will cover in greater detail in the Exception Handling section of this guide. At this point it suffices to say that the raise
statement will terminate the application and can be issued alone on a line, or it can be issued with arguments, these being the error that is being raised, a text message that explains the exception being raised and the caller. If you raise without any arguments, it will create a RuntimeError exception.
The exit
statement is actually an alias for the raise
statement and raises the exception SystemExit. Just prior to termination, Ruby executes any at_exit
methods and runs any object finalizers.
The exit!
statement will exit the application immediately and not run any exit handlers. If you provide it a parameter it will be passed on to the underlying system as the exit status.
The abort
statement will terminate execution immediately and, if provided a message, this message will be written to STDERR prior to terminating.
The fail
statement is an alias for raise
.