Ruby Programming/Ruby basics

As with the rest of this tutorial, we assume some basic familiarity with programming language concepts (i.e. if statement, while loops) and also some basic understanding of object-oriented programming.

= Dealing with variables =

We'll deal with variables in much more depth when we talk about classes and objects. For now, let's just say your basic local variable names should start with either a lower case letter or an underscore, and should contain upper or lower case letters, numbers, and underscore characters. Global variables start with a $.

= Program flow =

Ruby includes a pretty standard set of looping and branching constructs: if, while and case

For example, here's if in action:

a = 10 * rand if a < 5 puts "#{a} less than 5" elsif a > 7 puts "#{a} greater than 7" else puts "Cheese sandwich!" end

[As in other languages, the rand function generates a random number between 0 and 1]

There will be plenty more time to discuss conditional statements in later chapters. The above example should be pretty clear.

Ruby also includes a negated form of if called unless which goes something like

unless a > 5 puts "a is less than or equal to 5" else puts "a is greater than 5" end

Generally speaking, Ruby keeps an <tt>if</tt> statement straight as long as the conditional (<tt>if ...</tt>) and the associated code block are on separate lines. If you have to smash everything together on one line, you'll need to place the <tt>then</tt> keyword after the conditional

if a < 5 then puts "#{a} less than 5" end if a < 5 then puts "#{a} less than 5" else puts "#{a} greater than 5" end

Note that the <tt>if</tt> statement is also an expression; its value is the last line of the block executed. Therefore, the line above could also have been written as

puts(if a < 5 then "#{a} less than 5" else "#{a} greater than 5" end)

Ruby has also adopted the syntax from Perl where <tt>if</tt> and <tt>unless</tt> statements can be used as conditional modifiers after a statement. For example

puts "#{a} less than 5" if a < 5 puts "Cheese sandwich" unless a == 4

<tt>while</tt> behaves as it does in other languages -- the code block that follows is run zero or more times, as long as the conditional is true

while a > 5 a = 10*rand end

And like <tt>if</tt>, there is also a negated version of <tt>while</tt> called <tt>until</tt> which runs the code block until the condition is true.

Finally there is the <tt>case</tt> statement which we'll just include here with a brief example. <tt>case</tt> is actually a very powerful super version of the <tt>if ... elsif...</tt> system

a = rand(11) # Outputs a random integer between 0 and 10 case a when 0..5 puts "#{a}: Low" when 6 puts "#{a}: Six" else puts "#{a}: Cheese toast!" end

There are some other interesting things going on in this example, but here the <tt>case</tt> statement is the center of attention.

= Writing functions =

In keeping with Ruby's all-object-oriented-all-the-time design, functions are typically referred to as methods. No difference. We'll cover methods in much more detail when we get to objects and classes. For now, basic method writing looks something like this (save the following code in a file called func1.rb):

def my_function( a ) puts "Hello, #{a}" return a.length end len = my_function( "Giraffe" ) puts "My secret word is #{len} characters long"
 * 1) Demonstrate a method with func1.rb

now run the script:

$ func1.rb Hello, Giraffe My secret word is 7 characters long

Methods are defined with the <tt>def</tt> keyword, followed by the function name. As with variables, local and class methods should start with a lower case letter.

In this example, the function takes one argument (<tt>a</tt>) and returns a value. Note that the input arguments aren't typed (i.e. <tt>a</tt> need not be a string) ... this allows for great flexibility but can also cause a lot of trouble. The function also returns a single value with the <tt>return</tt> keyword. Technically this isn't necessary -- the value of the last line executed in the function is used as the return value -- but more often than not using <tt>return</tt> explicitly makes things clearer.

As with other languages, <tt>Ruby</tt> supports both default values for arguments and variable-length argument lists, both of which will be covered in due time. There's also support for code blocks, as discussed below.

= Blocks =

One very important concept in Ruby is the code block. It's actually not a particularly revolutionary concept -- any time you've written <tt>if ... {  ... }</tt> in C or Perl you've defined a code block, but in Ruby a code block has some hidden secret powers...

Code blocks in Ruby are defined either with the keywords <tt>do..end</tt> or the curly brackets <tt>{..}</tt>

do  print "I like " print "code blocks!" end {  print "Me too!" }

One very powerful usage of code blocks is that methods can take one as a parameter and execute it along the way.

''[ed note: the Pragmatic Programmers actually want to point out that it's not very useful to describe it this way. Instead, the block of code behaves like a 'partner' to which the function occasionally hands over control]''

The concept can be hard to get the first time it's explained to you. Here's an example:

$ irb --simple-prompt >> '''3.times { puts "Hi!" }''' Hi! Hi! Hi! => 3

Surprise! You always thought 3 was just a number, but it's actually an object (of type <tt>Fixnum</tt>)  As it's an object, it has a member function <tt>times</tt> which takes a block as a parameter. The function runs the block 3 times.

Blocks can actually receive parameters, using a special notation <tt>|..|</tt>. In this case, a quick check of the documentation for <tt>times</tt> shows it will pass a single parameter into the block, indicating which loop it's on:

$ irb --simple-prompt >> 4.times { |x| puts "Loop number #{x}" } Loop number 0 Loop number 1 Loop number 2 Loop number 3 => 4

The <tt>times</tt> function passes a number into the block. The block gets that number in the variable <tt>x</tt> (as set by the <tt>|x|</tt>), then prints out the result.

Functions interact with blocks through the <tt>yield</tt>. Every time the function invokes <tt>yield</tt> control passes to the block. It only comes back to the function when the block finishes. Here's a simple example:

def simpleFunction yield yield end simpleFunction { puts "Hello!" }
 * 1) Script block2.rb

$ block2.rb Hello! Hello!

The <tt>simpleFunction</tt> simply yields to the block twice -- so the block is run twice and we get two times the output. Here's an example where the function passes a parameter to the block:

def animals yield "Tiger" yield "Giraffe" end animals { |x| puts "Hello, #{x}" }
 * 1) Script block1.rb

$ block1.rb Hello, Tiger Hello, Giraffe

It might take a couple of reads through to figure out what's going on here. We've defined the function "animals" -- it expects a code block. When executed, the function calls the code block twice, first with the parameter "Tiger" then again with the parameter "Giraffe". In this example, we've written a simple code block which just prints out a greeting to the animals. We could write a different block, for example:

animals { |x| puts "It's #{x.length} characters long!" }

which would give:

It's 5 characters long! It's 7 characters long!

Two completely different results from running the same function with two different blocks.

There are many powerful uses of blocks. One of the first you'll come across is the <tt>each</tt> function for arrays -- it runs a code block once for each element in the array -- it's great for iterating over lists.

= Ruby is really, really object-oriented =

Ruby is very object oriented. Everything is an object -- even things you might consider constants. This also means that the vast majority of what you might consider "standard functions" aren't floating around in some library somewhere, but are instead methods of a given variable.

Here's one example we've already seen:

3.times { puts "Hi!" }

Even though 3 might seem like just a constant number, it's in fact an instance of the class <tt>Fixnum</tt> (which inherits from the class <tt>Numeric</tt> which inherits from the class <tt>Object</tt>). The method <tt>times</tt> comes from <tt>Fixnum</tt> and does just what it claims to do.

Here are some other examples

$ irb --simple-prompt >> 3.abs => 3 >> -3.abs => 3 >> "giraffe".length => 7 >> a = "giraffe" => "giraffe" >> a.reverse => "effarig"

There will be lots of time to consider how object-oriented design filters through Ruby in the coming chapters.