A Ruby introduction

Sebastien Tanguy

$Id: ruby.xml 33 2007-01-14 18:58:38Z stanguy $


Table of Contents

1. Introduction

This article is meant to be an introduction to the ruby programming language for programmers already knowledgeable of various languages like Perl, Python, C++ or Java. This is also a simple collection of notes taken while learning the language.

As a reference, we just use the user's guide written by the author of ruby: matz

2. The basic language

The syntax of the ruby programming language is somewhat similar to those of Perl and Python, but compared to the former, it has lost the C-like syntax using braces ({}) but rather than being a indentation oriented language like Python, it uses the keyword end in order to mark code sections, but it keeps the end-of-line as the marker of the end of an instruction

Example 1. Basic block structure in Perl

Example 2. Basic block structure in Python

Example 3. Basic block structure in Ruby

Both languages keep the character # to introduce a comment up to the end of line. Note that unlike python, the print instruction does not print a line feed, just like it does with Perl.

We can also find the same data structures in both languages. Note that although Ruby use specific prefixes ($ and @) for some variables, it only affects their access and not their data type. Just like Perl or python, we have simple variables (integers, strings), arrays (or lists) and dictionaries (or hashes, or associative array).

Example 4. Simple types in Perl

Example 5. Simple types in Python

Example 6. Simple types in Ruby

Note that however, Ruby tries very hard to be an object language, so even basic types are objects, as can be seen by the following example:

Example 7. Integers are objects

ruby> 12.is_a? Object
   true

As we have seen in the first example, the languages share naturally the same basic control structures, if, while, for. Note that Ruby offers various method to iterate over a collection.

Example 8. Perl control structures

Example 9. Python control structures

Example 10. Ruby control structures

This can also be written:

or even

Note that unlike both Perl and Python, Ruby offers a switch structure, while other languages only make use of a number of if.

Example 11. Ruby switch (case) structure

One thing we left is the syntax of variables. Basic local scope variables use “simple” names, which only need to be in lowercase. Names starting with an upper case character define constants (and thus their value cannot be modified). Global variables are prefixed by the $ sign. We will come back later to this point, but member variables are prefixed by the @ sign.

Example 12. Global variable example

ruby> foo = 1                    
   1
ruby> $foo = 2
   2
ruby> def bar()
    |    if defined? foo
    |       print "local value: ", foo, "\n"
    |    end
    |    if defined? $foo
    |       print "global value: ", $foo, "\n"
    |    end
    | end
   nil
ruby> bar
global value: 2
   nil

3. Functions and objects

With a syntax similar to the one used by Python, defining functions or procedures is done with the def keyword (and ended the usual way for Ruby blocks).

Example 13. Basic function

Note that you don't have to put a return statement, as Ruby will always return the last value.

Example 14. Functions returns their last expression

ruby> def foo( bar )    
    |    42
    | end
   nil
ruby> foo 12
   42

A function or method can use characters like ? or ! in their name, meaning usually that it returns a boolean (as an answer to a question) or that it modifies the object.

Example 15. Using ? and ! in function names

ruby> "foo".delete "o"
   "f"
ruby> f = "foo"
   "foo"
ruby> f.empty?
   false
ruby> f.delete "o"
   "f"
Note that the original object wasn't modified, but only the return value
ruby> f
   "foo"
ruby> f.delete! "o"
   "f"
ruby> f
   "f"

A class is simply defined using the keyword class. Methods of the class are defined as functions inside its definition. Static methods are considered as methods of the class itself and not methods of the instances. To define such a method, we only need to prefix it by the name of the class.

Example 16. Defining methods

Calling this program gives:

[seb@disease] % ruby rmethods.rb 
foobar
barfoo

Note also that Ruby unlike most usual languages makes heavy use of mixins: You can define a class in different parts, but you can also import inside a class a comportment defined by a module. This is most useful for using design patterns. For example, the following code sample shows how to create a simple Observer pattern.

Example 17. Subscribe/Publish design pattern

Reading the previous example, you can see several elements of the Ruby programing language: The constructor is named initialize, you don't need to reference the current instance the class (unlike Python where you would define and use self) but when you have to, just like Python, it is called self, You create instances using the class factory method named new.

Previously, we saw that member variables are prefixed by the @ sign, but this syntax can only be used inside methods of the class. Class (or static) variables are prefixed by @@. Instance variables can't be accessed this way, but sometimes, it may be useful to add accessors to those. Instead of writing methods for each case, Ruby provides keywords: attr_reader, attr_writer, attr_accessor for read, write, and both-way access.

Example 18. Accessors example

4. User interaction

Note

I won't talk here about building interfaces or programs interacting with a user, but instead I will talk about learning the language in a quick and (almost) painless way

Perl is famous for its one-liners, allowing us to write a small (or not so small) program on the command line. It is powerful. But it is not much interactive, you can just execute the code. Python has a interpreter. But Python is also a reflexive language. That means that we can observe and explore into our objects; For example, we have a dir() function which lists the methods and variables of an object.

Well, that is handy, but not really clean, isn't it? Ruby fancies itself to be a more object-oriented language. In fact, the Object class from which every other class inherits provides nice functions for everything you want to know about an object or class.

But the problem is that if you try to run the ruby command, it will run almost like the Perl interpreter and won't be friendly at all for interaction. Instead, for a python-like interpreter, you should use irb (which stands for “interactive ruby”).

Another good thing for Ruby is that classes are open. What does it mean? If I have a class, I can always re-enter its definition to add new methods or attributes.

Example 19. Class definition using irb

irb(main):001:0> class Foo
irb(main):002:1>   def bar()
irb(main):003:2>   end
irb(main):004:1> end
=> nil
irb(main):005:0> f = Foo.new()
=> #<Foo:0x326138>
irb(main):006:0> f.bar
=> nil

So, we have defined a class with a method. But we think about it, and finally, we would like to add another method.

irb(main):007:0> class Foo
irb(main):008:1>   def quux()
irb(main):009:2>   end
irb(main):010:1> end
=> nil
irb(main):011:0> f.quux
=> nil
irb(main):012:0> f.bar
=> nil

Notice how the new method is already available to our previously created object. Writing the same thing in Python, we wouldn't have the new method available in this object and any object created later would have no definition of the first class.