Learning Ruby Basics in < 9 minutes

Created on Jun 28, 2021

Russ Olsen

in his book Design Patterns in Ruby

makes it easy for beginners in the language to view an excellent intro about Ruby to help build better software programs.

In this article, I’m distilling the notes I wrote about chapter 2.

Check out chapter 1 here

Getting Started with Ruby

The easiest way to run Ruby language is to use the interactive Ruby shell, irb .

$ irb
irb(main):001:0> 2 + 2
=> 4
$ ruby hello.rb
hello world

where hello.rb is:

puts 'hello world'

As you can see, puts prints out values, and the function in Ruby can accept the parameter(s) without a parenthesis.

Also, in Ruby calculations can continue on the second line like in calc.rb file:

x = 1 +
    2 + 3
puts x

running the file:

$ ruby calc.rb

Take care if you continue the line before the desired statement ends like this:

x = 1
+ 2 + 3
puts x

it will give you 1. If you want to include adding 2 & 3, you should extend the first line with / :

x = 1 \
+ 2 + 3
puts x
Pounds = 2.2
FACTS = 'Life and Death'
6/3 # is 2
7/3 # is still 2
irb(main):012:0> 7777777777777777777.class
=> Integer
irb(main):013:0> 77.77777777777777777.class
=> Float
irb(main):014:0> 'str'.class
=> String

You can check the type of the object with instance_of method. You can check if it’s a nil or not by nil method. You can also convert the object to string with to_s method.

irb(main):023:0> 'hello'.instance_of? String
=> true
irb(main):021:0> 'hello'.nil?
=> false
irb(main):022:0> 44.to_s
=> "44"

Because everything in Ruby is an object, it is not correct to say that the expression x = 44 assigns the value 44 to the variable x. Instead, what is really happening is that x receives a reference to an object that happens to represent the number after 43.

nil || false # false
nil or false # false

as you might guess, || and or are the OR boolean operator while && and and are the AND operator. Also not and ! are the same for negation.

If you come from the world of C or C++, you will be shocked to learn that in Ruby, zero, being neither false nor nil , evaluates to true in a Boolean expression. Surprisingly, this expression:

if 0
    puts 'Zero is true'
    puts 'Zero is false'

will print out

Zero is true
unless weight < 100
    puts 'way too heavy'

A short form is also available:

puts 'way too heavy' unless weight < 100
array = ['first', 'second', 'third']
array.each do |element|
    puts element

instead of a for loop:

for element in array
    puts element
irb(main):001:0> name = 'Ezz'
=> "Ezz"
irb(main):002:0> name.length
=> 3
irb(main):003:0> name.upcase
=> "EZZ"
irb(main):004:0> name.downcase
=> "ezz"
irb(main):005:0> name[0] = 'Z'
=> "Z"
irb(main):006:0> name
=> "Zzz"
n = 42
puts "The value of n is #{n}."

which prints out:

The value of n is 42

Take care, you should the string, which contains a substitution, should be enclosed by double-quotes.

Symbols are more or less immutable strings and Ruby programmers use them as identifiers:


For example, you can’t edit str2 here:

str1 = 'Ezz'
str2 = :Ezz
str1[0] = 'Z'
# str2[0] = 'Z'
puts str1
puts str2
a = ['banana', 'apple', 'orange']
a << 'mango'
puts a # ['banana', 'apple', 'orange', 'mango']

You can sort or reverse the array. If you want to change the array in place (changes happen to the original array), add ! to the method.

a = ['banana', 'apple', 'orange']
a << 'mango'
puts "original array not sorted: #{a}"
puts "original array not reversed: #{a}"
puts "original array sorted: #{a}"
puts "original array reversed: #{a}"
h = {}
h['first_name'] = 'Abu Bakr'
h['last_name'] = 'El Seddiq'
puts h
h_new = {'first_name' => 'Abu Bakr', 'last_name' => 'El Seddiq'}
puts h_new

Symbols make good hash keys:

h_improved = {:first_name => 'Abu Bakr', :last_name => 'El Seddiq'}
puts h_improved
/old/ =~ 'this old house' # 5 - the index of 'old'
/new/ !~ 'this old house' # true - 'new' is not matching anything
/Russ|Russel/ =~ 'Fred' # nil - Fred is not Russ nor Russel
/.x*/ =~ 'any old string' # 0 - the RE will match anything


class BankAccount
    def initialize account_owner
        @owner = account_owner
        @balance = 0

    def deposit amount
        @balance = @balance + amount

    def withdraw amount
        @balance = @balance - amount
