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