So, looking deeper at our new program, notice the initial lines, which begin with a
hash mark (#). In Ruby, anything on a line after a hash mark is a
comment and is ignored by the interpreter. The first line of the file
is a special case, and under a Unix-like operating system tells the
shell how to run the file. The rest of the comments are there just
for clarity.
Our say_hi
method has become a bit tricker:
It now looks at the @names
parameter and to make decisions.
If it’s nil, it just prints out three dots. No point
greeting nobody, right?
If the @names
object responds to each
,
it is something that you can iterate over, so iterate over it and
greet each person in turn. Finally, if @names
is anything else,
just let it get turned into a string automatically and do the
default greeting.
Let’s look at that iterator in more depth:
@names.each do |name| puts "Hello #{name}!" endeach
is a method that accepts a block of code then runs that block
of code for every element in a list, and the bit between do
and
end
is just such a block. A block is like an anonymous function
or lambda
. The variable between pipe characters is the parameter
for this block.
What happens here is that for every entry in a list, name
is bound
to that list element, and then the expression puts "Hello #{name}!"
is run with that name.
Most other programming languages handle going over a list using the
for
loop, which in C looks something like:
This works, but isn’t very elegant. You need a throw-away variable
like i
, have to figure out how long the list is, and have to
explain how to walk over the list. The Ruby way is much more
elegant, all the housekeeping details are hidden within the each
method, all you need to do is to tell it what to do with each
element. Internally, the each
method will essentially call
yield "Albert"
, then yield "Brenda"
and then yield "Charles"
,
and so on.
The real power of blocks is when dealing with things that are more
complicated than lists. Beyond handling simple
housekeeping details within the method, you can also handle setup,
teardown, and errors — all hidden away from the cares of the user.
The say_bye
method doesn’t use each
, instead it checks to see if
@names
responds to the join
method, and if so, uses it.
Otherwise, it just prints out the variable as a string. This method
of not caring about the actual type of a variable, just relying on
what methods it supports is known as “Duck Typing”, as in “if it
walks like a duck and quacks like a duck…”. The benefit of this
is that it doesn’t unnecessarily restrict the types of variables
that are supported. If someone comes up with a new kind of list
class, as long as it implements the join
method with the same
semantics as other lists, everything will work as planned.
So, that’s the MegaGreeter class, the rest of the file just calls
methods on that class. There’s one final trick to notice, and that’s
the line:
__FILE__
is the magic variable that contains the name of the current
file. $0
is the name of the file used to start the program. This
check says “If this is the main file being used…” This allows a
file to be used as a library, and not to execute code in that context,
but if the file is being used as an executable, then execute that
code.
So that’s it for the quick tour of Ruby. There’s a lot more to
explore, the different control structures that Ruby offers; the use of
blocks and yield
; modules as mixins; and more. I hope this taste of
Ruby has left you wanting to learn more.
If so, please head on over to our Documentation area,
which rounds up links to manuals and tutorials, all freely available online.
Or, if you’d really like to dig into a book, check the book list (off-site link)
for titles available for sale online or at your local bookseller.