Introduction / History
Ruby is a “dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.” created by Matz.
Why Ruby ?
For me the first reason to learn Ruby was that it is, in fact, a beautiful programming language. It is really natural to code it and always express my thoughts.
The second main reason was Rails. The well known framework that Twitter, Basecamp, Airbnb, Github, and so many companies use.
How do I run a Ruby file?
It’s easy — just create a file with the extension . rb , navigate to that file’s directory from the command line, and run it using $ ruby filename. rb (the dollar sign is just the command prompt). You’ll be able to gets from and puts to the command line now!
Requiring Scripts or Gems in IRB
If you want to include a gem file (a library of methods, for instance) or another Ruby script in your IRB session, use
require will search for any gems you've downloaded from the internet. If you've explicitly provided a path to be required, for instance
./my_script.rb, it will bring in that specific file instead.
Once it’s been required, you can run methods and access variables from that file in IRB.
Load vs Require
There’s another method
load which is almost identical to
require but allows a file to be loaded multiple times.
This can be handy in IRB if you’re developing a script and want to make changes to it before reloading again without having to completely quit out of IRB.
require only allows you to load the file once and will not work if you try to do it again:
load is handy when you're playing around with command line scripts because it saves you from quitting IRB to refresh your changes, you should stick with
require if you use this functionality in your own scripts. That's because
require makes sure you've only loaded the file once while, with
load you might have accidental double-or-triple loads if multiple files require each other.
In Ruby, we have
- data types (integers, booleans (true / false), strings, symbols, float and so many other data types).
- arrays (integer number as indices)
- hash: key-value data structure
- while, for and each iterator. each iterator for both arrays and hash
You are maybe asking what is the difference of “each” iterator and so well known “for” looping. The main difference is that “each” iterator maintain the variable only inside of scope. “for” looping keeps the variable live outside the block. Let’s do a test:
The variable “num” in the “for” looping will keep alive after iteration block. “num” variable from “each” iterator block will not.
one = 1
my_name = "anil kumar"
male = true
my_integers = [1, 2, 3, 4, 5]
Arrays has a concept called index. The first element gets the index 0 (zero). The second gets 1, and so on. You got the idea!
The most common methods to add a new value to an Array is push and <<.
bookshelf = 
bookshelf.push(“The Effective Engineer”)
bookshelf << "Lean Startup"
You may ask “But it doesn’t use the dot notation as other methods. How it could be a method as well?” Wow, nice question! :)
bookshelf << "Hooked"
..is similar to writing this:
Hash: Key-Value Data Structure | Dictionary Collection
Classes & Objects
let’s understand Ruby syntax for classes:
And objects are instances of a class. We create an instance by calling .newmethod.
vehicle = Vehicle.new
Now, vehicle is an object (or instance) of the class Vehicle.
Remember that our Vehicle class has 4 attributes: Number of wheels, type of tank, seating capacity and maximum velocity. We set all this attributeswhen creating a vehicle object. So here we define our class to receive data when instantiates it.
We use the initialize method. We call it a constructor method. So when create the vehicle object, we can define this attributes, as below:
tesla_model_s = Vehicle.new(4, 'electric', 5, 250)tesla_model_s
# => <Vehicle:0x0055d516903a08 @number_of_wheels=4, @type_of_tank="electric", @seating_capacity=5, @maximum_velocity=250>
All attributes set. But how can we access this attributes values? We send a message to the object asking about them. We call it a method. It’s the object’s behavior. Let’s implement it!
This is an implementation of two methods: number_of_wheels and set_number_of_wheels. We call it getter & setter. Because the first get the attribute value, and the second set a new value for the attribute.
In Ruby, we can do that without this methods. It is the attr_reader, attr_writer and attr_accessor. Let’s see it with code!
- attr_reader: implements the getter method
- attr_writer: implements the setter method
- attr_accessor: implements both methods
So for now we learnt how to get attributes values, implement getter and setter methods & use attr (reader, writer and accessor).
But we can also use methods to other things like “make_noise” method. Let’s see it!
When we call this method, it just returns a string “VRRRRUUUUM”.
Encapsulation: hiding information
Encapsulation is used as a mechanism to restrict direct access to objects’ data and methods. But the same time it facilitates operation on that data (objects’ methods).
Encapsulation can be used to hide data members and members function.Under this definition, encapsulation means that the internal representation of an object is generally hidden from view outside of the object’s definition. — Wikipedia
So all internal representation of an object is hidden from the outside, only the object can interact with its internal data.
In Ruby we use methods to direct access data. Let’s see an example:
We just implemented this
Person class. And as we know to create the object person, we use the new method and pass the parameters.
tk = Person.new("Leandro Tk", 24)
So I created me! :) The tk object! Passing my name and my age. But how can I access this information? My first attempt is to call name or age method.
We can’t do it! We didn’t implement the name (and the age) method. Remember when I said that “In Ruby we use methods to direct access data”? To access the tk name and age we need to implement those methods on our Person class.
Now we can direct access this information. With encapsulation we can ensure that the object (tk in this case) is the only responsible to access the data (name and age). The internal representation of the object is hidden from the outside.
Inheritance: behaviors and characteristics
In object oriented programming, classes can inherit common characteristics (data) and behavior (methods) from another class.
Let’s see another example and implement it in Ruby!
Imagine a car. Number of wheels, seating capacity and maximum velocity are all attributes of a car. We can say that an ElectricCar class inherits these same attributes from Car class.
Our Car class implemented! :)
Instantiated and we can use all methods created! Nice!
In Ruby, we use the < operator to a class inherits from another. An ElectricCar class can inherits from our Car class.
Simple as that! We don’t need to implement the initialize method and any other method, because this class already has it (inherited from Car class). Let’s prove it!
- A module is a collection of methods, variables and constants stored in a container.
- It’s similar to a class but it cannot be instantiated.
- A module is defined by
module ... end.
- A module can have no instances.
- A module can have no subclasses.
Define a Module
In Ruby, the
module keyword allows you to define a new module
Greeting -> This is
hello -> this is a
Modules have 2 main purposes:
- providing a namespace and prevent name clashes
- using the mixin facility for composition
Module as namespace
Namespacing is a way of bundling logically related objects together.
Modules serve as a convenient tool for this. This allows classes or modules with conflicting names to co-exist while avoiding collisions.
A good example of namespacing is the
This module contains a bunch of classes and modules — For example, the
Here we can see that the
Application class is defined within the scope of the
Note that to access this class from outside of the module
Rails, we use the
Application class is a pretty common class name that we could encounter in another gem then — and in order to avoid clashing — the
Application class is encapsulated in the
This means that the
Rails::Application class will never clash with an
Application class or a
Dummy::Application class that can be defined anywhere else.
Composition with the mixin facility
Ruby doesn’t handle multiple inheritance.
So how to organise a class to keep it maintainable in long term ?
The answer is by applying the Composition over Inheritance principle.
The Composition principle is based on the fact that a class should contain a set of objects that provide the desired functionality.
So instead of passing the functionality using the inheritance chain, it’s preferable to compose a class of objects that are responsible of providing the desired functionality.
Actually, Ruby facilitates the use of composition by using the mixin facility.
Indeed, a module can be included in another module or class by using the
For more read at @ https://medium.com/rubycademy/modules-in-ruby-part-i-a2cdfaccdb6e
An example of Ruby module is Math module. We can access the constant PI:
Math::PI # > 3.141592653589793
And .sqrt method:
Math.sqrt(9) # 3.0