Phorum about AppServers & Grid Technologies
It is currently Sun Jul 14, 2024 10:46 pm

All times are UTC + 2 hours [ DST ]

Post new topic Reply to topic  [ 1 post ] 
Author Message
PostPosted: Mon Feb 11, 2019 3:03 am 
Site Admin

Joined: Tue Jan 25, 2011 8:51 pm
Posts: 49
Welcome to Ruby!

Ruby is a dynamic, object-oriented, general-purpose programming language.
It is ranked among the top 10 programming languages worldwide. Much of its growth
is attributed to the popularity of software written in Ruby, particularly the Ruby
on Rails web framework.

A quote from its creator, Yukihiro "Matz" Matsumoto: "Ruby is simple in appearance, but
is very complex inside, just like our human body."

Matsumoto has said that Ruby is designed for programmer productivity and fun, following
the principles of good user interface design.

In Ruby, everything (even a simple number) is an object. We will learn more about objects
in the coming lessons.
Ruby is also completely free. Not only free of charge, but also free to use, copy, modify,
and distribute.
Hello, Ruby!

Let's create our very first Ruby program, the classic "Hello World" program.
For this, we use the built-in puts method.
puts "Hello World"

This code will output the text "Hello World" to the screen.
All text values (strings) must be enclosed in single or double quotes.
Hello, Ruby!

Another method that can be used to display output to the screen is print.
For example:
print "Hello World"

This code displays the same output as before, except that the puts automatically
adds a new line after the output, while print does not.
For example:
puts "Hi"
print "there"
print "Ruby"


Comments are lines of annotation within Ruby code that are ignored at program runtime.
In Ruby, the hashtag symbol is used to create a single-line comment.
For example:
# printing some text
puts "Hi there"

Everything following the hashtag symbol on that line is ignored when the program is run.

You can also create multi-line comments.
Everything between the =begin and =end reserved words are considered a comment:
This comment
spans multiple
puts "Hello"

Adding comments to your code is a good practice. It facilitates a clear understanding
of the code for you and for others who read it.

A variable is a named storage location for a value. It is called variable because the
information stored in that location can be changed when the program is running.
To assign a variable a value, use the equal sign.
For example:
x = 8

This assignment statement declares a variable named x and gives it the value 8. The
equal sign is called the assignment operator.
We can later use the variable name to access its value. For example, to output the
value stored in the variable, we can use puts or print and refer to the variable name:
x = 8
puts x

# outputs 8

Variable names may consist of alphanumeric characters and the underscore character (_),
but cannot begin with a capital letter.

Variables beginning with a capital letter are called constants.
The value of a constant variable cannot be changed once it has been assigned.
For example:
MyNum = 42

# Trying to change the value produces a warning

MyNum = 8
# warning: already initialized constant MyNum
Data Types

All variables in Ruby can be of all data types.
Ruby automatically determines data type by the value assigned to the variable.
For example:

x = 42 # integer
y = 1.58 # floating point value
z = "Hello" # string

You can reassign a different value to a variable at any time.
To insert the value of a variable into a double quote string (a string is a sequence of
characters, such as "Hello"), use the # symbol and curly brackets with the variable name.
For example:

age = 42
puts "He is #{age} years old"

# outputs "He is 42 years old"
Fill in the blanks to insert the value of the name variable into the string:
name = "David"
puts "Hello,#{name}"
Doing Math

Math is an important part of programming. Ruby supports the following arithmetic operators:
x = 5
y = 2

# Addition
puts x+y
# outputs 7

# Subtraction
puts x-y
# outputs 3

# Multiplication
puts x*y
# outputs 10

# Division
puts x/y
# outputs 2

When you divide two integer values, the result will be an integer, as shown in the above
example. If you want to have a floating point result, one operand must be a floating
point value:
x = 5.0
y = 2
puts x/y # outputs 2.5
Modulus Operator

The modulus operator, represented by the percentage symbol (%), represents the remainder of
a division operation.
For example:
x = 9
y = 5
puts x%y
# outputs 4

9 divided by 5 is 1 with a remainder of 4.
Exponent Operator

The ** represents the exponent operator for raising a number to a power to perform
For example:
a = 2
b = 5
puts a**b
# this raises 2 to the power of 5 and outputs 32

The result is 32, as 2*2*2*2*2 = 32.
All operators can also be used with floating point values.
Shorthand Assignment Operators

