Edition

Transcription

2nd EditionYOUR FREE GUIDE TO PROGRAMMING RUBYFROM SAPPHIRESTEEL SOFTWAREWWW.SAPPHIRESTEEL.COM

The Little Book Of Ruby :: :: www.sapphiresteel.com :: page 2The Little Book Of RubyCopyright 2008 Dark Neon Ltd.All rights reserved.written byHuw CollingbourneDownload source code Of-RubyYou may freely copy and distribute this eBook as long as you do not modify the textor remove this copyright notice. You must not make any charge for this eBook.The Little Book of Ruby is produced in association with SapphireSteel Software,makers of the Ruby In Steel IDE for Visual Studio (www.sapphiresteel.com).(First edition: June 2006)Second edition: March 2008

The Little Book Of Ruby :: :: www.sapphiresteel.com :: page 3Table of ContentsWelcome To The Little Book Of Ruby.5Learn Ruby In Ten Chapters . 5What Is Ruby? . 5What Is Rails? . 5Installing And Using Ruby With Ruby In Steel . 6Installing Ruby Yourself . 6Get The Source Code Of The Sample Programs . 6Running Ruby Programs . 7How To Use This Book . 7Making Sense Of The Text. 7Chapter One .9Strings and Embedded Evaluation . 12Methods . 13Numbers . 15Testing a Condition: if then . 16Chapter Two .18Instances and Instance Variables . 19Constructors – new and initialize. 22Inspecting Objects. 24Chapter Three.26Superclasses and Subclasses . 29Chapter Four .31Accessor Methods . 31Attribute Readers and Writers . 33Attributes Create Variables . 35Calling Methods of a Superclass . 38Class Variables . 39Chapter Five .41Using Arrays . 41Creating Arrays. 42Multi-Dimensional Arrays . 44Iterating Over Arrays . 46Indexing Into Arrays . 47

The Little Book Of Ruby :: :: www.sapphiresteel.com :: page 4Chapter Six .49Creating Hashes . 49Indexing Into A Hash . 51Hash Operations . 52Chapter Seven .54For Loops . 54Blocks. 58While Loops. 59While Modifiers . 60Until Loops . 63Chapter Eight .65If.Then.Else . 66And.Or.Not. 68If.Elsif. 69Unless . 71If and Unless Modifiers. 71Case Statements . 73Chapter Nine .76A Module Is Like A Class . 76Module Methods. 77Modules as Namespaces. 78Module ‘Instance Methods’ . 80Included Modules or ‘Mixins’. 80Including Modules From Files . 82Pre-Defined Modules . 83Chapter Ten .84IronRuby and JRuby. 84Saving Data. 85YAML . 85Files . 86Moving On. 87

The Little Book Of Ruby :: Welcome To The Little Book Of Ruby ::www.sapphiresteel.com :: page 5WELCOME TO THE LITTLE BOOK OF RUBYLearn Ruby In Ten Chapters Chapter One :Chapter Two:Chapter Three:Chapter Four:Chapter Five:Chapter Six:Chapter Seven:Chapter Eight:Chapter Nine:Chapter Ten:Strings and MethodsClasses and ObjectsClass HierarchiesAccessors, Attributes, Class VariablesArraysHashesLoops and IteratorsConditional StatementsModules and MixinsSaving Files, Moving On What Is Ruby?Ruby is a cross-platform interpreted language which has many features incommon with other ‘scripting’ languages such as Perl and Python. However,its version of object orientation is more thorough than those languages and, inmany respects, it has more in common with the great-granddaddy of ‘pure’OOP languages, Smalltalk. The Ruby language was created by YukihiroMatsumoto (commonly known as ‘Matz’) and it was first released in 1995.What Is Rails?Currently much of the excitement surrounding Ruby can be attributed to aweb development framework called Rails – popularly known as ‘Ruby OnRails’. While Rails is an impressive framework, it is not the be-all and end-allof Ruby. Indeed, if you decide to leap right into Rails development without