my_account = BankAccount.new('Ezz')
my_account = BankAccount.new('Ezz')
puts my_account.balance

it seems this code is not working and produces the following error:

BankAccount.rb:17:in `<main>': undefined method `balance' @owner="Ezz", @balance=0> (NoMethodError)

This is because the instance variable on a Ruby object can not be accessed outside the object. That’s why we define an accessor method:

def balance

If we add this to the BankAccount class and tried to get the balance, we will receive 0.

We might want to set a new balance, so we add a setter method:

def set_balance new_balance
    @balance = new_balance

If you tried to take it easy and ignore just setter method and wrote this:

my_account.balance = 100

it will output a NoMethodError . What you need to do instead of that and instead of the ugly setter method is:

def balance=(new_balance)
    @balance = new_balance

which we can use to set balance using:


and as always in Ruby, you can omit the parenthesis.

What we did above is a trick to make Ruby know that balance= is a method and it takes one argument. Yes, as you might realize, this equal sign is part of the method’s name that Ruby translates it into a plain old method call.

So now, the class looks good from the outside world. We have balance ; a method to get and balance= ; a method to set.

Boring, isn’t it?

Unsurprisingly, Ruby has a solution. As Ruby programmers use getter and setter methods a lot. Ruby supplies us with a great shortcut:

attr_accessor :balance

Now, this statement creates the value of the instance variable @balance to be able to get . It also creates the balance=(new_value) setter method.

What if you want to just have access to getting an instance variable not setting it? In this case, you can use attr_reader like so:

attr_reader :name

in this case, the name variable is read-only.

Similarly, for the setter method only, use attr_writer .

class SelfCentered
    def talk_about_me
        puts "Hello I am #{self}"

conceited = SelfCentered.new

but when you run that code, you’ll get something like this:

Hello I am #<SelfCentered:0x00005600a5ccfa78>

pointing to a hex address of the instance SelfCentered .

In this example, we will create a subclass of BankAccount :

class InterestingBearingAccount < BankAccount
    def initialize owner, rate
        @owner = owner
        @balance = 0
        @rate = rate

    def deposit_interest
        @balance += @rate * @balance

If you compare this with the superclass BankAccount , you’ll see duplicate information in the initialize method. We have the same owner and balance as in the BankAccount ’s initialize method:

def initialize account_owner
    @owner = account_owner
    @balance = 0

In this case, it’s better to avoid that messy code duplication and we should use super method like so:

def initialize owner, rate
    @rate = rate

When a method calls super , it’s saying, “Find the method with the same name as me in my superclass, and call that.”

So basically, what super is doing is that it calls the initialize method in the superclass BankAccount . If this method doesn’t exist in the first superclass, Ruby will continue in the root of inheritance until it finds that particular method.


def add_args name, car="BMW"
    puts "#{name} has #{car}"

add_args("Ezz", "Rolls Royce")

For the first return, it will say that I have BMW and the second return states that I got richer and have Rolls Royce.

def describe_langs name, *languages
    puts "#{name}"
    for lang in languages
        puts "learns: #{lang}"

describe_langs("Ezz", "Python", "MATLAB", "Javascript", "Rust")


module Chatty
    def say_hi
        puts "Hello, my name is #{name}"
        puts "My job title is #{title}"

class Employee
    include Chatty

    def name

    def title
        'Data Engineer'

employee = Employee.new
puts employee.say_hi

so you can’t do something like this:

employee = Chatty.new
puts employee.say_hi


    quotient = 1 / 0
rescue ZeroDivisionError
    puts "Division by zero"

If you want to raise the exception, you can use raise .

Importing source files

require 'account.rb'


require 'account'

This also applies to the standard files included with Ruby. For example, you can parse some URLs with URI class that comes with Ruby:

require 'uri'
ezz = URI.parse 'https://wwww.ezzeddinabdullah.com'
require 'rubygems'
require 'runt'

Final Thoughts

In this chapter, we’ve been on a quick tour of the Ruby language.

We’ve seen that everything in Ruby, from a string to a number to arrays, is an object. Here, the author wraps up Ruby for beginners so that you can use it to build better software programs implementing design patterns. Stay tuned because we’re about to start.

See you in chapter 3 notes!

Get Design Patterns in Ruby from Amazon!!

Design Patterns in Ruby by RussOlsen

Image by the Author


Get the next FREE ebook ‘Disciplined’ once released and more exclusive offers in your inbox

Published on medium