All of the arithmetic operators have corresponding shorthand forms for assignment.
For example, a = a + 8 can be written as a += 8.
The same applies to the other operators:
x += y # x=x+y
x -= y # x=x-y
x *= y # x=x*y
x /= y # x=x/y
x %= y # x=x%y
x **= y # x=x**y

These are called self-assignment operators, as they perform an assignment and an
arithmetic operation at the same time.
Parallel Assignment

Ruby also supports parallel assignment of variables. This enables multiple variables
to be initialized with a single line of code.
For example:
x = 10
y = 20
z = 30
may be more quickly initialized using parallel assignment:
x, y, z = 10, 20, 30

Parallel assignment is also useful for swapping the values held in two variables:
a, b = b, a
Operator Precedence

Ruby evaluates a mathematical expression using an order of operations that is based
on operator precedence. Exponentiation has the highest precedence followed by
multiplication, division, and modulus from left to right, and then addition and
subtraction from left to right.
You can change the order of operations by using parentheses.
For example:
x = (3+2) * 4
puts x
# outputs 20

As mentioned in the previous lessons, a string is text between single or double
quotation marks.
However, some characters can't be directly included in a string. For instance,
single quotes can't be directly included in a single quote string, because this
would designate the end of the string. Characters like these can be included in
a string by using an escape sequence, which is indicated by a backslash (\):

text = 'Ruby\'s syntax is fun'
puts text
# outputs Ruby's syntax is fun

A string formed with double quotation marks can also include the \n escape sequence,
which represents a new line.
text = "Hello \n World"
puts text

# Outputs:
# Hello
# World

Only the \' and \\ escape sequences can be used with single quote strings.
String Interpolation

You can embed any Ruby expression inside a double quote string using #{ },
just as you did with variable names. Ruby evaluates the placeholders and
replaces them with values:
a = 5
b = 2
puts "The sum is #{a+b}"
# outputs "The sum is 7"

Strings can be joined using the + in a process called concatenation.
When concatenating strings, it doesn't matter whether they've been created with single or
double quotes.

a = "Hi "
b = 'there'
puts a+b
# outputs "Hi there"

Even if your strings contain numbers, they are still added as strings rather than
integers. Adding a string to a number produces an error, because even though they
might look similar, they are two different entities: "1" is a string, whereas 1 is an integer.
Repeating a String

Strings can be repeated using the * and an integer value.
The order of the string and the integer does matter: the string has to come first.
For example:
a = "abc"
puts a*3
# outputs "abcabcabc"

puts '5'*4
# outputs 5555
Try It Yourself

Strings can't be multiplied by other strings.

To get input from the user in Ruby, you use the gets method, which returns what the user
types as a string. To store the input for later use, you can assign the return value
to a variable.
For example:

x = gets
puts x

gets gets a line of text, including the new line at the end. If you do not want to
include the new line, use the gets.chomp method:

puts "Enter your name"
name = gets.chomp
puts "Welcome, #{name}"

The value of the input is a string. To convert it to an integer, you can use the
gets.to_i method.

In Ruby, there are two Boolean values: true and false.
isOnline = true

userIsAdmin = false

Another value that you will often encounter is nil. It shows the absence of value.

If you try to evaluate a value other than true or false as a Boolean, Ruby will automatically
treat it as a Boolean.
When this is done, a non-Boolean value that evaluates to true is called "truthy" and a
non-Boolean value that evaluates to false is called "falsey".

In Ruby only false and nil are falsey. Everything else is truthy (even 0 is truthy).
Only true and false are Booleans. nil is not a Boolean. 0 is not a Boolean. The string
"Hello" is not a Boolean. However, in a context where a Boolean is expected, Ruby evaluates
them as Boolean (truthy and falsey).

A Boolean comparison using the == operator returns true when two operands are equal,
and false when they are not:

a = 5
b = 8

puts a == b # false

puts a == 5 # true

Be careful not to confuse assignment (one equals sign) with comparison (two equals signs).

Another comparison operator, the not equal operator (!=), evaluates to true if the items being
compared aren't equal, and false if they are.

For example:
a = 8
b = 7

puts a != b # true

Ruby also has operators that determine whether one value is greater than or less than another.
These operators are > and < respectively. Similarly, the greater than or equal to, and less
than or equal to operators are >= and <=.
For example:

puts 12 > 8 # true