The Little Book Of Ruby :: Welcome To The Little Book Of Ruby ::www.sapphiresteel.com :: page 6first mastering Ruby, you may find that you end up with an application thatyou don’t even understand. While the Little Book of Ruby won’t cover thespecial features of Rails, it will give you the grounding you need tounderstand Rails code and write your own Rails applications.Installing And Using Ruby With Ruby In SteelRuby In Steel is a Windows-based IDE which comes with an all-in-oneinstaller to install Ruby, Visual Studio, Ruby In Steel and various otheroptional packages including Rails. Be sure to read the installation guideprovided with the software: http://www.sapphiresteel.com.Installing Ruby YourselfIf you are using some other IDE or editor, you will need to download thelatest version of Ruby from www.ruby-lang.org. Be sure to download thebinaries (not merely the source code).Get The Source Code Of The Sample ProgramsAll the programs in every chapter in this book are available for download as aZip archive from by. Whenyou unzip the programs you will find that they are grouped into a set ofdirectories – one for each chapter. If you are using Ruby In Steel, you will beable to load all the programs as a single solution, with the programs for eachchapter arranged on the branches of a tree in the Project Manager.

The Little Book Of Ruby :: Welcome To The Little Book Of Ruby ::www.sapphiresteel.com :: page 7Running Ruby ProgramsIt is often useful to keep a Command window open in the source directorycontaining your Ruby program files. Assuming that the Ruby interpreter iscorrectly pathed on your system, you will then be able to run programs byentering ruby program name like this:ruby 1helloworld.rbIf you are using Ruby In Steel you can run the programs in the interactiveconsole by pressing CTRL F5 or (in some editions) you may run them in thedebugger by pressing F5.How To Use This BookThis book is a step-by-step tutorial to programming in Ruby and you canfollow it chapter by chapter, reading the text and running the sampleprograms. On the other hand, if you prefer to ‘dip in’, you may want to try outsome of the programs in whichever order takes your fancy; then refer back tothe text for explanations. There are no monolithic applications in this book –just small, self-contained sample programs – so it’s easy to skip from chapterto chapter if you wish Making Sense Of The TextIn The Little Book Of Ruby, any Ruby source code is written like this:def saysomethingputs( "Hello" )end

