old-www/LDP/LG/issue81/ramankutty.html

572 lines
15 KiB
HTML

<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Programming in Ruby, part 1 LG #81</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<CENTER>
<A HREF="http://www.linuxgazette.com/">
<IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png"
WIDTH="600" HEIGHT="124" border="0"></A>
<BR>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="padala.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue81/ramankutty.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="sandeep.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<P>
</CENTER>
<!--endcut ============================================================-->
<H4 ALIGN="center">
"Linux Gazette...<I>making Linux just a little more fun!</I>"
</H4>
<P> <HR> <P>
<!--===================================================================-->
<center>
<H1><font color="maroon">Programming in Ruby, part 1</font></H1>
<H4>By <a href="mailto:hiran_rk@rediffmail.com">Hiran Ramankutty</a></H4>
</center>
<P> <HR> <P>
<!-- END header -->
<H2><B> Introduction </B></H2>
<p>
<p><TD align=right><TD align=left>
Ruby is an interpreted, pure Object Oriented language designed by
Yukihiro Matsumoto of Japan, where it is reported to be more
popular than Python and Perl! The first part of this series is
meant to be a tutorial introduction, with more advanced stuff
in the pipeline.
</TD></TD>
<p>
Of course, I need not go through the ritual of advocating the
`advantages of Ruby compared to languages X, Y and Z' - most people
realize that each language has a unique flavour and character of
its own - whether you choose Python or Ruby for your next open
source project depends more on the peculiar affinity which you as an
individual feel for one over the other, and the availability of
standard library facilities, rather than on arcane technical
issues. So let's enjoy that unique Ruby flavour!
</p>
<H2><B>Requirements</B></H2>
<p>
I presume that your development environment is Linux and you have Ruby installed on
it. Ruby is free software, and there are no restrictions on it's usage. You can
get it from the <a href="http://www.ruby-lang.org"> Ruby Home Page </a>.
</p>
<H2><B>Hello World</B></H2>
<p>
Let's start with the mandatory `Hello, World'.
<pre>
% cat > hello.rb
print "Hello World\n"
^D
% ruby hello.rb
Hello World
%
</pre>
<H2><B>Variables</B></H2>
<p>
Categorization is done on the basis of the first character of the name of the
identifier:
<pre>
$ global variable
@ instance variable
a-z or '_' local variable
A-Z constant
</pre>
<p>
The two `pseudo-variables' are exceptions to the above stated rule. They are `self'
and `nil'.
<ul>
<li> self refers to the currently executing object
<li> nil meaningless or FALSE or value assigned to uninitialized variables
</ul>
<p>
Both are named as if they are local variables, but they are not! We will see their
real meaning later on.
<H2><B>Global variables</B></H2>
<p>
A global variable has it's name starting with $. As such, it can be
referred to from anywhere in the program. It is to be noted that a global variable
assumes the value 'nil' before initialization. You can test this out:
<pre>
% ruby
print $foo,"\n"
$foo = 5
print $foo,"\n"
^D
%
</pre>
The interpreter responds
<pre>
nil
5
</pre>
It is possible for us to `bind' procedures to global variables,
the procedures being automatically invoked when the variable
is changed. More about this later!
<p>
Some special kinds of global variables formed with a single character following a '$'
sign are, as a collection, interpreted by Ruby as major system variables
(made read-only). Some of them are given below along with their meanings.
<ul>
<li> $! latest error message
<li> $@ location of error
<li> $_ string last read by gets
<li> $. line number last read by interpreter
<li> $& string last matched by regexp
<li> $~ the last regexp match, as an array of subexpressions
<li> $n the nth subexpression in the last match (same as $~[n])
<li> $= case-insensitivity flag
<li> $0 the name of the ruby script file
<li> $* the command line arguments
<li> $$ interpreter's process ID
<li> $? exit status of last executed child process
</ul>
<H2><B>Local variables</B></H2>
<p>
A local variable has it's name starting with a lower case letter or an '_'. Unlike
globals and instance variables, they do not assume the value 'nil', but they
behave as shown below:
<pre>
% ruby
print foo
^D
</pre>
You will get an error message:
<pre>
"undefined local variable or method 'foo' for #(object...)".
</pre>
<p>
The scope of a local variable is confined to one of
<ul>
<li> proc {....}
<li> loop {....}
<li> def .... end
<li> class .... end
<li> module .... end
<li> the entire program (unless one of the above applies)
</ul>
If we initialize a local variable in any block(or a procedure), then it remains
undefined after exiting from the loop. For example:
<pre>
def foo(n)
k = 2 * n
print "\n",k,"\n"
print defined? k,"\n"
end
foo 3
print defined? k,"\n"
^D
</pre>
The output is:
<pre>
6
local-variable
nil
</pre>
<p>
In the above example `defined?' is an operator which checks whether it's argument
is defined or not. The results "local-variable" and "nil" (to indicate false) must make it
clear.
</p>
<H2><B>Constants</B></H2>
<p>
Any name with characters following an uppercase letter is treated as a constant. But
Ruby programmers, to avoid confusion, use names with all uppercase letters. So 'Foo' as well
as 'FOO' are constants. As in case of local variables, a constant is defined by a
substitution and an access to an undefined constant or alteration of a defined constant
causes an error. Check for yourself.
<H2><B> Strings </B></H2>
<p>
Strings in ruby can be single quoted('...') or double quoted("...").
But both are different. Use double quotes if the string contains
backslash-escaped characters. Also results of evaluation are
embedded for contained expressions quoted by #{}. See examples:
</p>
<pre>
print "\n"
print '\n'
print "\001","\n"
print '\001',"\n"
print "abcd #{5*3} efg","\n"
var = " abc "
print "1234#{var}567","\n"
^D
\n
\001
abcd 15 efg
1234abc567
</pre>
<p>
We will learn more about strings in the next section, arrays. This is to
include the features that are similar and are held by both arrays and strings.
</p>
<H2><B>Arrays</B></H2>
<p>
Arrays can be quoted using '[]'. One of the features of Ruby is that arrays
are heterogenous.
<pre>
a = [1,2,"3"]
print a,"\n"
^D
</pre>
<p>
Now, if you write a Ruby program to add all the elements of the array shown in the
above program, you will get an error:
<pre>
Error!!String cannot be coerced into Fixnum
</pre>
The `3' in the array is stored as a string. Now, if it is done like this:
<pre>
a = [1,2,"3"]
b = a[0] + a[1] + a[2].to_i
print b,"\n"
^D
</pre>
The program will be executed without any errors. The attachment to a[2] i.e. '.to_i'
is to convert the content of a[2] to an integer.You can also try '.to_s'.
<p>
Operations like concatenation and repetition can be done on arrays.
<pre>
a = [1,2,"3"]
print a + ["foo","bar"]
print a * 2
^D
</pre>
We get
<pre>
123foobar
123123
</pre>
<p>
It's possible to `slice and dice' arrays. Here are some examples:
<pre>
a = [1,2,"3","foo","bar"]
print a[0],"\n"
print a[0,2],"\n"
print a[0..3],"\n"
print a[-2..2],"\n"
print a[-3..-1],"\n"
</pre>
</p>
<p>
Arrays and strings are inter-convertible. An array can be converted to a string
with 'join', and a string is split up into an array with 'split'.
<pre>
a = [1,2,3]
print a[2],"\n"
a = a.join(":")
print a[2],"\n"
print a,"\n"
a = a.split(":")
print a[2],"\n"
print a,"\n"
^D
</pre>
<p>
The Associative Array is another important data structure - it's also
called a `hash' or a `dictionary'. It's basically a name-value mapping,
as shown below:
<pre>
h = {1 => 2, "2" => "4"}
print hash,"\n"
print hash[1],"\n"
print hash["2"],"\n"
print hash[5],"\n"
^D
</pre>
I hope the results are convincing!
</p>
<H2><B>Control structures</B></H2>
<H3><B>If - else</B></H3>
<p>
Let us write the factorial function.The mathematical
definition is:
<pre>
n! = 1 (when n==0)
n! = n * (n-1)! (otherwise)
</pre>
In ruby this can be written as:
<pre>
def fact(n)
if n == 0
1
else
n * fact(n-1)
end
end
print fact 4,"\n"
</pre>
You get 24.
<p>
Ruby has been called `Algol like' because of the repeated
occurrence of `end'. In this recursive call, you may notice the
lack of the return statement. In fact, use of return is
permissible but unnecessary because a ruby function returns
the last evaluated expression (does this sound a wee bit
Lispish? If you insist, you sure can do Lisp in Ruby!)
</p>
<H3><B>The for loop</B></H3>
<p>
<pre>
for i in 0..4
body-of-for
end
</pre>
<p>
Here i is the variable and 0..4 is the range.In the case of
strings, you can very well write:
<pre>
for i in "abc"
</pre>
<H3><B>The while loop</B></H3>
<p>
Try this out
</p>
<pre>
i=0
while i < 10
print i+=1,"\n"
end
</pre>
<H3><B> Case </B></H3>
<p>
We use the case statement to test a sequence of conditions. Try this out.
</p>
<pre>
i = 7
case i
when 1,2..5
print "i in 2 to 5\n"
when 6..10
print "i in 6 to 10\n"
end
^D
</pre>
<p>
You get
</p>
<pre>
i in 6 to 10
</pre>
<p>
2..5 means the range including 2 and 5. It checks whether i falls
within that range.
</p>
<p>
This can be applied to strings as shown below.
</p>
<pre>
case 'abcdef'
when 'aaa','bbb'
print 'contains aaa or bbb \n"
when /def/
print "contains def \n"
end
^D
contains def
</pre>
<p>
Note the slash used with "def". It is used for quoting a regular expression.
We shall see it later.
</p>
<H3><B> Modifications with control structures </B></H3>
<p>
The case statement mentioned just above actually tests for the range
(i in 2..5) as
</p>
<pre>(2..5) === i </pre>
<p>The relationship operator '===' is used by case to check for several
conditions at a time. '===' is interpreted by ruby suitably for the
object that appears in the when condition.
</p>
<p>
Thereby in the example with strings equality is tested with first when
and an expression is matched with the second when.
</p>
<p>
Now try using the operator '===' with if structure(try implementing
functions like isalnum(),isalpha(),isnum() etc.).
</p>
<p>
Your code can be shortened when we have to use if and while constructs
for individual statements: as shown below
</p>
<pre>
i = 7
print "contained in 5..10\n" if (5..10) === i
print i-=1,"\n" while i > 0
^D
contained in 5..10
6
5
4
3
2
1
0
</pre>
<p>
You may at times want to negate the test conditions. An unless is
a negated if, and an until is a negated while. This is left up to you to
experiment with.
</p>
<p>
There are four ways to interrupt the processing of statements of a loop
from inside. First, as in C, break means, to escape from the loop
entirely. Second, next skips to beginning of the next iteration of the
loop (corresponds to continue statement in C). Third ruby has redo,
which restarts the current iteration. The following is C code
illustrating the meanings of break, next, and redo:
</p>
<pre>
while(condition) {
label_redo:
goto label_next; /* ruby's "next" */
goto label_break; /* ruby's "break"*/
goto label_redo; /* ruby's "redo" */
...
...
label_next:
}
label_break:
...
</pre>
<p>
The return statement is actually the fourth way to get out of a loop
from inside. In fact return causes escape not only from the loop
but also from the method that contains the loop.
</p>
<H2><B> Conclusion </B></H2>
We have examined some elementary language features - enough to get
you started with a bit of `quick-and-dirty' coding. As I learn more
about this `gem' of a language, I shall be sharing my experience
with you through future articles. Good bye!
<!-- *** BEGIN bio *** -->
<SPACER TYPE="vertical" SIZE="30">
<P>
<H4><IMG ALIGN=BOTTOM ALT="" SRC="../gx/note.gif">Hiran Ramankutty</H4>
<EM>I am a final year student of Computer Science at Government Engineering
College, Trichur. Apart from Linux, I enjoy learning Physics.</EM>
<!-- *** END bio *** -->
<!-- *** BEGIN copyright *** -->
<P> <hr> <!-- P -->
<H5 ALIGN=center>
Copyright &copy; 2002, Hiran Ramankutty.<BR>
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
Published in Issue 81 of <i>Linux Gazette</i>, August 2002</H5>
<!-- *** END copyright *** -->
<!--startcut ==========================================================-->
<HR><P>
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="padala.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue81/ramankutty.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../lg_faq.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="sandeep.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->