puts 5 < 2 # false

puts 5 >= 5.0 # true

puts 3 <= 6 # true

There is also the .eql? method, which results in true only if both arguments have the same
type and equal values.
For example:

puts 3 == 3.0 # true
# but
puts 3.eql?(3.0) # false

3.eql?(3.0) is false because 3 is an integer and 3.0 is a float.
Greater than and less than operators can also be used to compare strings lexicographically
(the alphabetical order of words is based on the alphabetical order of their component letters).
if Statements

You can use an if expression to execute code when a certain condition holds.
If a conditional expression evaluates to true, the if code is carried out. Otherwise, the
code is ignored.
For example:
a = 42

if a > 7
puts "Yes"

# outputs "Yes"

The condition a > 7 is evaluated. When it is true, the statements inside the if are executed
and the program outputs Yes.
You can have multiple statements inside a single if expression.
The end keyword is required to indicate the end of the if.
if Statements

if expressions can be nested, one inside the other.
This means that the inner if is the code part of the outer one. This is one way to see
whether multiple conditions are satisfied. Keep in mind that once an if condition fails, the
entire block is exited.

num = 16
if num > 7
puts "Greater than 7"
if num < 42
puts "Between 7 and 42"
# outputs:
# Greater than 7
# Between 7 and 42

Each if has to have a corresponding end.
else Statements

An else block in an if expression contains code that is called when the if conditional
evaluates to false.
For example:

age = 15
if age > 18
puts "Welcome"
puts "Too young"

# outputs "Too young"

The end keyword is only needed for the if statement, as the else block is part
of the if expression.
elsif Statements

The elsif (short for else if) block is useful when you want to test multiple conditions.
A series of if elsif expressions can have a final else block, which is called if none of the
if or elsif expressions are true.
For example:

num = 8
if num == 3
puts "Number is 3"
elsif num == 10
puts "Number is 10"
elsif num == 7
puts "Number is 7"
puts "Not found"

When an elsif block executes the entire if expression is exited.

The unless expression is the opposite of an if expression. It executes code when a conditional is false.
For example:

a = 42
unless a < 10
puts "Yes"
puts "No"

# outputs "Yes"

You can use an else block with the unless, just like you did with the if expression. The end
keyword is also required to close the block.

The if and unless modifiers can also be used to execute code.

a = 42
puts "Yes" if a > 10
puts "Yes" unless a < 10

This code before the if executes only if the condition evaluates to true.
The code before the unless executes only if the condition is false.
As you can see, Ruby code is comparably short and easy to read, making it a very intuitive
programming language.
Logical Operators

Logical operators are used to form more complex criteria that test more than one condition
for an if expression.
Ruby has three logical operators: and (&&), or (||), and not (!).
A conditional using and evaluates as true if, and only if, both of its operands
are true. Otherwise, the entire conditional evaluates to false.
For example:

a = 42
b = 8
if a > 7 && b < 11
puts "Yes"

# outputs "Yes"

Ruby can use words instead of the logical operator symbols (and, or, not), but those have
lower precedence and are generally avoided.

The or (||) operator evaluates to true if either (or both) of its operands are true,
and false if both operands are false.
For example:

a = 3
b = 5
if a ==3 || b > 10
puts "Welcome"

# outputs "Welcome"

The not (!) operator reverses the state of a single operand.
The result of not true is false, and not false is true.

a = 7
puts !(a>5)

# outputs false

In this code, a>5 evaluates to true and then the not operator reverses it to false.
You can chain together multiple conditions with the logical operators to check for multiple
conditions. Parentheses can be used to group together separate conditions for clarity and
to control the order of operations. For example:

(a>b && b < 100) || (a<b && b > 100)
case Statements

As we have seen in the previous lessons, we can check for multiple conditions using the
if/elsif/else expression.
A more simplified and flexible option is the case expression, which tests a value in when statements.
For example:

a = 2

case a
when 1
puts "One"
when 2
puts "Two"
when 3
puts "Three"

# outputs "Two"

You can have as many when statements as you need for a single case.
Note that the case expression must be closed with the end keyword.
case Statements

Multiple values can be tested within a single when by separating the values with commas.
For example:
age = 5

case age
when 1, 2, 3
puts "Little baby"
when 4, 5
puts "Child"

# outputs "Child"
case Statements

An else statement can be provided to execute code if no when condition matches:
age = 18