The Little Book Of Ruby :: Welcome To The Little Book Of Ruby ::www.sapphiresteel.com :: page 8When there is a sample program to accompany the code, the program name isshown in a little box like this:helloname.rbExplanatory notes (which generally provide some hints or give a more indepth explanation of some point mentioned in the text) are shown in a shadedbox like this:This is an explanatory note. You can skip it if you like – but if you do so,you may miss something of interest !

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 9Chapter OneIN WHICH WE TIE UP SOME STRINGS, ADD UP SOMEAND DIAGNOSE SOME CONDITIONS NUMBERS, MESS ABOUT WITH METHODSFrom the fact that you are reading this, it is safe to deduce that you want toprogram Ruby – and, if you are anything like me, you will be impatient to geton with it. OK, let’s not hang around. I’ll assume that you already have Rubyinstalled. If not, you’ll need to do that first, as explained in the Introduction IMPORTANT: If you are using Ruby In Steel, be sure to load the solution,LittleBookOfRuby.sln for easy access to all the sample programs.Now, let’s start coding. Fire up your editor and enter the following:helloworld.rbputs 'hello world'Now run the program (In Ruby In Steel, press CTRL F5). All being well, Rubyshould display ‚hello world‛.If you are using an editor which lacks an interactive console, you mayhave to run programs from the command prompt. To do this, open acommand window (enter CMD from the Start/Run menu in Windows)and navigate to the directory containing the source code then enter rubyfollowed by the program name, like this:ruby helloworld.rb

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 10This must just about the shortest ‘hello world’ program in the history ofprogramming so we’ll immediately move on to a way of getting input fromthe user The obvious next step is to ‘get’ a string. As you might guess, the Rubymethod for this is gets.uppercase.rbObjects and MethodsRuby is a highly OOP (Object Oriented Programming) language.Everything from an integer to a string is considered to be an object. Andeach object has built in ‘methods’ which can be used to do various usefulthings. To use a method, you need to put a dot after the object, thenappend the method name. For example, Here I am using the upcasemethod to display the string, ‚hello world‛ in uppercase:puts( "hello world".upcase )Some methods such as puts and gets are available everywhere and don’tneed to be associated with a specific object. Technically speaking, thesemethods are provided by Ruby’s Kernel module and they are included inall Ruby objects. When you run a Ruby application, an object called mainis automatically created and this object provides access to the Kernelmethods.

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 11The helloname.rb program prompts the user for his or her name – let’ssuppose it’s ‚Fred‛ - and then displays a greeting: ‚Hello Fred‛. Here’s thecode:helloname.rbprint( 'Enter your name: ' )name gets()puts( "Hello #{name}" )While this is still very simple, there are a few details that need to be explained.First, notice that I’ve used print rather than puts to display the prompt. This isbecause puts adds a linefeed at the end whereas print does not; in the presentcase I want the cursor to remain on the same line as the prompt.On the next line I use gets() to read in a string when the user presses Enter.This string is assigned to the variable, name. I have not predeclared thisvariable, nor have I specified its type. In Ruby you can create variables as youneed them and Ruby ‘infers’ their types. Here I have assigned a string to nameso Ruby knows that the type of the name variable must be a string.Note: Ruby is case sensitive. A variable called myvar is different from onecalled myVar. A variable such as name in our sample project must beginwith a lowercase character.Incidentally, the brackets following gets() are optional as are the bracketsenclosing the strings after print and puts; the code would run just the same ifyou removed the brackets. Brackets help to avoid potential ambiguity in codeand, in some cases, the Ruby interpreter will warn you if you omit them.While some Ruby programmers like to omit brackets whenever possible, I amnot one of them; you will, therefore, find brackets used liberally in myprograms.

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 12Strings and Embedded EvaluationThe last line in the helloname.rb program is rather interesting:puts( "Hello #{name}" )Here the name variable is embedded into the string itself. This is done byplacing the variable between two curly braces preceded by a hash (‘pound’)character #{ }. This kind of ‘embedded’ evaluation only works with stringsdelimited by double quotes.It isn’t only variables which can be embedded in double-quoted strings. Youcan also embed non-printing characters such as newlines “\n” and tabs “\t”.You can even embed bits of program code and mathematical expressions.Let’s assume that you have a method called showname, which returns thestring ‘Fred’. The following string would, in the process of evaluation, call theshowname method and, as a result, it would display the string ‚Hello Fred‛:string eval.rbputs "Hello #{showname}"See if you can figure out what would be displayed by the following:puts( "\n\t#{(1 2) * 3}" )Run the string eval.rb program to see if you were right.

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 13Comments:Lines beginning with a # character are treated as comments (they areignored by the Ruby interpreter):# This is a commentMethodsIn the previous example, I blithely introduced a Ruby method withoutexplaining precisely what it is and the syntax needed to create it. I’ll correctthat omission now.A method is so called because it provides a method (that is, ‘a way’) for anobject to respond to messages. In OOP terminology, you send a message to anobject by asking it to do something. So let’s imagine that you have an objectcalled ob which has a method called saysomething; this is how you wouldsend it a saysomething message:object.rbob.saysomethingLet’s suppose that the saysomething method looks like this:def saysomethingputs( "Hello" )endThe result is, that when you send ob a saysomething message it responds withthe saysomething method and displays ‚Hello‛.

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 14OK, so that’s the ‘pure OOP’ way of describing this stuff. A not-so-pure OOPway of describing this would be to say that saysomething is like a functionwhich is bound to the object and can be called using dot notation:ob.saysomething.method.rbIn Ruby a method is declared with the keyword def followed by a methodname which should begin with a lowercase letter, like this:def showstringputs( "Hello" )endYou may optionally put one or more arguments, separated by commas, afterthe method name:def showname( aName )puts( "Hello #{aName}" )enddef return name( aFirstName, aSecondName )return "Hello #{aFirstName} #{aSecondName}"endThe brackets around the arguments are optional. The following syntax is alsopermissible:def return name2 aFirstName, aSecondNamereturn "Hello #{aFirstName} #{aSecondName}"end

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 15As explained previously, for the sake of clarity, I am very much prejudiced infavour of brackets but you can omit them if you wish.mainob.rbIf methods belong to objects, which object owns any ‘free-standing’methods that you write in your code? As I mentioned earlier, Rubyautomatically creates an object named main when you run a program andit is to this object that any free-standing methods belong.NumbersNumbers are just as easy to use as strings. For example, let’s suppose youwant to calculate the selling price or ‘grand total’ of some item based on its extax value or ‘subtotal’.To do this you would need to multiply the subtotal by the applicable tax rateand add the result to the value of the subtotal. Assuming the subtotal to be 100 and the tax rate to be 17.5%, this Ruby code would do the calculation anddisplay the result:subtotal 100.00taxrate 0.175tax subtotal * taxrateputs "Tax on #{subtotal} is #{tax}, so grand total is #{subtotal tax}"Obviously, it would be more useful if it could perform calculations on avariety of subtotals rather than calculating the same value time after time!Here is a simple version of a Tax Calculator that prompts the user to enter asubtotal:

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 16taxrate 0.175print "Enter price (ex tax): "s getssubtotal s.to ftax subtotal * taxrateputs "Tax on #{subtotal} is #{tax}, so grand total is #{subtotal tax}"Here s.to f is a method of the String class. It attempts to convert the string toa floating point number. For example, the string ‚145.45‛ would be convertedto the floating point number, 145.45. If the string cannot be converted, 0.0 isreturned. So, for instance, “Hello world”.to f would return 0.0.Testing a Condition: if thenThe problem with the simple tax calculator code shown above is that it acceptsminus subtotals and calculates minus tax on them – a situation upon whichthe Government is unlikely to look favourably! I therefore need to check forminus figures and, when found, set them to zero. This is my new version ofthe code:tax calculator.rbtaxrate 0.175print "Enter price (ex tax): "s getssubtotal s.to fif (subtotal 0.0) thensubtotal 0.0endtax subtotal * taxrateputs "Tax on #{subtotal} is #{tax}, so grand total is #{subtotal tax}"

