We are going to start with variables. Variable is
a storage location with an associated name. For example
x = 10
means that we allocated some memory, put something in it (in our
case we put number 10 inside), and called it `X`, to make it
easier to use this object in the future.
Different programming languages have different variable types (e.g.,
string, number, arrays, etc.). Some languages want you to
specify variable's type (e.g.
string x = "Hello"
),
and some don't.
Since Ruby is a dynamic language, you can change variable's type later. It can be a number in the beginning, and in the future, it can become a string. Here is an entirely correct code:
x = 10
x = "Now I'm a string!"
Let's start programming. Ruby has an interactive shell that allows us to
execute commands on it. It is an excellent tool for learning and testing.
Just open your terminal, and type irb
:
Ruby knows how to do primary arithmetic operations. Try to do some
simple operations. Each command will return a value, which will
be printed below your command. Try them in
irb
:
1 + 100
100 / 20
(5 + 6) - 1 + (4515 / 5)
"String 1" + "String 2"
"A" + "B" + "2"
"A" + "B" + 2
The last command has returned an error - it says it could not figure out how to add a number to a string. Before doing something like this, you need to be sure that command is logically correct. Otherwise, it will return an error, or will crash an app.
So why did
"A" + "B" + "2"
work, and
"A" + "B" + 2
did not? The difference between both expressions is that the first one has
quotes around number 2, which means that it is not a number,
but a string. You can add string to the string,
but Ruby does not know how to add a number to a string. To make
it work, you will need to convert a number into a string.
We will come back to it later.
So, let's make our first variable. To make a variable, give it a name first, then add `=` sign, and tell Ruby what to you want to assign to your new variable. Variable names can contain alphabet letters, numbers, and symbols like - or _. Variable names can't start with a digit, though. Let's make three variables that will represent John's age, Ann's age, and Steve's age. John is 28, Ann is 26, and Steve is 31. How would you calculate their average age with Ruby?
john_age = 28
ann_age = 26
steve_age = 31
average_age = (john_age + ann_age + steve_age) / 3
Ruby thinks the average age is 28, that is correct if we want to get a rounded, or integer value. However, the real average is slightly higher. So, where is the problem? We were using all integers, and Ruby decided that result should also be an integer. But what if we want to have an exact answer, with decimals? Let's make one value in our expression a decimal value. In this case, Ruby returns a correct value:
average_age = (john_age + ann_age + steve_age) / 3.0
There are Booleans, Symbols, Numbers, Strings, Arrays and Hashes in Ruby.
The boolean data type is very straightforward. Boolean variables can be `true` or `false`. We will use it a lot with conditional statements, for example:
john_likes_pizza = true
if john_likes_pizza
# some code to get a pizza
else
# some code to get a burger
end
Boolean is also used as a result of some expressions, like
# one equals one:
1 == 1
# five less than six:
5 < 6
# five less or equals six:
5 >= 6
(in this example, == can be read as "is equal". Single `=` is used to assign value to a variable, and double `=` sign is used to compare variables).
Strings are sets of characters. To create a string, you can use single
quotes '
, or double quotes "
:
name = "John"
name = 'John'
The difference is that double-quoted strings can be interpolated, which means that you can put a variable inside, and it will be converted to its value. Make sure to use #{} for your variable - this expression will tell Ruby that variable has to be interpolated. For example:
name = "John"
"Hi, my name is #{name}"
'Hi, my name is #{name}'
'Hi, my name is ' + name
As you can see, Ruby successfuly converted a variable name to its value in a first example, with double quotes. The second example did not change our string; it just returned whatever we entered. The third example shows that strings can be added to each other, just like numbers - this action called concatenation.
You can also multiply strings:
"Hey! " * 3
Sometimes you may need to get a substring of a string. For example, we have a string "ABCDEFG", and we need to get "ABC" substring:
str = "ABCDEFG"
This is pretty easy in Ruby. To get a substring, we need
to specify a range of characters inside the main string.
To do it, you also need to know that all indexes start from 0 in Ruby.
It means that first character has index 0, second - 1, and so on.
To get the first character, we would use:
first_character = str[0]
# => "A"
To get first three characters, we would use:
abc = str[0..2]
# => "ABC"
We can also use negative indexes: index of a last element would be -1,
element before it would be -2, etc:
new_str = str[3..-2]
# => "DEF"
You can always find all available info about Strings on ruby-doc. For example, how to reverse your string, or to make all characters capitalized, how to search for a substrings index and much more.
Symbols may look like a string, but they are different. To create
a symbol, you need to use :
instead of quotes. For example:
order_status = :new
Second, you can't change or update symbols. They can't be added
to each other, subtracted, multiplied or divided. Usually we use
symbols to represent some kind of state:
order_status = :new
order_status = :active
order_status = :shipped
Interesting thing about symbols: same symbols, even if they are assigned to different variables, will be a same object. It means that unlike strings, all same symbols are one exact object, and all variables that use it actually point to one location in memory. You can use `object_id` method to check it:
str = "String!"
sym = :symb
str2 = "String!"
sym2 = :symb
str.object_id == str2.object_id
sym.object_id == sym2.object_id
Please also visit ruby-doc for more info on Symbols.
There are different Number types in Ruby:
All numbers can be positive or negative, and you can do all kind of arithmetic operations with them, such as subtractions, multiplications, etc.
You can convert integers to floats and vice-versa with `to_i` or `to_f` methods. For example:
0.95.to_i
5.to_f
More info on integers (Fixnum class) and floats can be found in docs.
Rational numbers represent exact numbers, without rounding errors, for
example, 3/4, 15/124, etc.
You can also think of rational numbers as a fraction of two integers:
a/b
, where
b
can't be zero. To create a rational number,
we can use `to_r`
method.
1.to_r
0.23.to_r
0.25.to_r
You can always find more info on rational numbers in docs.
Arrays are collections of objects. You can add whatever you want to it: strings, numbers, other arrays, hashes, etc. To create an array, following syntax:
my_array = [ 1, "two", 3.0, [ 4, 5 ] ]
To access an object in the array, you need to specify object's index in the
array
in square brackets. Remember that indexes start from zero, so
if you want to get the first element, use
my_array[0]
,
to get third -
my_array[2]
.
You can also use indexes to get objects from the end
of the array. Th last object has index -1, object before it has an index -2, and so on.
If we want to create a new variable with value of the last object
in our array, we will use next:
last_object = my_array[-1]
There are also lots of useful methods to find an object in an array by its value, get an index of some object with given value, etc. Try to play with next commands:
# find object in array that is less than three:
my_array.find { |obj| obj.to_i < 3 }
# get index of object "two":
my_array.index("two")
# check if array includes object 3.0:
my_array.include? 3.0
# add new object to the end of array:
my_array.push :new
# get number of objects in array:
my_array.count
# get array with reverse objects positions:
my_array.reverse
You can always find more info on arrays by visiting ruby-doc.
Hashes are collections of objects, just like Arrays. But they are dictionary-like collections. It means we will use a key instead of an index to access some element inside of it. The key can be a string, symbol or a number.
To create a new hash, you will need to use another type of brackets -
{}
.
To assign a value to a key, you will need to use
=>
.
If you use Symbol as a key, you can just transform it from
:key
to
key:
,
and Ruby will understand that this is a Symbol used as a key.
Let's create our first hash:
hash = { "first" => 1, second: 2, 3 => "third" }
As with arrays or strings, to get an element inside of a hash,
just use square brackets, and specify a key. For example:
hash[:second]
.
Same with assigning new values for existing or new keys:
hash[:fourth] = "4"
hash["first"] = [ 1, 2, 3 ]
As usual, more info on Hashes can be found ruby-doc.org
All Ruby objects have lots of important methods that will help you to work with different data types.
As you already know, all data types are different - they have different properties, different purposes, some actions that you can apply to one data type can't be applied to another one, etc.
This adds some layer of complexity: you need to be sure that variable has the exact data type as you expect. For example, you can add some characters to the String, but you can't add them to Symbol.
Sometimes you may not be sure if a variable has the expected data type. For example, you send request to a web server, and you expect it to return Weather forecast for today, that would look like a Hash:
forecast = { min: 10, max: 13, wind: 4 }
But instead, it responded with an error:
forecast = { error: "Wrong Date" }
Inside of the code, you can't see whether the response is correct or not. You will need to check whether variable looks like you expect; for example, check if it has the proper class, the correct number of values, and more.
First, we could check if response is actually a Hash. Every Ruby object
has very helpful methods
is_a?()
and
class
:
response.class
# => Hash
response.is_a?(Hash)
# => true
It helped us to confirm that response in both cases is a Hash, that is good. We can continue our investigation. Now we could check whether some key inside a Hash exists. There is a Nil Object in Ruby. It represents emptiness - if some variable equals nil, it means that variable has no real value. So before using our forecast data, we need to check whether it exists. We can do it in many ways:
response[:min].is_a?(Number)
response[:min].nil?
response.has_key?(:min)
Some of these actions can be applied to Hash only, and if your response
would be a String for some reason, and you would call
.has_key?
on it,
it would crash the app.
This is why we had to check that we are dealing with Hash in the first
place. So let's see what error response would return for all
those commands:
We just confirmed that response variable is a correct response, that we could use in the app. In the next chapter we are going to learn what is the Block, and how can we use it. You've seen them already in this chapter in methods like:
# find object in array that is less than three:
my_array.find { |obj| obj.to_i < 3 }