case age
when 1, 2, 3
puts "Little baby"
when 4, 5
puts "Child"
puts "Not a baby"

# outputs "Not a baby"

Case statements allow us to more easily control program flow. If statements
should always be used to determine if a conditional is true, and case statements
are for when you need to make different decisions based on a value.

Loops are used to execute the same block of code a specified number of times.
The while loop executes a block of code while its condition is true.
For example:
x = 0
while x < 10
puts x
x += 1

This will output the numbers 0 to 9. After the loop control variable becomes 10, the
condition x < 10 evaluates to false and the loop ends its execution.
If we leave out the x+=1 statement, the loop will run forever, because
the condition will remain true. This situation is called an infinite loop.
until Loops

The until loop is the opposite of a while loop: it will run while its condition is false.
For example:

a = 0
until a > 10
puts "a = #{a}"
a +=2

This will print all even numbers from 0 to 10.

A range represents a sequence. 0 to 10, 56 to 82, and a to z are all examples of ranges.
Ruby has special operators to create ranges with ease.
These are the ''..'' and ''...'' range operators. The two-dot form creates an inclusive range,
while the three-dot form creates a range that excludes the specified high value.
For example:
a = (1..7).to_a
puts a # [1, 2, 3, 4, 5, 6, 7]

b = (79...82).to_a
puts b # [79, 80, 81]

c = ("a".."d").to_a
puts c # [a, b, c, d]

The to_a method is used to convert a range to an array, so we can output it.
You will learn more about arrays in the coming lessons.

Ranges can be used in case statements for when values.
For example:
age = 42

case age
when 0..14
puts "Child"
when 15..24
puts "Youth"
when 25..64
puts "Adult"
puts "Senior"
Try It Yourself

Ranges are also useful in for loops. You will learn about them in the coming lesson.
for Loop

The for loop is a useful statement when you need to loop over a specific set of values,
for example, a range.
The for loop consists of an empty variable and a range. At each iteration of the loop,
the empty variable will be assigned the corresponding element of the range.
For example:

for i in (1..10)
puts i

This will output the numbers 1 to 10.
During the first loop the variable i will be assigned the first value of the range, 1.
On the second loop, it will be assigned to the value 2, and so on, until the end of the range.
The for loop executes a block of code once for each element in the range.

The break statement can be used to stop a loop.
For example:

for i in 1..5
break if i > 3
puts i

# outputs:
# 1
# 2
# 3

The loop stops executing when the condition i > 3 is met.

Similarly, the next statement can be used to skip one iteration of the loop and continue with the next one.
For example:

for i in 0..10
next if i %2 == 0
puts i

This will output only the odd numbers from 0 to 10 because the even numbers will skip the loop iteration.
Ruby also has the redo statement, which causes the current loop iteration to repeat.
The retry statement causes the whole loop to start again from the beginning.
loop do

Another looping statement in Ruby is the loop do statement.
It allows code to execute until a break condition is achieved.
For example:

x = 0
loop do
puts x
x += 1
break if x > 10

This will print the numbers 0 to 10. When x > 10 evaluates to true, the loop will stop.
If we do not include a break condition, the loop will run forever.

An Array is essentially a list of numbered items.
The items are declared in a comma-separated list and enclosed in square brackets.
For example:
items = ["Apple", "Orange", "Banana"]

The code above declares an array named items containing three strings.

Each item has its own unique index with the first item at index zero.
To refer to an item, we need to refer to its index:
puts items[0]
# outputs "Apple"

You can assign any array element a new value by using its index:
items[1] = "Kiwi"

This will assign the element with index 1 the value "Kiwi"
A negative index is assumed relative to the end of the array. For example, an index of -1 indicates
the last element of the array, -2 is the next to last element in the array, and so on.
Adding Elements

An array can contain different types of elements:
arr = [5, "Dave", 15.88, false]

puts arr[0] # 5
puts arr[1] # "Dave"
puts arr[-1] # false

To add new elements to the array, you can use the << operator, which is typed as two less than signs:

arr << 8
puts arr

This will add an element with the value 8 to the end of the array.
Alternatively, you can use the push and insert methods (we will learn more about methods in the coming
module. For now, just remember that a method is code that performs an action).


This will add 8 to the end of the array.

The insert method allows you to insert the element at the desired position:

arr.insert(2, 8)

