This document was uploaded by user and they confirmed that they have the permission to share
it. If you are author or own the copyright of this book, please report to us by using this DMCA
report form. Report DMCA
Ruby User's Guide Introduction Ruby is `an easy object oriented language'. It may seem a little strange at first, but it is designed to be easily read and written. In this "Ruby User's Guide" you will become experienced at invoking ruby. In addition we will sometimes delve further into ruby's nature than in the reference manual.
Getting started Characteristics of ruby Simple examples Strings Regular expressions Arrays and associative arrays Simple examples again Control structures What is an iterator? Introduction to object orientedness Methods Classes Inheritance Redefinition of methods More on methods (for access control) Singleton method Modules Procedure objects Variables Global variables Instance variables Local variables Class constants Exception processings Don't forget to close the door (ensure)
Translator's note This is translated from the original version in Japanese by matz. Any questions for this document are welcome. There is also Ruby Language Reference Manual written by the author of ruby. Check it out. Thanks!
Translators GOTO Kentaro & Julian Fondren Correspondence should be addressed to GOTO Kentaro: [email protected]
First, check whether ruby is installed or not. In the following shell prompt (we denote shell prompt by `% ', so you should not type `% '), type % ruby -v
(`-v' tells the interpreter to print the version of ruby), then press the ENTER key. If the next message are displayed, ruby is installed (version, date and platform may be different) % ruby -v ruby 1.1b5(98/01/19) [i486-linux]
When ruby is not installed, ask your administrator to install it. Of course you can do it yourself, ruby is free software so you can get it with no cost, and you have no restrictions on installation and it's use. Now, let's play with ruby. You can specify the program on command line with the `-e' option. % ruby -le 'print "hello world\n"' hello world
A program of ruby can be stored in a file of course. % cat > test.rb print "hello world\n" ^D % cat test.rb print "hello world\n" % ruby test.rb hello world
(^D is control-D) Ruby has a number of command line options which may be useful. Major options are listed here: 0[DIGIT] paragraph mode a auto split mode c syntax checking only e SCRIPT specifies the SCRIPT on command line F`DELIMITOR' specifies delimitor i[extention] in-place editing mode I DIRECTORY specities load path l remove NEWLINE from input and put NEWLINE to output n automatic loop p automatic loop with output v prints version, verbose mode For example, % ruby -i.bak -pe 'sub "foo", "bar"' *.[ch]
means "replace `foo' into `bar' for all C files, preserving the original ones under name with `.bak'
`cat' whose longer name. Also it is slower than `cat' :-)
Characteristics of Ruby
We will try to list the characteristics of ruby. The catch phrase of ruby is `an interpreted scripting language for quick and easy object-oriented programming'. Let's examine certain feautures of ruby which support this slogan. !
!
!
!
quick and easy " interpreted " variables aren't typed " variable declaration unnecessary " simple syntax " memory managing unnecessary for OOP " everything is an object " classes, inheritance, methods, etc... " singleton method " Mixin by module " iterator and closure scripting language " interpreter " powerful string operations and regular expressions " enable to access to OS directly misc... " multiple precision integers " exception processing model " dynamic loading
Do you understand what sort of language ruby is? Don't worry about unknown concepts above since they will be explained in this guide.
Simple examples
Now, we begin to start with a sample. First, let's consider a common example, the factorial function. The mathematical definition of the n factorial is: n! = 1
It is written in ruby as def fact(n) if n == 0 1 else n * fact(n-1) end end
You may notice many occurrences of `end'. Someone said `Algol-like' by the historical reason. Actually, the syntax of ruby is mimic the langage which is named Eiffel. You may also find lack of `return'. It works since ruby's `if' has its value. Of course, appending `return' is allowed, however, in case of without `return' it is faster rather than in case of returning by `return'. Let's use this. Append the following line to the end of above program and save it into file, say `fact.rb'. print fact(ARGV[0].to_i), "\n" Here, `ARGV' is an array which contains command line argument, and `to_i' is method to convert to integer. % ruby fact.rb 4 24
Does it work with argument of 40? It makes the calculator overflow... % ruby fact.rb 40 815915283247897734345611269596115894272000000000
It worked. Indeed, ruby can deal with any integer which is allowed by your machines memory. So 400 can be obtained. % ruby fact.rb 400 64034522846623895262347970319503005850702583026002959458684 44594280239716918683143627847864746326467629435057503585681 08482981628835174352289619886468029979373416541508381624264 61942352307046244325015114448670890662773914918117331955996 44070954967134529047702032243491121079759328079510154537266 72516278778900093497637657103263503315339653498683868313393 52024373788157786791506311858702618270169819740062983025308 59129834616227230455833952075961150530223608681043329725519 48526744322324386699484224042325998055516106359423769613992 31917134063858996537970147827206606320217379472010321356624 61380907794230459736069956759583609615871512991382228657857 95493616176544804532220078258184008484364155912294542753848 03558374518022675900061399560145595206127211192918105032491 00800000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000
We cannot check the correctness with a glance, but it must be right :-) When you invoke ruby without an argument ruby reads a script from standard input then executes them after the end of input. % ruby print "hello world\n" print "good-bye world\n" ^D hello world good-bye world
However, you may want to use it as a shell. Using the following program, you can execute line by line. It
isn't necessary to understand this program. line = '' indent=0 print "ruby> " while TRUE l = gets if not l break if line == '' else line = line + l if l =~ /,\s*$/ print "ruby| " next end if l =~ /^\s*(class|module|def|if|case|while|for|begin)\b[^_]/ indent += 1 end if l =~ /^\s*end\b[^_]/ indent -= 1 end if l =~ /\{\s*(\|.*\|)?\s*$/ indent += 1 end if l =~ /^\s*\}/ indent -= 1 end if indent > 0 print "ruby| " next end end begin print eval(line).inspect, "\n" rescue $! = 'exception raised' if not $! print "ERR: ", $!, "\n" end break if not l line = '' print "ruby> " end print "\n"
Save this to a file `eval.rb', and run it (Actually, it is contained in `sample' directory in the source of ruby.) % ruby eval.rb ruby> print "hello world\n" hello world nil ruby> ^D
`hello world' in the second line is output by `print' and next `nil' is returned value of `print'. `nil' means `void (meaningless) value', it is used if the return value is not used e.g. `print'. Anyhow, this short program is useful. Throughout this guide, `ruby> ' denotes input for this program. (There is a program named `rbc.rb' in the sample directory, which is more useful. Please try it.)
Strings
Ruby deals with not only numerals but also strings. A string is something double-quoted ("...") or single-
Differences between double-quoted and single-quoted are as follows. In double-quoted form, various expressions leaded by backslash (\) are available, and also the results of evaluation are embedded for contained expressions quoted by #{}. See examples: ruby> "\n" "\n" ruby> '\n' "\\n" ruby> "\001" "\001" ruby> '\001' "\\001" ruby> "abcd #{5*3} efg" "abcd 15 efg" ruby> var = " abc " " abc " ruby> "1234#{var}5678" "1234 abc 5678"
Ruby's string is smarter than C's one. For instance, concatenating is denoted by `+', repeating of n times is denoted by `* n'. ruby> "foo" + "bar" "foobar" ruby> "foo" * 2 "foofoo"
It would be written in C as follows. char *s = malloc(strlen(s1)+strlen(s2)+1); strcpy(s, s1); strcat(s, s2);
We are free from even any memory management; We do not even have to consider the spaces spent by a string. Strings in ruby have a lot of features, while only a part of them are introduced here. Concatenation ruby> word = "fo" + "o" "foo"
Repetition ruby> word = word * 2 "foofoo"
Picking up a character (characters are integers in ruby) ruby> word[0] 102 # 102 is ASCII code of `f' ruby> word[-1] 111 # 111 is ASCII code of `o'
Note: The above examples are results for ruby 1.0. For ruby 1.1, results are reported in lower case, i.e., true, false. Now, let's make a ``pazzle'' with these features. This puzzle is `Guessing the word'. The word ``puzzle'' is too dignified for what is to follow ;-) words = ['foobar', 'baz', 'quux'] srand() word = words[rand(3)] print "guess? " while guess = STDIN.gets guess.chop! if word == guess print "you win\n" break else print "you lose.\n" end print "guess? " end print "the word is ", word, ".\n"
You don't have to understand details of this program. A result of execution is as follows. (my answer is preceeded by guess?) guess? foobar you lose. guess? quux you lose. guess? ^D the word is baz.
Oh, I had many mistakes despite the 1/3 probability. It is not exciting -- it is not good example...
Regular expressions
I'll try to make a more interesting pazzle. This time, we test whether or not a string matches another string, say pattern. In order to be useful, we import some characters with special meaning into patterns. The following are special characters.
range specification. (e.g., [a-z] means a letter in range of from a to z) letter or digit. same as [0-9A-Za-z_] neither letter nor digit blank character. same as [ \t\n\r\f] non-space character. digit character. same as [0-9]. non digit character. word boundary (outside of range specification). non word boundary. back spage (0x08) (inside of range specification) zero or more times repetition of followed expression zero or one times repetition of followed expression at least n times, but not more than m timesrepetition of followed expression at least 0 times, but not more than 1 timesrepetition of followed expression eather followed or leaded expression grouping
For example, `^f[a-z]+' means "repetition of letters in range from `a' to `z' which is leaded by `f'" Special matching characters like these are called `reguler expression'. Regular expressions are useful for string finding, so it is used very often in UNIX environment. A typical example is `grep'. To understand regular expressions, let's make a little program. Store the following program into a file named `regx.rb' and then execute it. Note: This program works only on UNIX because this uses reverse video escape sequences. st = "\033[7m" en = "\033[m" while TRUE print "str> " STDOUT.flush str = gets break if not str str.chop! print "pat> " STDOUT.flush re = gets break if not re re.chop! str.gsub! re, "#{st}\\{en}" print str, "\n" end print "\n"
This program requires input twice and reports matching in first input string to second input regular expression by reverse video displaying. Don't mind details now, they will be explained. str> foobar pat> ^fo+ foobar ~~~
# foo is reversed and ``~~~'' is just for text-base brousers. Let's try several inputs. str> abc012dbcd555 pat> \d abc012dbcd555 ~~~ ~~~
This program detect multiple muchings. str> foozboozer pat> f.*z foozboozer
`fooz' isn't matched but foozbooz is, since a regular expression maches the longest substring. This is too diffucult of a pattern to recognize at a glance. str> Wed Feb 7 08:58:04 JST 1996 pat> [0-9]+:[0-9]+(:[0-9]+)? Wed Feb 7 08:58:04 JST 1996 ~~~~~~~~
In ruby, a regular expression is quoted by `/'. Also, some methods convert a string into a regular expression automatically. ruby> 3 ruby> 3 ruby> FALSE ruby> FALSE
`=~' is a matching operator with respected to regular expression; it returns the position when matched.
Arrays and associative arrays
Ruby also deals with arrays. We can make an array by quoting with `[]'. Ruby's arrays are capable of containing many types of objects. ruby> ary = [1, 2, "3"] [1, 2, "3"]
Arrays can be concatenated or repeated in the same manner as strings. ruby> ary + [1, 2, "3", ruby> ary * [1, 2, "3",
["foo", "bar"] "foo", "bar"] 2 1, 2, "3"]
We can get a part of a array. ruby> ary[0] 1 ruby> ary[0,2] [1, 2] ruby> ary[0..1] [1, 2] ruby> ary[-2] 2 ruby> ary[-2,2] [2, "3"] ruby> ary[-2..-1] [2, "3"]
Arrays and Strings are convertable. An array converts into a string with `join', and a string is split into an
Assosiative arrays are another important data structure. An associative array is an array with keys which can be valued in any way. Assosiative arrays are called hashes or dictionaries. In ruby world, we usually use hash. A hash is constructed by a `{ }' form. ruby> hash = {1 => 2, "2" => "4"} {1=>2, "2"=>"4"} ruby> hash[1] 2 ruby> hash["2"] "4" ruby> hash[5] nil ruby> hash[5] = 10 # appending value ruby> hash {5=>10, 1=>2, "2"=>"4"} ruby> hash[1] = nil # deleting value nil ruby> hash[1] nil ruby> hash {5=>10, "2"=>"4"}
Thanks to arrays and hashes, we can make data containers easily.
Simple examples again
Ok, I will give explanations for more details of ruby programming. First, we see some 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 it line by line. def fact(n)
In the first line, `def' is a statement to define a function or method. Here, it defines that the function `fact' takes `n' as it's one argument. if n == 0
In the second line, `if' is for checking a condition. When the condition holds execute the next line, or execute below of `else' otherwise. 1
It means the value of `if' is 1 if the condition holds. else
If the condition doesn't hold, here to `end' is evaluated. n * fact(n-1)
When the condition is not satisfied, the value of `if' is the result of n times fact(n-1). end
`if' statement is closed by `end'. end
`def' statement is closed by `end' too. print fact(ARGV[0].to_i), "\n"
This outputs the result of fact() respecting to a value specified from the command line. 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 doesn't convert strings into integers automatically like perl does. Next we see the pazzle appearing in the chapter on strings. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
words = ['foobar', 'baz', 'quux'] srand() word = words[rand(3)] print "guess? " while guess = STDIN.gets guess.chop! if word == guess print "you win\n" break else print "you lose.\n" end print "guess? " end print "the word is ", word, ".\n"
If you are programmer it may be clear, but here is an explanation. In this program, a new control structure `while' is used. By `while', we execute the range up to `end' while the condition returns true. `srand()' in the 2nd line is to initialize for random numbers. `rand(3)' in the 3rd line returns a random number with at most 3, i.e., `rand(3)' is valued 1,2, and 3. In the 6th line, this program reads one line from standard input by the method `STDIN.gets'. If EOF (endof-line) occures while getting line, `gets' returns nil. So this `while' is to repeat until inputing `^D' (controlD). `guess.chop!' in the 7th line remove the last character from input. In this case, `new line' is removed. Last, we look the program for regular expressions.
st = "\033[7m" en = "\033[m" while TRUE print "str> " STDOUT.flush str = gets break if not str str.chop! print "pat> " STDOUT.flush re = gets break if not re re.chop! str.gsub! re, "#{st}\\{en}" print str, "\n" end print "\n"
Because `while TRUE' in the 4th line has the condition TRUE for `while' it forms an infinite loop. However, we don't expect infinite repetition, so we put `break' in 8th and the 13th lines to escape this `while' loop. These two `break's are also an example of the `if' modifier. An `if' modifier executes the statement on the left hand side of `if' when the condition is preceeded by `if' `chop!' in the 9th and the 14th lines or `gsub!' in the 15th line are method whose name contains `!'. In ruby, we can attach `!' or `?' to end of name of method. Actually, a name of method doesn't cause any effect to function of the method. It is a convention that we give a name with `!' to a destructive (changing state of the receiver) mathod. Also we give a name with `?' to a predicate (returning true or false) method. For example, `chop!' removes the last character of the string, and `gsub!' replaces the substring matching the regular expression specified by first argument with the second argument string. In the second argument "#{st}\\{en}" of `gsub!' in the 15th line, `\&' occurs. This means to expand substring matching regular expression here. Remember that a backslash is expanded in a double-quoted string. So one more backslash is needed here.
Control structures
This chapter shows ruby's control structures. We have seen `if', `while' and `break' already. Others are shown here. We know of an `if' modifier, there is also a `while' modifier. ruby> i = 0; print i+=1, "\n" while i < 3 1 2 3 nil
We use the `case' statement to check for many options. It will be written as follows: ruby> ruby| ruby| ruby| ruby| ruby|
case i when 1, 2..5 print "1..5\n" when 6..10 print "6..10\n" end
where `2..5' is an expression which means the range between 2 and 5. In above example, the result of the following expression is used to decide whether or not `i' is in the range as follows. (2..5) === i
As this instance, `case' uses the relationship operator `===' to check for each conditions at a time. By ruby's object oriented features, the relationship operator `===' is interpreted suitably for the object appeared in the `when' condition. For example, ruby> case 'abcdef' ruby| when 'aaa', 'bbb' ruby| print "aaa or bbb\n" ruby| when /def/ ruby| print "includes /def/\n" ruby| end includes /def/ nil
tests equality as strings or string matching to regular expressions. There are three controls to escape from a loop. `break' means, as in C, to escape from the loop. `next' corresponds to `continue' in C, and is used for skipping the rest of loop once and going to the next iteration. Additionally, ruby has `redo', which executes the current iteration again. The following C code is witten in order to help C users undestand. while (condition) { label_redo: goto label_next goto label_break goto label_redo ; ; label_next: } label_break: ;
/* next */ /* break */ /* redo */
The last way is `return'. A evaluation of `return' causes escaping. If an argument is given it will be the return value, otherwise ruby assumes that an argument `nil' is given. One more repetition control structure is left, that is `for'. It is used as follows. for i in obj ... end
The `for' statement iterates up to `end' for each elements of 'obj', with substituting each of them to the variable `i'. This is the alternative form of the iterator, which will be mentioned later. See the following for example of iterator. obj.each {|i| ... }
Both of above two forms are equivalent, but you may understand `for' more than `each'. It is one of the reasons that `for' exists.
An iterator isn't an original concept in ruby. It is a of feature CLU, which is popular among some people. In Lisp, iterators are often used whereas they aren't called iterators. However the concepet of iterator is an unfamiliar one for many so it should be explained in more detail. The verb `iterate' means "do the same thing many times', you know, so `iterator' means "one which does the same thing many times'. Writing code, we often put loops into them in various situations. In C, we use them as `for' or `while'. For example, char *str; for (str = "abcdefg"; *str; str++) { /* process for each chars here */ }
The part of `for(...)' is a sort of idiom, but it requires some knowledge of internal data from us and is so irksome. A programmer is required to know about internal structure when in a simple loop; That's why we feel the language be low level. Some higher level languages have control structures to iterate. Consider the following example of `sh'. (You may ask me, "Is `sh' higher than `C'?" Ok, it is right at least in this problem...) for i in *.[ch]; do # something to do for each file done
In this case, `sh' undertakes detailsome, pick up and substitute file names one by one. I think this is higher level rather than C, don't you? But there are more problems. It is good that a language deals with iterations for built-in data types, but we are disappointed again if we must write low level loops, like in C, for data types defined by user :-( In OOP, users often define one data type after another, so this problem is serious. To solve above matters, every OOP language has elaborate ways to make iterations easy, for example some languages provide class controlling iteration, etc. On the other hand, ruby allows us to define control structures directly. In term of ruby, such user-defined control structures are called iterators. Some examples are showed below. Ruby's string type has some iterators, so it's apt. ruby> "abc".each_byte{|c| printf "<%c>", c}; print "\n" nil