The Little Book Of Ruby :: Chapter One :: www.sapphiresteel.com :: page 17The Ruby if test is similar to an if test in other programming languages. Note,however, that the brackets are once again optional, as is the keyword then.However, if you were to write the following, with no line break after the testcondition, the then would be obligatory:if (subtotal 0.0) then subtotal 0.0 endNote that the end keyword that terminates the if block is not optional. Forgetto add it and your code will not run.

The Little Book Of Ruby :: Chapter Two ::www.sapphiresteel.com :: page 18Chapter TwoDEFINING CLASSES, CREATING OBJECTS AND PEEKING INSIDE THEM So far we’ve used a number of ‘standard’ Ruby objects such as numbers andstrings. Let’s now see how to create new types of objects of our very own. Asin most other OOP languages, a Ruby object is defined by a class. The class islike a blueprint from which individual objects are constructed. This is a verysimple class:class MyClassendAnd this is how I would create a usable object from it:ob MyClass.newNot that I can do a great deal with my ob object – for the simple reason that Ihaven’t programmed anything in the MyClass class, from which it is created.object class.rbActually, if you create an ‘empty’ class like MyClass, the objects createdfrom it will not be totally useless. All Ruby classes automatically inheritthe features of the Object class. So my ob object can make use of Objectmethods such as class (which tells an object display its class):puts ob.class# displays: “MyClass”

The Little Book Of Ruby :: Chapter Two ::www.sapphiresteel.com :: page 19To make MyClass a bit more useful, I need to give it a method or two. In thisexample (which was mentioned briefly in the last chapter), I’ve added amethod called saysomething:class MyClassdef saysomethingputs( "Hello" )endendNow, when I create a MyClass object, I can call this method in order to get thatobject to say ‚Hello‛:ob MyClass.newob.saysomethingInstances and Instance VariablesLet’s create some more useful objects. No home (or computer program) shouldbe without a dog. So let’s make ourselves a Dog class:class Dogdef set name( aName )@myname aNameendendNote that the class definition begins with the keyword class (all lower case)and is followed by the name of the class itself, which must begin with anuppercase letter. My Dog class contains a single method, set name. This takes