The code above will insert an element with value 8 at the position with index 2.
Removing Elements

Similarly, there are pop and delete_at methods available to remove elements from the array.
The pop method removes the last element of the array.
For example:
arr = [1, 2, 3]
print arr
# [1, 2]

When used to output arrays, the puts method outputs one element per line, while print actually
outputs brackets and a list of items.

You can use the delete_at method to specify the index of the element to be removed:
arr = [2, 4, 6, 8]
print arr
# [2, 4, 8]

Remember, the index starts counting at 0. So the third element in the array has the index 2.
Array Ranges

You can even access a range within the array using the range operators:
nums = [6, 3, 8, 7, 9]
print nums[1..3]
# [3, 8, 7]
Combining Arrays

You can add two arrays together:
a = [1, 2, 3]
b = [4, 5]

res = a + b
print res # [1, 2, 3, 4, 5]

You can also subtract arrays, which will result in the first array removing any elements that also appear
in second array.
a = [1, 2, 3, 4, 5]
b = [2, 4, 5, 6]

res = a - b
print res #[1, 3]

The elements of an array can be duplicated using the * operator and an integer value.
For example: [1, 2, 3] * 3 results in [1, 2, 3, 1, 2, 3, 1, 2, 3]
Boolean Operations

The & operator returns a new array containing the elements common to the two arrays, with no duplicates.
a = [2, 3, 7, 8]
b = [2, 7, 9]

print a & b # [2, 7]

The | operator returns a new array by joining the arrays and removing duplicates.
a = [2, 3, 7, 8]
b = [2, 7, 9]

print a | b # [2, 3, 7, 8, 9]
Moving Elements

The reverse method returns a new array containing the original array elements in reverse order.
arr = [5, 3, 8]
res = arr.reverse
print res # [8, 3, 5]

You can also reverse the array in place using the reverse! method:
arr = [1, 2, 3]
print arr.reverse!
Array Methods

There are a number of other useful methods available for manipulating arrays.
Here are some of the most used ones:
array.length or array.size returns the number of elements in array.
array.sort returns a new array with the elements sorted
array.uniq returns a new array with duplicate values removed from array.
array.uniq! removes duplicates in place.
array.freeze safeguards the array, preventing it from being modified.
array.include?(obj) returns true if obj is present in array, false otherwise.
array.min returns the element with the minimum value.
array.max returns the element with the maximum value.
Most of the methods also work for strings, which can be thought of as arrays of characters.

A for loop is one way to iterate over an array of elements:
arr = ["a", "b", "c"]
for x in arr
puts "Value: #{x}"

This will loop through all the elements of the array and output them one per line.
Ruby has a more elegant way of iterating over array elements. You will learn about iterators in
the coming lessons.

Hashes (sometimes known as associative arrays, maps, or dictionaries) are similar to arrays in that they are
an indexed collection of elements.
However, while you index arrays with integers, you can index a hash with anything.
That is very useful when you want to map values, for example: "name" => "David". Here,
"name" is the index (also called the key) which is mapped to the value "David". So, hashes represent
key=>value pairs.
A hash is created with comma separated keys and values inside curly brackets:

ages = { "David" => 28, "Amy"=> 19, "Rob" => 42 }
puts ages["Amy"]
# outputs 19

As you can see, the values are accessed using the same index syntax as with an array.
Compared with arrays, hashes have one significant advantage: they can use any object as an index,
even an array. For example:
{ [1,"jan"] => "January" }

In the previous example we used strings as keys for the hash, but Ruby has a more elegant and faster way for
creating and accessing hash indexes than using strings.
Symbols are similar to strings, but they are immutable, meaning that they cannot be changed.
A symbol is created using a colon and a name, for example:
a = :id

In the code above :id is a symbol. You can also think of :id as meaning the name of the variable
id, and plain id as meaning the value of the variable.
So why use symbols instead of strings? Using symbols not only saves time when doing
comparisons, but also saves memory, because they are only stored once.
Hashes & Symbols

Uses of symbols includes using them as hash keys.
For example:
h = {:name=>"Dave", :age=>28, :gender=>"male"}

puts h[:age]

In the code above, symbols are used as keys for our hash.
A shorter way of writing the same code as above is the following:
h = {name:"Dave", age:28, gender:"male"}

puts h[:age]

In other programming languages hashes are called associative arrays or dictionaries.

