Ruby is one of the easiest languages to grasp the concept of OOP (object orientated programming). In particular the power that of PORO’s (plain old Ruby objects).
Let's go through a short example using a little robot 🤖
Goal specifications
We want to robot to be able to do the following:
- Move around 🏃♂️
- Return home 🏠
- Change colour 🔴🟡🔵
- Receive a toy 🧸
To define a class in Ruby it’s quite simple, let’s start.
# Initializing a class
class Robot
def initialize(north, south, east, west, colour)
@north = north
@south = south
@east = east
@west = west
@colour = colour
end
end
The initializer method is responsible for handling creating new instances of our class. In this method we define what attributes we want our class to have, this can be anything!
Using our class
Now I suggest if you're following along, running a ruby console (assuming you have installed ruby on your machine). To create and play around with our robot.
To create an instance of a class, and assign it to a local variable
robot = Robot.new
As simple as that!
Now we have access to our robot, but we cannot do anything with it. This is where attribute accessors come into play.
You should read more in depth on this. The principle of attribute accessors is that, they give us write and read permissions on our classes instance objects.
# How to access attributes of a class
class Robot
attr_accessor :north, :south, :east, :west, :colour
def initialize(north, south, east, west, colour)
@north = north
@south = south
@east = east
@west = west
@colour = colour
end
end
Now if we call our class in irb, we can move our robot by going.
robot = Robot.new(0,0,0,0)
PLEASE NOTE: At this point, if we do not assign a value to these attributes, you will get an error. We will cover how to change this later.
Class methods and Instance methods
There are two fundamental types on methods you can use on classes in ruby. Class methods, which are called only on the class, and instance methods, called only on an instance of the class.
Here is a good article with some more detail.
https://dev.to/adamlombard/ruby-class-methods-vs-instance-methods-4aje
Now, we can update our class with what we have learnt.
class Robot
attr_accessor :north, :south, :east, :west, :colour
def initialize(north = 0, south = 0, east = 0, west = 0, colour = "red")
@north = north
@south = south
@east = east
@west = west
@colour = colour
end
# Class method, only called on the class
def self.instructions
'Hello, I am a Robot, I can move in any direction, and I have a colour!'
end
# Instance method only called on an instance of the class
def print_coordinates
"Hello I am Robot, I am north #{north}, south #{south}, east #{east}, west #{west}"
end
end
Notice as well I have added placeholder values in the class initializer method. This means we can safely call our class with no values.
Next let's write some methods to make our robot move around, by updating its attributes.
class Robot
attr_accessor :north, :south, :east, :west, :colour
def initialize(north = 0, south = 0, east = 0, west = 0, colour = "red")
@north = north
@south = south
@east = east
@west = west
@colour = colour
end
# Class method, only called on the class
def self.instructions
'Hello, I am a Robot, I can move in any direction, and I have a colour!'
end
# Instance method only called on an instance of the class
def print_coordinates
"Hello I am Robot, I am north #{north}, south #{south}, east #{east}, west #{west}"
end
# Updating an attribute on the class
def move_north(distance)
self.north = north + distance
end
def move_south(distance)
self.south = south + distance
end
def move_east(distance)
self.east = east + distance
end
def move_west(distance)
self.west = west + distance
end
end
Notice how I call self
on each method. This is because on these instance methods, we want to assign new data to the instance of the class, therefore itself. I suggest reading this for more explanation.
Using Constants
One very handy tool in ruby is the use of constants. I'd explain constants as key bits of data we want to store in memory, that relate to our class. For instance, they are commonly used in Models for important business logic. This data should not change once defined.
Below I have added some constants for our robots colour. Followed up by a method that uses an array of these constants.
# Using constants
class Robot
attr_accessor :north, :south, :east, :west, :colour
# Declaring constants
RED = 'red'.freeze
BLUE = 'blue'.freeze
YELLOW = 'yellow'.freeze
GREEN = 'green'.freeze
# Declaring an array of constants
COLOURS = [
RED,
BLUE,
YELLOW,
GREEN
].freeze
def initialize(north = 0, south = 0, east = 0, west = 0, colour = RED)
@north = north
@south = south
@east = east
@west = west
@colour = colour
end
# Class method, only called on the class
def self.instructions
'Hello, I am a Robot, I can move in any direction, and I have a colour!'
end
# Instance method only called on an instance of the class
def print_coordinates
"Hello I am Robot, I am north #{north}, south #{south}, east #{east}, west #{west}"
end
# Updating an attribute on the class
def move_north(distance)
self.north = north + distance
end
def move_south(distance)
self.south = south + distance
end
def move_east(distance)
self.east = east + distance
end
def move_west(distance)
self.west = west + distance
end
# Select a random colour
def change_colour
self.colour = Robot::COLOURS.sample
end
# reset the co-ordinates
def bring_home
self.north = 0
self.south = 0
self.east = 0
self.west = 0
end
end
Look at how our class has grown! Now think of the power we have learnt (evil laugh).
Let's have fun with our instance methods:
robot = Robot.new
robot.move_north(3)
robot.change_colour
robot.bring_home
We have now achieved so much from the spec!
But wait, there's more we can do, and we haven't fulfilled the spec. We need to give our robot a toy, the little fella earnt it, don't you think?
Not only can we pass numbers and strings into our classes, we can also pass... dun dun dun, other classes!
Let's create a toy class. A simple class with a name attribute.
class Toy
attr_accessor :name
def initialize(name = 'skateboard')
@name = name
end
end
Now, if we pass in another attribute parameter to our robot, as well as define another attribute accessor. We can have full access of the toy within an instance of our robot class.
# Passing in a class instance object to another class
class Robot
attr_accessor :north, :south, :east, :west, :colour, :toy
# Declaring constants
RED = 'red'.freeze
BLUE = 'blue'.freeze
YELLOW = 'yellow'.freeze
GREEN = 'green'.freeze
# Declaring an array of constants
COLOURS = [
RED,
BLUE,
YELLOW,
GREEN
].freeze
def initialize(north = 0, south = 0, east = 0, west = 0, colour = RED, toy)
@north = north
@south = south
@east = east
@west = west
@colour = colour
@toy = toy
end
# Class method, only called on the class
def self.instructions
'Hello, I am a Robot, I can move in any direction, and I have a colour!'
end
# Instance method only called on an instance of the class
def print_coordinates
"Hello I am Robot, I am north #{north}, south #{south}, east #{east}, west #{west}"
end
# Updating an attribute on the class
def move_north(distance)
self.north = north + distance
end
def move_south(distance)
self.south = south + distance
end
def move_east(distance)
self.east = east + distance
end
def move_west(distance)
self.west = west + distance
end
# Select a random colour
def change_colour
self.colour = Robot::COLOURS.sample
end
# reset the co-ordinates
def bring_home
self.north = 0
self.south = 0
self.east = 0
self.west = 0
end
end
Now if you were to call toy = Toy.new
and robot = Robot.new(toy)
, you can successfully met the spec, congratulations!
Conclusion
As you can see creating our own classes in ruby is not only fun, but extremely powerful. If you harness the power of classes in your rails applications, you can create very modular, DRY, and sexy looking code. 😘
I encourage you on your ruby journey, to jump on in a console and have fun! I find it's the best way to learn. Thanks for reading, you're a 💎
Top comments (4)
Hi Max,
Congrats for writing an article about Ruby Classes. We need for sure more fresh content like this one in Ruby world so that people that want to learn Ruby can be inspired.
Thank you for contributing to Ruby community and hope I can read more articles from you.
Hope you don't mind a suggestion: you can have better syntax highlighting if you specify the language when writing code samples.
For example for Ruby if you type
ruby
after the code markdown it will highlight the Ruby syntax:Writing this:
will generate this preview:
Notice I wrote
ruby
immediately after the three backticks.More details about how to do syntax highlighting in the markdown used by Dev.to can be found here
I was not sure how to contact you privately to write this suggestion so please feel free to delete this comment as it is off-topic.
Thanks so much for reaching out Lucian, I didn’t think anyone would even read it! Means a lot ❤️
Thanks as well for pointing out the syntax highlighting! I’ve been looking around for how to do that 💎
Awesome
Came across this while diving in the ruby world.
Thanks buddy 😘
Thanks so much 🙏! Hope your enjoying the world on Ruby 💎