![]() Prev |
![]() Contents |
![]() Next |
Ruby user's guide | Back to the simple examples |
Now let's take apart the code of some of our previous example programs.
The following appeared in chapter 3.
def fact(n) if n == 0 1 else n * fact(n-1) end end print fact(ARGV[0].to_i), "\n"
Because this is the first explanation, we examine each line individually.
def fact(n)
In the first line, def
is a statement to define a
function (or, more precisely, a method; we'll talk more about
what a method is in chapter 11). Here, it
specifies that the function fact
takes a single argument,
referred to as n
.
if n == 0
The if
is for checking a condition. When the condition
holds, the next line is evaluated; otherwise whatever follows the
else
is evaluated.
1
The value of if
is 1 if the condition holds.
else
If the condition does not hold, the code from here to end
is
evaluated.
n * fact(n-1)
If the condition is not satisfied, the value of if
is
the result of n
times fact(n-1)
.
end
The first end
closes the if
statement.
end
The second end
closes the def
statement.
print fact(ARGV[0].to_i), "\n"
This invokes our fact()
function using a value specified
from the command line, and prints the result.
ARGV
is an array which contains command line arguments.
The members of ARGV
are strings, so we must convert this into a
integral number by to_i
. Ruby does not convert strings into
integers automatically like perl does.
Hmmm... what would happen if we fed this program a negative number? Do you see the problem? Can you fix it?
Next we examine the puzzle program from chapter 4. As this is somewhat longer, we number the lines for reference.
1 words = ['foobar', 'baz', 'quux'] 2 srand() 3 secret = words[rand(3)] 4 5 print "guess? " 6 while guess = STDIN.gets 7 guess.chop! 8 if guess == secret 9 print "you win\n" 10 break 11 else 12 print "you lose.\n" 13 end 14 print "guess? " 15 end 16 print "the word is ", secret, ".\n"
In this program, a new control structure, while
, is
used. The code between while
and its corresponding
end
will execute repeatedly as long as some specified
condition remains true.
srand()
in line 2 initializes a random number
generator; then rand(3)
in line 3 returns a random number
in the range 0 to 2. This random number is used to extract one
of the members of the array words
.
In line 6 we read one line from standard input by the method
STDIN.gets
. If EOF (end of file) occurs
while getting the line, gets
returns
nil
. So the code associated with this
while
will repeat until it sees ^D (or
^Z under DOS), signifying the end of input.
guess.chop!
in line 7 removes the last character from
guess
; in this case it will always be a newline
character.
In line 16 we print the secret word. We have written this as
a print statement with three arguments (which are printed one after
the other), but it would have been equally effective to do it with a
single argument, writing secret
as #{secret}
to make it clear that it is a variable to be evaluated, not a literal
word to be printed:
print "the word is #{secret}.\n"
Finally we examine the program in chapter 5 that tested regular expressions.
1 st = "\033[7m" 2 en = "\033[m" 3 4 while TRUE 5 print "str> " 6 STDOUT.flush 7 str = gets 8 break if not str 9 str.chop! 10 print "pat> " 11 STDOUT.flush 12 re = gets 13 break if not re 14 re.chop! 15 str.gsub! re, "#{st}\\&#{en}" 16 print str, "\n" 17 end 18 print "\n"
In line 4, the condition for while
is hardwired to
true
, so it forms what looks like an infinite loop.
However we put break
statements in the 8th and 13th lines to
escape the loop. These two break
s are also an example
of if
modifiers. An "if
modifier" executes the
statement on its left hand side if and only if the specified
condition is satisfied.
There is more to say about chop!
(see lines 9 and
14). In ruby, we conventionally attach '!
' or
'?
' to the end of certain method names. The
exclamation point (!
, sometimes pronounced aloud as
"bang") indicates something potentially destructive, that is to say,
something that can change the value of what it touches.
chop!
affects a string directly, but chop
with no exclamation point works on a copy. Here is an
illustration of the difference.
ruby> s1 = "forth" "forth" ruby> s1.chop! # This changes s1. "fort" ruby> s2 = s1.chop # This puts a changed copy in s2, "for" ruby> s1 # ... without disturbing s1. "fort"
You will later come across method names that end in a question mark
(?
); this indicates a "predicate" method, one that can
return either true
or false
.
Line 15 deserves some careful attention. First, notice that
gsub!
is another so-called destructive method. It
changes str
by replacing everything matching the pattern
re
(sub
means substitute, and the
leading g
means global, i.e., replace all
matching parts in the string, not just the first one found). So
far, so good; but what are we replacing the matched parts of the text
with? st
and en
were defined in lines 1-2
as the ANSI sequences that make text color-inverted and normal,
respectively. In line 15 they are enclosed in #{}
to ensure that they are actually interpreted as such (and we do not
see the variable names printed instead). Between these
we see "\\&
". This is a little tricky.
Since the replacement string is in double quotes, the pair of
backslashes will be interpreted as a single backslash; what
gsub!
actually sees will be "\&
", and
that happens to be a special code that refers to whatever matched the
pattern in the first place. So the new string, when printed,
looks just like the old one, except that the parts that matched the
given pattern are highlighted in inverse video.
![]() Prev |
![]() Contents |
![]() Next |