There are useful methods available for manipulating hashes:
hash.delete(key) removes the key-value pair from hash by key.
hash.index(value) returns the key for the given value in hash, nil if no matching value is found.
hash.invert creates a new hash, reversing keys and values from hash; that is, in the new hash, the
keys from hash become values and values become keys.
hash.keys returns a new array with keys from hash.
hash.values returns a new array containing all the values of hash.
hash.length returns the length of hash as an integer.

For example:

car = {brand:"BMW", year:2016, color:"red", length:205}
puts car.values

# outputs:
# 2016
# red
Nested Arrays

Arrays can contain other arrays. These are called nested arrays.
For example:
arr = [ [1, 2, 3], [4, 5, 6] ]
puts arr[1][2]
# outputs 6

The arr array contains two arrays. So, arr[1][2] accesses the second array's third element, which is 6.
There can be multiple levels of nesting.
Nested Hashes

Hashes can also be nested.
cars = {
bmw: { year:2016, color:"red"},
mercedes: { year:2012, color:"black"},
porsche: { year:2014, color:"white"}

puts cars[:bmw][:color]
# outputs "red"

Hashes and arrays can have any level of nesting, but keep in mind that hashes and arrays with more than
three dimensions are harder to manage.

As we have seen in the previous lessons, we can loop over arrays and hashes using for loops.
Ruby provides more elegant looping methods called iterators. Iterators are used to create loops.
The each iterator is one of the most used ones:
arr = [2, 4, 6]

arr.each do |x|
puts x

The syntax might seem confusing at first, but you just need to remember the pipe symbols around
the variable. The each iterator loops through all elements of the array and assigns the corresponding
element to the variable inside the pipes with each iteration. This variable is called the block parameter.
We can, for example, calculate the sum of all elements:
arr = [2, 4, 6]
sum = 0
arr.each do |x|
sum += x

puts sum # 12

The each iterator can also be used with hashes:
sizes = {svga:800, hd:1366, uhd:3840}

sizes.each do |key, value|
puts "#{key}=>#{value}"

In the example above, key and value are variables that get assigned to the corresponding values of the
hash elements at each iteration. You can use any name for your variables.

The do and end keywords specify a block of code in Ruby.
After the opening of the block, we have the block parameters within pipes ( | | ).
Ruby provides a shorthand way of writing blocks: you can use curly braces to start and end code blocks.
So the above example can be written shorter as:
sizes = {svga:800, hd:1366, uhd:3840}

sizes.each { |key, value| puts "#{key}=>#{value}" }

The each iterator can also be used on ranges.
For strings, you can use the each_char iterator to iterate over the characters.

There are also iterators available for numbers.
The times iterator executes a loop the specified number of times:
10.times do
puts "Hi"

The code above will print "Hi" 10 times.
Letter Frequency

Let's create a program that will count the frequency of letters (number of
occurrences) in a given string.
First we need a string:
# a sample text
text = "I am learning Ruby and it is fun!"


The downcase! method is used to convert all letters in the string to lowercase.

Next, we will need a hash to hold the letters as keys and the frequency of
the letters as their corresponding values.
For that we need to create an empty hash and set the default value for
all values to 0.

freqs = {}
freqs.default = 0

The default method is used to set the default value for the hash, meaning
that any key that does not have a value assigned will be set to that value.
Letter Frequency

Next, we will need to iterate over each character in the string and calculate
the number of occurrences in the hash. We can do that using the each_char iterator:
text.each_char { |char| freqs[char] += 1}

During each iteration, the char variable is assigned the corresponding
character in our text string and then the value of that character's
frequency is incremented in the freqs hash.
So, for example, if the letter "c" appears twice in the text, freqs["c"] will
be equal to 2 after the iterator executes.
So, freqs will hold all the characters of the string with their corresponding
occurrence number.

To show a nice result output in an alphabetical order, we can create a range of
all letters and print their corresponding frequencies:

("a".."z").each {|x| puts "#{x} : #{freqs[x]}" }

We do this because not all letters of the alphabet are contained in our text.

The final code:

text = "I am learning Ruby and it is fun!"
freqs = {}
freqs.default = 0

text.each_char { |char| freqs[char] += 1}

("a".."z").each {|x| puts "#{x} : #{freqs[x]}" }

With just 6 lines of code we created a fully working letter frequency counter!

