Daniel Carrera <dcarrera / math.umd.edu> wrote:
> I am actually thinking of trying to make a tutorial for precisely this
> purpose.  I'm just getting started, so there's nothing really there yet.
> But you can look at what I here:
> 
> www.math.umd.edu/~dcarrera/ruby/index.html

Perhaps you should introduce IRB right at the beginning, so that people
can play with more immediate examples. (On the other hand, the
ubiquitous return value could be confusing - how hard would a beginner's
mode that outputs something only when asked to be to hack up?).

One suggestion - have an 'Objects' section *before* 'Variables' - start
with defining an object (*don't* introduce the term 'object oriented
programming', or classes - just make it seem like an object is the
natural unit of data storage), and then segue into variables.

Feel free to use as much or as little of the following as you wish:

<<EOF

What is an Object?

An object is a piece of data stored by Ruby. Objects have a /type/ (the
type of data stored in them) and a /value/ (the data itself). Some typical
objects are

Value      Type 
-----------------
   5      Integer  
 3.14     Float
"Hello"   String
[1,2,3]   Array (an array is a collection of objects)

Ruby also provides a rich set of /methods/ and /operators/ to help in
working with its objects. 

Methods:
A method is a function that acts on an object and returns another
object. An example is the 'next' method, which returns an integer that
is one greater than the given integer. Methods are called using the
notation /object.method/ - try the following example

puts 5 # -> 5
puts 5.next # -> 6

The set of methods a given object has depends on its type - for
instance, objects of type Float have no 'next' method

puts 2.3.next # -> undefined method 'next' for 2.3:Float

which tells us that we tried to use a method ('next') on an object of
value 2.3 and type Float, for which there was no 'next' method.

Since the methods an object has depends on its type, the full name of a
method includes both the type name and the method name. The usual
convention in Ruby documentation is to write this in the form
Type#method, so that we can say Integer#next exists, but Float#next
doesn't.

Here are some examples of Ruby's built in methods for Strings:

puts "Hello World" # -> Hello World
puts "Hello World".capitalize # -> HELLO WORLD
puts "Hello World".reverse # -> dlroW olleH
puts "Hello World".length # -> 11

As the last example indicates, the object returned by the method need
not be of the same type as the original object.

Some methods require /arguments/ - these are additional objects passed
to the method in parentheses. For instance, the method String#index
searches a string for another string, and returns the position where
that string is found. However, unlike, say, String#reverse, which just
reverses the original String object, String#index needs to know another
object - the String we want to find. Here's how it's used:

puts "Hello World".index("lo") # -> 3

We call the method String#index of the object "Hello World", and pass it
the additional object "lo" as an argument.

!Note: Since Ruby starts counting from 0, it finds "lo" at position 3
rather than 4

Operators:

An operator is a special kind of method that acts on two objects, and is
called using a symbol rather than a name. An example is the operator
'+', which adds two numbers:

puts 3 + 4 # -> 7

If we were to do this via a conventional method, it would look something
like

puts 3.add(4)

which would do the same thing, but less conveniently.

All the basic arithmetic operators work in Ruby. Try the following:

puts 1 + 2 # -> 3
puts 7 - 2 # -> 5
puts 1.5 * 6 # -> 9.0
puts 5/3 # -> 1

At this point, you may well wonder what is going on in the last example.
The answer is that, like methods, what an operator returns depends on
the types of its /operands/ (the two objects it operates on). The /
operator performs 'integer division' if both its operands are integers,
that is, it rounds down to the nearest integer. If you want floating
point division, at least one of the operands should be a float:

puts 5.0/3 # -> 1.666666667

!Note: Each operator is actually several different methods, depending on
the type of its left hand operand. The two we just saw are, in full,
Integer#/ and Float#/. This is sometimes referred to as 'operator
overloading'.

Thanks to overloading, we can use the arithmetic operators with objects
of other types too, For instance, we have String#+ and String#* as shown:

puts "Hello" + "World" # -> HelloWorld
puts "foo" * 3 # -> foofoofoo

And similarly for Arrays:

p [1,2,3] + [4,5] # -> [1,2,3,4,5]
p ["a", "b"] * 3 # -> ["a", "b", "a", "b", "a", "n"]

!Note: We have introduced the 'p' function - p 'pretty prints' complex
objects like Arrays. To see the difference between 'puts' and 'p', try
the following:
puts [1,2,3]
p [1,2,3]

1
2
3
[1,2,3]

EOF

Then move into the concept of variables, referring always to 'object
type' rather than 'variable type'.

Having introduced variables lets us talk about += and friends, and the !
methods. Then, before moving into flow control, I'd devote a chapter to
a more detailed look at methods,formalising the concepts of a receiver,
arguments and a return value, and showing how methods can be chained
since the return value is just another object.

This would also be a nice place to speak about operator precedence and
parentheses for forcing precedence. Also, be more explicit about what
parallel assignment does, and why it's a nice thing.

martin