Clever Algorithms: Nature-Inspired Programming Recipes

A book by Jason Brownlee

Home | Read Online | Amazon | GoodReads | Google Books | PDF (code) | GitHub



Ruby: Quick-Start Guide

Overview

All code examples in this book are provided in the Ruby programming language. This appendix provides a high-level introduction to the Ruby programming language. This guide is intended for programmers of an existing procedural language (such as Python, Java, C, C++, C#) to learn enough Ruby to be able to interpret and modify the code examples provided in the Clever Algorithms project.

Language Basics

This section summarizes the basics of the language, including variables, flow control, data structures, and functions.

Ruby Files

Ruby is an interpreted language, meaning that programs are typed as text into a .rb file which is parsed and executed at the time the script is run. For example, the following snippet shows how to invoke the Ruby interpreter on a script in the file genetic_algorithm.rb from the command line: ruby genetic_algorithm.rb

Ruby scripts are written in ASCII text and are parsed and executed in a linear manner (top to bottom). A script can define functionality (as modules, functions, and classes) and invoke functionality (such as calling a function).

Comments in Ruby are defined by a # character, after which the remainder of the line is ignored. The only exception is in strings, where the character can have a special meaning.

The Ruby interpreter can be used in an interactive manner by typing out a Ruby script directly. This can be useful for testing specific behavior. For example, it is encouraged that you open the Ruby interpreter and follow along this guide by typing out the examples. The Ruby interpreter can be opened from the command line by typing irb and exited again by typing exit from within the interpreter.

Variables

A variable holds a piece of information such as an integer, a scalar, boolean, or a string.

a = 1  # a holds the integer value '1'
b
= 2.2  # b holds the floating point value '2.2'
c
= false # c holds the boolean value false
d
= "hello, world" # d holds the string value 'hello, world'

Ruby has a number of different data types (such as numbers and strings) although it does not enforce the type safety of variables. Instead it uses 'duck typing', where as long as the value of a variable responds appropriately to messages it receives, the interpreter is happy.

Strings can be constructed from static text as well as the values of variables. The following example defines a variable and then defines a string that contains the variable. The #{} is a special sequence that informs the interrupter to evaluate the contents of inside the brackets, in this case to evaluate the variable n, which happens to be assigned the value 55.

n = 55 # an integer
s
= "The number is: #{n}" # => The number is: 55

The values of variables can be compared using the == for equality and != for inequality. The following provides an example of testing the equality of two variables and assigning the boolean (true or false) result to a third variable.

a = 1
b
= 2
c
= (a == b) # false

Ruby supports the classical && and || for AND and OR, but it also supports the and and or keywords themselves.

a = 1
b
= 2
c
= a==1 and b==2 # true

Flow Control

A script is a sequence of statements that invoke pre-defined functionality. There are structures for manipulating the flow of control within the script, such as conditional statements and loops.

Conditional statements can take the traditional forms of if condition then action, with the standard variants of if-then-else and if-then-elseif. For example:

a = 1
b
= 2
if(a == b)
        a
+= 1 # equivalent to a = a + 1
elsif a == 1 # brackets around conditions are optional
        a
= 1 # this line is executed
else
        a
= 0
end

Conditional statements can also be added to the end of statements. For example, a variable can be assigned a value only if a condition holds, defined all on one line.

a = 2
b
= 99 if a == 2 # b => 99

Loops allow a set of statements to be repeatedly executed until a condition is met or while a condition is not met.

a = 0
while a < 10 # condition before the statements
        puts a
+= 1
end
b = 10
begin
        puts b
-= 1
end until b==0 # condition after the statements

As with the if conditions, the loops can be added to the end of statements allowing a loop on a single line.

a = 0
puts a
+= 1 while a<10

Arrays and Hashs

An array is a linear collection of variables and can be defined by creating a new Array object.

a = [] # define a new array implicitly
a
= Array.new # explicitly create a new array
a
= Array.new(10) # create a new array with space for 10 items

The contents of an array can be accessed by the index of the element.

a = [1, 2, 3] # inline declaration and definition of an array
b
= a[0] # first element, equivalent to a.first

Arrays are also not fix-sized and elements can be added and deleted dynamically.

a = [1, 2, 3] # inline declaration and definition of an array
a
<< 4 # => [1, 2, 3, 4]
a
.delete_at(0) # => returns 1, a is now [2, 3, 4]

A hash is an associative array, where values can be stored and accessed using a key. A key can be an object (such as a string) or a symbol.

h = {} # empty hash
h
= Hash.new
h
= {"A"=>1, "B"=>2} # string keys
a
= h["A"] # => 1
h = {:a=>1, :b=>2} # label keys
a
= h[:a] # => 1
h
[:c] = 3 # add new key-value combination
h
[:d] # => nil as there is no value

Functions and Blocks

The puts function can be used to write a line to the console.

puts("Testing 1, 2, 3") # => Testing 1, 2, 3
puts
"Testing 4, 5, 6" # note brackets are not required for the function call

Functions allow a program to be partitioned into discrete actions and pre-defined and reusable. The following is an example of a simple function.

def test_function()
        puts
"Test!"
end
puts test_function
# => Test!

A function can take a list of variables called function arguments.

def test_function(a)
        puts
"Test: #{a}"
end
puts test_function
("me") # => Test: me

Function arguments can have default values, meaning that if the argument is not provided in a call to the function, the default is used.

def test_function(a="me")
        puts
"Test: #{a}"
end
puts test_function
() # => Test: me
puts test_function
("you") # => Test: you

A function can return a variable, called a return value.

def square(x)
       
return x**2 # note the ** is a power-of operator in Ruby
end
puts square
(3) # => 9

A block is a collection of statements that can be treated as a single unit. A block can be provided to a function and it can be provided with parameters. A block can be defined using curly brackets {} or the do and end keywords. Parameters to a block are signified by |var|.

The following example shows an array with a block passed to the constructor of the Array object that accepts a parameter of the current array index being initialized and returns the value with which to initialize the array.

b = Array.new(10) {|i| i} # define a new array initialized 0..9
# do...end block
b
= Array.new(10) do |i| # => [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
        i
* i
end

Everything is an object in Ruby, even numbers, and as such everything has some behaviors defined. For example, an integer has a .times function that can be called that takes a block as a parameter, executing the block the integer number of times.

10.times {|i| puts i} # prints 0..9 each on a new line

Ruby Idioms

There are standard patterns for performing certain tasks in Ruby, such as assignment and enumerating. This section presents the common Ruby idioms used throughout the code examples in this book.

Assignment

Assignment is the definition of variables (setting a variable to a value). Ruby allows mass assignment, for example, multiple variables can be assigned to respective values on a single line.

a,b,c = 1,2,3

Ruby also has special support for arrays, where variables can be mass-assigned from the values in an array. This can be useful if a function returns an array of values which are mass assigned to a collection of variables.

a, b, c = [1, 2, 3]
def get_min_max(vector)
       
return [vector.min, vector.max]
end
v
= [1,2,3,4,5]
min
, max = get_min_max(v) # => 1, 5

Enumerating

Those collections that are enumerable, such as arrays, provide convenient functions for visiting each value in the collection. A very common idiom is the use of the .each and .each_with_index functions on a collection which accepts a block. These functions are typically used with an in-line block {} so that they fit onto one line.

[1,2,3,4,5].each {|v| puts v} # in-line block
# a do...end block
[1,2,3,4,5].each_with_index do |v,i|
        puts
"#{i} = #{v}"
end

The sort function is a very heavily-used enumeration function. It returns a copy of the collection that is sorted.

a = [3, 2, 4, 1]
a
= a.sort # => [1, 2, 3, 4]

There are a few versions of the sort function including a version that takes a block. This version of the sort function can be used to sort the variables in the collection using something other than the actual direct values in the array. This is heavily used in code examples to sort arrays of hash maps by a particular key-value pair. The <=> operator is used to compare two values together, returning a -1, 0, or 1 if the first value is smaller, the same, or larger than the second.

a = {:quality=>2, :quality=>3, :quality=>1}
a
= a.sort {|x,y| x[:quality]<=>y[:quality] } # => ordered by quality

Function Names

Given that everything is an object, executing a function on a object (a behavior) can be thought of as sending a message to that object. For some messages sent to objects, there is a convention to adjust the function name accordingly. For example, functions that ask a question of an object (return a boolean) have a question mark (?) on the end of the function name. Those functions that change the internal state of an object (its data) have an exclamation mark on the end (!). When working with an imperative script (a script without objects) this convention applies to the data provided as function arguments.

def is_rich?(amount)
       
return amount >= 1000
end
puts is_rich
?(99) # => false
def square_vector!(vector)
        vector
.each_with_index {|v,i| vector[i] = v**2}
end
v
= [2,2]
square_vector
!(v)
puts v
.inspect # => [4,4]

Conclusions

This quick-start guide has only scratched the surface of the Ruby Programming Language. Please refer to one of the referenced textbooks on the language for a more detailed introduction to this powerful and fun programming language [Thomas2004] [Flanagan2008].

Bibliography

[Flanagan2008] D. Flanagan and Y. Matsumoto, "The Ruby Programming Language", O'Reilly Media, 2008.
[Thomas2004] D. Thomas and C. Fowler and A. Hunt, "Programming Ruby: The Pragmatic Programmers' Guide", Pragmatic Bookshelf, 2004.



Please Note: This content was automatically generated from the book content and may contain minor differences.