In the previous lessons we have seen some examples of methods, such as the reverse
method for arrays.
A method is a set of statements that perform a specific task.
You can define your own methods to perform your desired tasks.
The def keyword is used to define a method.

def say
puts "Hi"

The above code defines a method called "say" that performs a simple output operation,
printing "Hi".
The method name should start with a lowercase letter, so it will not be confused
with constants.
Calling Methods

Now that we have defined our method, we can call it by including its name in a line of code:
def say
puts "Hi"

# outputs "Hi"

You can call methods as many times as you need:

Methods should be defined before calling them, otherwise Ruby will raise an error.
You can also call methods inside other methods.

A method declaration can include parameters, which you define inside parentheses after the method name.
For example:
def sqr(x)
puts x*x

# outputs 64

The defined sqr method has one parameter (called x) and outputs its square. You can name your parameters
anything you like.
When calling the method, we "pass" the actual parameter value to the method using parentheses.
The actual parameter value is called an argument.
So, in the above example, x is the parameter of the method, while 8 is the argument.
Multiple Parameters

A method can include multiple parameters, separated by commas.
For example:
def sum(a, b)
puts a+b

sum(7, 4)
# outputs 11

sum(88, 164)
# outputs 252

You can also pass variable arguments:
def sum(a, b, c)
puts a+b+c

x = 2
y = 42
z = 6
sum(x, y, z)
# outputs 50
Default Parameters

You can also set default values for the parameters, so that the method will still work even if
you do not provide all the arguments.
For example:
def sum(a, b=8)
puts a+b

Now our parameter b has a default value of 8.
If we pass just one argument, the method will use the value 8 as the second argument:
x = 5
# outputs 13

We can also pass two arguments as before, and the method will work as expected. The default value
only comes into play when no value for that argument is provided.
Fill in the blanks to define a method with two parameters with default values 10 and 42 respectfully.

def doSmth(x = 10, y=42)
puts x*y

You can also leave off the parentheses when using methods.
For example, sum(x, y) can be written as sum x, y.

def sum x, y
puts x+y

sum 6, 9

This leads to more fluid reading of code, but sometimes it can be confusing.

Let's create a program that prompts the user to enter a name and then outputs a greeting based
on the input.

def greet(name="")
if name==""
puts "Greetings!"
puts "Welcome, #{name}"


We defined a method called greet that takes one parameter and outputs a message based on that parameter.
Then we called the greet method passing user input as the argument.
Reminder: gets.chomp is used to take user input and strip the newline at the end of the input.
Optional Parameters

You can also define methods that take any number of arguments using the following syntax:
def someMethod(*p)
puts p

someMethod(25, "hello", true)

Now you can pass any number of arguments to the method.
In the code above p is an array. When you pass arguments to the method, they become elements of p.
If you call the method without any arguments, the array p will be empty.

This technique allows optional parameters for a method, for example:

def myMethod(a, b, *c)
#some code

myMethod has two mandatory parameters and an optional one. Therefore, you can pass two or more arguments
to the method.
Returning Values

Until now all the methods we have defined output values. Sometimes you need a method to perform
an action and return the result so that the returned value can be used further in the program (for example, by assigning the return value to a variable).
The return keyword is used to return a value from a method.
For example:
def sum(a, b)
res = a+b
return res

x = sum(5, 23)
puts x

The sum method returns the sum of its parameters, which is then assigned to variable x.
Returning Values

You can return multiple values from a method by separating them with commas in the return statement.
For example:
def squares(a, b, c)
return a*a, b*b, c*c

arr = squares(2, 3, 6)
puts arr
Try It Yourself

The result is an array containing the returned values.

Even when you do not explicitly include a return statement in your method, Ruby always returns
the evaluated result of the last line of the method that is executed.
For example:

def demo(a, b)
a = b-2
b = a-3

puts demo(5, 6)
# outputs 1

The above method will return the result of its last expression, which is b = a-3.
Any code in the method after a return statement will not execute, because a method stops executing
once the return is executed.
For example:

def demo(a)
a = 5
return a
a = 9

The method above will return the value 5. The statement a=9 is ignored.
Chaining Methods

Because all methods return a value, we can chain multiple methods together, as well as chain methods
with iterators.
For example:

def square(x)

square(4).times {puts "Hi"}

In the code above we chained our defined square method with the times iterator. As square(4) will
return 16, the loop will run and output "Hi" 16 times.
If anywhere along the chain there is a nil or an error, the entire chained call will break down.
Methods as Arguments