The Little Book Of Ruby :: Chapter Two ::www.sapphiresteel.com :: page 20an incoming argument, aName. The body of the method assigns the value ofaName to a variable called @myname.Variables beginning with the @ character are ‘instance variables’ – thatmeans that they belong to individuals objects – or ‘instances’ of the class.It is not necessary to pre-declare variables.I can create instances of the Dog class (that is, ‘dog objects’) by calling the newmethod. Here I am creating two dog objects (remember that class names beginuppercase letters; object names begin with lowercase letters):mydog Dog.newyourdog Dog.newAt the moment, these two dogs have no names. So the next thing I do is callthe set name method to give them names:mydog.set name( 'Fido' )yourdog.set name( 'Bonzo' )Having given names to the dogs, I need to have some way to find out theirnames later on. Each dog needs to know its own name, so let’s give it aget name method:def get namereturn @mynameendThe return keyword here is optional. Ruby methods will always return thelast expression evaluated. For the sake of clarity (and to avoid unexpectedresults from methods of more complexity than this one!) we shall make a habit

The Little Book Of Ruby :: Chapter Two ::www.sapphiresteel.com :: page 21of explicitly returning any values which we plan to use. Finally, let’s give thedog some behaviour by asking it to talk. Here is the finished class definition:dogs and cats.rbclass Dogdef set name( aName )@myname aNameenddef get namereturn @mynameenddef talkreturn 'woof!'endendNow, we can create a dog, name it, display its name and ask it to talk like this:mydog Dog.newmydog.set name( 'Fido' )puts(mydog.get name)puts(mydog.talk)For the sake of variety – and to show that I am not biased against our felinefriends - I have also added a Cat class in my program, dogs and cats.rb. TheCat class is similar to the Dog class apart from the fact that its talk method,naturally enough, returns a miaow instead of a woof.

The Little Book Of Ruby :: Chapter Two ::www.sapphiresteel.com :: page 22This program contains an error. The object named someotherdog neverhas a value assigned to its @name variable. Fortunately, Ruby doesn’tblow up when we try to display this dog’s name. Instead it just prints ‘nil’.We’ll shortly look at a simple way of making sure that errors like thisdon’t happen again Constructors – new and initializetreasure.rbFor now, let’s take a look at another example of a user-defined class. Load uptreasure.rb. This is an adventure game in the making. It contains two classes,Thing and Treasure. The Thing class is very similar to the Dog class from thelast program – well, apart from the fact that it doesn’t woof, that is.The Treasure class has a few interesting extras, however. First of all, it hasn’tgot get name and set name methods. Instead, it contains a method namedinitialize which takes two arguments whose values are assigned to the @nameand @description variables:def initialize( aName, aDescription )@name aName@description aDescriptionendWhen a class contains a method named initialize this is automatically calledwhen an object is created using the new method. It is a good idea to use aninitialize method to set the values of an object’s instance variables. This hastwo clear benefits over setting each instance variable using methods suchset name. First of all, a complex class may contain numerous instancevariables and you can set the values of all of them with the single initialize

The Little Book Of Ruby :: Chapter Two ::www.sapphiresteel.com :: page 23method rather than with many separate ‘set’ methods; secondly, if thevariables are all automatically initialised at the time of object creation, you willnever end up with an ‘empty’ variable (like the nil value returned when wetried to display the name of someotherdog in the previous program).Note: The new method creates an object so it can be thought of as theobject’s ‘constructor’. However, you should not normally implement yourown version of the new method (this is possible but it is generally notadvisable). Instead, when you want to perform any ‘setup’ actions – suchas assigning values to an object’s internal variables - you should do so ina method named initialize. Ruby executes the initialize methodimmediately after a new object is created.Finally, I have created a method called to s which is intended to return astring representation of a Treasure object. The method name, to s, is notarbitrary. The same method name is used throughout the standard Ruby classhierarchy. In fact, the to s method is defined for the Object class itself whichis the ultimate ancestor of all other classes in Ruby. By redefining the to smethod, I have added new behaviour which is more appropriate to theTreasure class than the default method. In

web development framework called Rails – popularly known as ‘Ruby On Rails’. While Rails is an impressive framework, it is not the be-all and end-all of Ruby. Indeed, if you decide to l