We can also pass methods as arguments to other methods. The returned values of those methods
will be used as the actual values for the arguments, for example:

def add(a, b)

def mult(a, b)

x = mult(add(2, 3), add(4, 7))
puts x
# outputs 55

We defined two methods, add and mult, and passed two calls to the add method as arguments to mult.
Lets break down the code:
add(2, 3) returns 5
add(4, 7) returns 11
so mult(add(2, 3), add(4, 7)) is the same as mult(5, 11) which returns 55.
Variable Scope

Scope defines where in a program a variable is accessible.
Ruby has four types of variable scope: local, global, instance and class.

Local variables are local to the code construct in which they are declared. For example, a local
variable declared in a method or within a loop cannot be accessed outside of that loop or method.
Local variable names must begin with either an underscore or a lowercase letter.
For example:

def calc(x)
y = 2
puts x*y

In the above code x and y are both local variables. They are accessible only inside the calc method.
If we try to access them outside of the method we will get an error:

def calc(x)
y = 2
puts x*y

puts y
# output: "undefined local variable or method 'y' "

The same applies to loops and iterators:

arr = [1, 2, 3]
arr.each {|x| puts x}

x is a local variable available only in the iterator block.
You can have different variables with the same name in different scopes.
Global Scope

Global variables in Ruby are accessible from anywhere in the Ruby program, regardless of where
they are declared. Global variable names are prefixed with a dollar sign ($).
For example:
$x = 42

def change
$x = 8

puts $x
# outputs 8

As you can see the $x global variable is accessible in the whole program.
Use of global variables is strongly discouraged. The problem with global variables is that, not only
are they visible anywhere in the code, but they can also be
changed from anywhere in the application. This can result in hard to find bugs.
Variable Scope

So why does scope exist? Why couldn't all variables be accessible everywhere so we wouldn't have
to care about their scope?
First of all, there are naming issues: if you have a big program, you'd have to give all of
your variables unique names to avoid conflicts. Imagine keeping track of thousands of variable names.
Then, there are access issues: it's very hard to track who changes what when everyone has the
ability to do so.
Scope makes the program more predictable and secure.
The other two types of scope in Ruby are instance and class. We will learn about them in the
next module.

Another way of creating loops is recursion. It involves the concept of methods calling themselves.
It is used to solve problems that can be broken up into easier sub-problems of the same type.

A classic example of a method that is implemented recursively is the factorial method, which finds
the product of all positive integers below a specified number.
For example, 5! (5 factorial) is 5 * 4 * 3 * 2 * 1 (120). To implement this recursively, notice
that 5! = 5 * 4!, 4! = 4 * 3!, 3! = 3 * 2!, and so on. Generally, n! = n * (n-1)!.
Furthermore, 1! = 1. This is known as the base case, as it can be calculated without performing
any more factorials.
Below is a recursive implementation of the factorial method.

def fact(n)
if n<= 1
n * fact( n - 1 )

puts fact(5)
# outputs 120

The if n<=1 block acts as the base case. The base case is the exit condition of the recursion.
Ruby is fast! Try to run the above code for a larger number and see the output.

Recursive methods can become infinite, just like infinite loops. These often occur when you
forget to implement the base case.
Below is an incorrect version of the factorial method. It has no base case:

def fact(n)
n * fact( n - 1 )

puts fact(5)
# outputs "stack level too deep (SystemStackError)"

Remember, an important key concept with recursion is to define and include the base case that
makes the recursion stop.
Object Oriented Programming

Ruby is a pure object-oriented language, which means everything in Ruby is an object. Even simple
numbers, strings and Booleans are objects.

In programming, objects are independent units, and each has its own identity, just
as objects in the real world do. An apple is an object; so is a mug. Each has its own unique
identity. It's possible to have two mugs that look alike, but they are still separate, unique objects.

To create objects we use classes.
A class defines the data and actions associated with an object, but is separate from the object
itself. In other words, a class can be thought of as an object's blueprint, description, or
definition. For example, there can be many cat objects of the single class Cat.
Just like in the real world, where you can use a blueprint to construct multiple buildings,
in programming you can use the same class as a blueprint for creating multiple objects.

Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC + 2 hours [ DST ]

Who is online

Users browsing this forum: No registered users and 1 guest

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: