ave you heard about Ruby? It seems to be a popular topic in software development circles today. This language came to my attention at a Java conference last spring, where gentlemen like Bruce Tate (author of Bitter Java and Better, Faster, Lighter Java), Dave Thomas (Pragmatic Programmer: From Journeyman to Master), and others were all talking about Ruby and telling many of us in the audience it deserved a look.
Now, if you are like me,you’ve been developing software for some time and you know that while learning a new programming language can be fun, you’ve been through enough of them that you probably look a little skeptically at another programming language. After all, the programming language wars in the ’80s and ’90s culminated in the conclusion that there are essentially two camps: the Java world and the development languages that Microsoft supported on .NET. Its not that I didn’t want to learn another language, I just expected that the days of switching programming languages to gain a technological advantage were over. However, given the stature of these gentlemen in the industry, I decided to take a look.
Well, “I’ve been to the mountain top” so to speak and this article is a report on what I’ve found regarding Ruby. Bottom line up front, Ruby has some very nice features and is worth your investigation.
Setting Up Ruby
Ruby is an open source programming language developed by Yukihiro “Matz” Matsumoto in Japan in the mid-90s (for more on the history of Ruby, check out this article by its founder. Ruby can be obtained at www.ruby-lang.org. Originally built as a scripting language, it is available for many platforms, including Linux, many flavors of UNIX, MS-DOS, Windows, BeOS, Amiga, Acorn Risc OS, and MacOS X. As of this writing, the latest version of Ruby is 1.8.4. For those using Windows platforms, click here for the “one-click” Windows installer. Along with the base Ruby binaries and libraries, this download comes with several helpful (and free) IDEs and tools, including: documentation and sample code, RubyGems Package Manager, FreeRIDE (Free Ruby IDE), Fox GUI Libraries, fxri (a search engine and GUI guide to Ruby’s documentation, along with an interactive command line tool), and SciTE (Scintilla Text Editor IDE). As of this writing, the “stable” version of Ruby offered through the Windows installer is 1.8.2, with a 1.8.4 version in preview form. This article was written using the 1.8.2 version of the Windows installer.
The installation of Ruby using the Windows installer is straightforward. You download and run a simple install executable (ruby182-15.exe for version 1.8.2) that initiates a standard install wizard. The download file is about 15MB and will take up almost 40MB when the wizard completes the install of Ruby on your Windows platform.
For those dedicated to using their favorite editors to program, a number of familiar editors offer Ruby support to include emacs, vim, JEdit, Jed, Nedit, and Textpad. Of course, there is also a Ruby Eclipse project. Ruby Development Tools (RDT) is an Eclipse plug-in that is still early in development but available here. Also emerging on the market are a number of inexpensive Ruby IDEs. Arachno Ruby is one such example.
Running Ruby
Like many interpreted languages, Ruby offers programmers a couple of ways to develop code. You can run Ruby in interactive mode using a command line tool or you can create a Ruby program file and ask Ruby’s interpreter to execute the program.
In Windows, bring up a Command Prompt window, simply type “ruby” at the prompt, and hit the Enter key (the Ruby in directory should be on your path for this to work). Ruby is now awaiting your program. Type in the program below, hit Control-D and then the Enter key. You should see Ruby execute your program as shown in Figure 1.
def convertCtoF (celsius) print(celsius.to_s + " degrees celsius is " + ((celsius * 9)/5 + 32).to_s + " degrees in fahrenheit
")endconvertCtoF(20)
![]() Figure 1. Running the Celsius to Fahrenheit Calculator in Ruby Interactively: Start Ruby and enter a program and then hit the end of file character (Control-D). Ruby displays the results and exits. | ![]() Figure 2. Running convertCtoF.rb: The Ruby interpreter can also execute a Ruby program file. |
By the same token, the Celsius to Fahrenheit program above can be written with a Ruby IDE or simple text editor saved to a file?for example convertCtoF.rb (.rb is the conventional file type for Ruby programs). Now the Ruby interpreter will execute the Ruby program in the program file as shown in Figure 2.
The idea of having an interactive environment is not new, but it is quite powerful. Those familiar with Smalltalk, Common Lisp Object System (CLOS), or other interpreted programming environments of the past will find it very familiar. The interactive nature allows you to experiment with small chunks of programming code. A special Ruby batch file, irb.bat, kicks off the interactive Ruby interpreter and makes this point even more apparent. Figure 3 shows Ruby started using the irb.bat command. Now, code can be entered, interpreted, and tested one line at a time.
![]() Figure 3. Interactive Ruby: In this example, the Ruby interpreter is started in interactive mode (using the irb.bat file provided with the Windows Installer) and several lines of Ruby code are entered and tested. | ![]() Figure 4. . fxri’s interactive Ruby Capability: The graphical language documentation guide, fxri, is also used here to run the same Ruby commands as in Figure 3, but from inside this documentation tool. |
The interactive Ruby feature is built into several tools as well. For example, the graphical interface to the Ruby documentation, called fxri, not only serves as a language guide, but as an interactive Ruby interpreter as well (see Figure 4).
Objects, Methods, and Classes
In Ruby, everything is an object, and I do mean everything. Again, for those that have programmed in highly object-oriented languages such as Smalltalk, Eiffel, or CLOS, this will be a welcome surprise. In fact, one blog writer suggested that it is “time to learn Ruby or relearn Smalltalk” giving you a precursor to the nature and feel of Ruby. Numbers like 1, 2, 3 or 10.8 are all objects?not primitive types as they are in Java or C++. Strings are objects. Classes and methods are objects. For example, the following is legal Ruby code (comment lines in Ruby are demarcated with “#”):
#absolute value of the object -34-34.abs#Round a float object10.8.round#return an uppercased, reversed copy of a string object "This is Ruby".upcase.reverse#return the number of arguments to the Math "sin" method.Math.method(:sin).arity
![]() | |
Figure 5. Ruby Is All Objects: In Ruby, integers, floats, strings, and even classes and methods are all objects. The code here demonstrates method calls on these types of objects. |
And in Ruby, work is done by calling on methods or operations of objects. What may look like a function or a procedure call in other programming languages is, in fact, a method call in Ruby.
As in all object-oriented programming languages, objects are created from classes. Many pre-built classes are provided with the Ruby library. You can modify these classes or build your own classes. Classes are defined with the “class” keyword. Class names start with an uppercase letter. Class definitions end with the “end” keyword. So a Rectangle class can be defined with the following code.
class Rectangleend
To add methods to the class, use the keyword def. Methods also end with the end keyword. Method parameters follow the def keyword and method name. Adding an area method to the Rectangle class above would look like the following code.
class Rectangle def area (hgt, wdth) return hgt*wdth endend
For those familiar with other programming languages, you may have noticed a few differences. Ruby does not use any braces to delimit classes or methods, nor does it use semi-colons or other characters to denote the end of programming lines. The goal of Ruby, according to its creator, is to be simple, easy and “fun” to code. Who wants to remember all those semi-colons? Not fun. As long as you put statements on one line, no semi-colons or other code line ending mark is needed. By the way, the parentheses around the arguments to the area method are not required either. And by default, Ruby returns the last thing evaluated in a method, so the return keyword is not required. Therefore, you could have simply coded Rectangle as shown below:
class Rectangle def area hgt, wdth hgt*wdth endend
While legal, it is recommended that parentheses be used for method parameters for better legibility.
Instance Variables and Attributes
Classes can also have instance variables (also known as properties in some languages). For example, objects created from the Rectangle class should all have a height and width. In Ruby, instance variables do not explicitly have to be declared in the class, they simply have to be used and annotated with a special character in their name. Specifically, all instance variable names begin with an “@.” To store the height and width in the instance of rectangle when the area method is invoked, you merely have to add instance variables to the area method:
class Rectangle def area (hgt, wdth) @height=hgt @width = wdth @height*@width endend
More appropriately, when an instance of Rectangle gets created, the height and width should be specified and the instance variables set at that time. Ruby provides a special method called initialize to allow you to set up or prepare new instances of the class:
class Rectangle def initialize (hgt, wdth) @height = hgt @width = wdth end def area () @height*@width endend
To create a new object or instance of Rectangle, you call on the standard Ruby constructor method “new” against the class?in this case, Rectangle:
Rectangle.new(4,7)
Or, if you prefer the same instantiation without parentheses, although again for clarity’s sake, I would recommend using parentheses:
Rectangle.new 4,7
In this example, a new Rectangle object will get created, and the initialize method is called with the parameters of 4 and Rectangle class also defined methods for granting access. Notice, in the code below, the height and width methods have been added in order to share height and width information:
class Rectangle def initialize (hgt, wdth) @height = hgt @width = wdth end def height return @height end def width return @width end def area () @height*@width endend
Likewise, in order for some other object to update or set the height and width of a Rectangle object, additional mutating methods need to be defined:
class Rectangle def initialize (hgt, wdth) @height = hgt @width = wdth end def height return @height end def height=(newHgt) @height=newHgt end def width return @width end def width=(newWdth) @width=newWdth end def area () @height*@width endend
The mutator methods above (“height=” and “width=”) may look tricky, but they really are just methods. Don’t let the equal sign in the name fool you. The additional character at the end of the method name means nothing to Ruby, but it makes it seem more readable to humans when used. What do you think the following code looks like it is doing?
aRectangle.height=27
That’s right, a Rectangle object’s height is being assigned/changed. In fact, it is just a call to the method “height=” on the Rectangle object.
Because granting access to an object’s instance variable is quite common, Ruby comes with a set of keywords that essentially define the instance variable and the accessor/mutator methods all at once; making these instance variables “public” attributes. The keywords are attr_reader, attr_accessor. They help simplify the code considerably:
class Rectangle attr_accessor :height, :width def initialize (hgt, wdth) @height = hgt @width = wdth end def area () @height*@width endend
In the example code above, attr_accessor gives the Rectangle both getters and setters for the height and width attributes.
Building Applications with Interactive Ruby
So now you have a little bit of knowledge to start building a Ruby application. To demonstrate the interactive nature of the Ruby interpreter and to see how applications slowly get developed in Ruby, start an Interactive Ruby Help and Console utility (the fxri utility installed with Ruby) as shown in Figure 6.
![]() | |
Figure 6. Start fxri: Open the Interactive Ruby tool fxri from the Windows Start menu as shown here. |
In the lower right hand pane of the window is an interactive Ruby command prompt (notice the irb(main) :001:0> command prompt) that displays when the window opens. Go ahead and enter the Figure 7 at the command prompt.
Notice that as you type in your code, the interpreter is helping to format your code and as you enter your last “end” statement, Ruby returns => nil which is an indication that the Ruby interpreter has detected the end of your Rectangle class. Rectangle is now defined in this irb session.
Now try to create a few instances of your new Rectangle class. On the very next line, enter Rectangle.new(4,5) and then Rectangle.new(5,12). You should see Ruby again respond with new instances of your Rectangle:
irb(main):011:0> Rectangle.new(4,5)=> #irb(main):012:0> Rectangle.new(5,12)=> #
Now let’s try that area method. On the next irb command prompt line enter Rectangle.new(6,5).area(). You should see results that look like the following:
irb(main):013:0> Rectangle.new(6,5).area()=> 30
Cool?! Yes, and extremely powerful as you slowly build and test chunks of your application classes and methods. But wait, there is more.
In Ruby, classes are never closed. This means you can always add or redefine methods to an existing class. Say, for example, that you also wanted to add a circumference method to the Rectangle class that you created. On the command prompt, enter the following code a line at a time:
class Rectangle def circumference () @height * 2 + @width * 2 endend
![]() | |
Figure 7. Enter the Rectangle Class: Enter the definition of the Rectangle class into the fxri interactive Ruby interpreter as shown in the lower right-hand frame of this example. |
Has the Rectangle class just been defined again? No, the Ruby interpreter understands that you are making a modification to the current Rectangle class and it is adding a new method to the existing Rectangle class. Now enter the following line at the command prompt: Rectangle.new(2,3).circumference(). You should see results that look similar to those below:
irb(main):014:0> class Rectangleirb(main):015:1> def circumference()irb(main):016:2> @height * 2 + @width * 2irb(main):017:2> endirb(main):018:1> end=> nilirb(main):019:0> Rectangle.new(2,3).circumference=> 10
To redefine any method already in the Rectangle class, for example the area method, simply reenter the class definition with the new area method definition:
irb(main):020:0> class Rectangleirb(main):021:1> def area()irb(main):022:2> @height*2irb(main):023:2> endirb(main):024:1> end=> nilirb(main):025:0> Rectangle.new(6,5).area=> 12
In the simple example above, the area method has been redefined to always return twice the height.
The idea that a class is never closed applies to classes you define as well as those built into the language. For example’s sake, let’s add an area method to the String class. Enter the following code at the command prompt:
class String def area() length() endend
In this case, you are defining the “area” of a string to return the length of the string. Now, try this new method on your name as a String as shown with im below:
irb(main):026:0> class Stringirb(main):027:1> def area()irb(main):028:2> length()irb(main):029:2> endirb(main):030:1> end=> nilirb(main):031:0> "Jim".area=> 3
As you read this article, use the interactive nature of Ruby and its development environment to test and explore the programming language with the small chunks of Ruby code provided to you.
Variables, Assignment
Have you noticed throughout the examples shown so far that something is missing in the code? Have you had to type the constants, instance variable, or class variables? The answer is a big NO! It is part of the truly object-oriented nature of Ruby. To give further definition to this point, take a look at plain old variables in Ruby. Up to this point, you have created a lot of Rectangle instances, but you have not kept them around for too long. Say you wanted to assign a variable to an instance of Rectangle you create:
myRectangle = Rectangle.new(4,5)
This is perfectly legal code in Ruby and it doesn’t need any other line of code to “type” or declare myRectangle as something that references Rectangles. After this line is executed, the variable myRectangle references an instance of a Rectangle with a height and width of four and five respectively. But it is just an object reference that can be changed at anytime, without regard to the object’s type (again?everything in Ruby is an object). So on the next command prompt line, you could just as easily assign myRectangle to a string:
irb(main):049:0< myRectangle=Rectangle.new(4,5)=> #irb(main):050:0< myRectangle="Jim's Rectangle"=> "Jim's Rectangle"
Try that in many other programming languages?even object-oriented languages like Java and watch the compiler errors fly from your IDE.
Variables, instance variables, class variables, and even “constants” are really just object references. The refer to objects, but they are not the objects themselves. Therefore, they can be changed dynamically; even refering to a different type of object.
Because of this flexibility, some conventions have been established in Ruby to help everyone know how a variable is being used in the code. You have already seen one of these?the @ sign?used to signify an instance variable. Other variable, method, and class naming conventions are listed below and demonstrated in Table 1 below.
- Local variables and method parameters begin with a lowercase letter.
- Method names begin with a lowercase letter.
- Global variables begin with a $.
- Instance variables begin with a @ symbol.
- Class variables begin with two @ symbols.
- Constants start with an uppercase character (they usually are designated with all caps).
- Class and module names begin with an uppercase letter.
Local Variables | Global Variables | Instance Variables | Class Variables | Constants | Class Names | Method Names |
aVar | $Var | @var | @@var | VAR | MyClass | myMethod |
name | $debug | @lastName | @@interest | PI | Rectangle | area |
Table 1. This table contains examples of the conventions used in Ruby coding, especially as it applies to various types “variables.”
Operator Methods
Now, suppose you want to give instances of the Rectangle class a way to merge or be added to another rectangle instance. You could certainly define an additional method called “add,” but the alternative takes advantage of one of Ruby’s truly object-oriented features. You will override the “+” operator to appropriately add two Rectangle instances. The “+” method (as in 4+5) to Ruby is just another method. As just another method, you can give it functionality to meet Rectangle needs. You will define the “+” operator method to add the area of one rectangle to the area of another rectangle.
def + (anotherRectangle) totalArea = area() + anotherRectangle.area() Rectangle.new(@height,totalArea/@height) end
After adding this method to the Rectangle class, you can add two Rectangle instance using the + method call:
irb(main):001:0> rect1=Rectangle.new(2,3)=> #irb(main):002:0> rect2=Rectangle.new(3,4)=> #irb(main):003:0> rect1+rect2=> #
Operator overloading, which is what you just accomplished, is a feature that may be familiar to those that have programmed in Agol, C++, Python, and a few other languages. Again, Ruby is a culmination of the best aspects of many languages.
Method Arguments
Up to this point, it is assumed that the number of arguments passed to a method is known. While unthinkable in many other languages, Ruby allows you to pass in a variable number of arguments and capture them with a single parameter. To create an argument of a variable length, simply place an asterisk (*) in front of the last argument. In this way, you could write the definition of a polygon in Ruby.
class Polygon def initialize (s1, s2, s3, *others) @sideOne = s1 @sideTwo = s2 @sideThree = s3 @otherSides = others endend
As shown below, you can use this definition to create a triangle or a hexagon. In Part 2 of this series, you will learn more about arrays and how to work with the other “sides,” or arguments passed in, of the Polygon instances.
irb(main):009:0> poly1=Polygon.new(2,4,5)=> #irb(main):010:0> poly2=Polygon.new(2,18,4,5,7,9)=> #
On the flipside of accepting variable length arguments, Ruby also lets you define a default value for a method argument when the caller does not provide one. For example, here’s a better initializer for the Rectangle class.
def initialize (hgt = 1, wdth = 1) @height = hgt @width = wdth end
As seen here, the assignment operator next to the parameters listed in the definition serves as a default assigner if parameters are left off. Now, when creating a new Rectangle, if the width is left off in the call, an appropriate width is provided by default:
irb(main):090:0> rect=Rectangle.new(2)=> #
Class Variables and Class Methods
Like most object-oriented languages, Ruby classes also allow for class variables and methods. A class variable allows a single variable to be shared amongst all instances of a class. In Ruby, a double at sign (@@) is used to signify class variables. For example, if you wanted all instances of a BankAccount class to share the same interest rate, then the class might be defined as follows:
class BankAccount @@interestRate = 6.5 def BankAccount.getInterestRate() @@interestRate end attr_accessor :balance def initialize (bal) @balance = bal endend
As you can see, class variables must be initialized before they are used, and like instance variables, you need to write accessor methods if you want to make class variables accessible. In this case, I have defined a class method to return the interest rate. Note the class name and period in front of getInterestRate denoting a class method. A class method works the same regardless of any instance?in this case, returning the common interest rate to all BankAccount instances. To call on class methods, you need to use the class name as it is also used in the class method definition:
irb(main):045:0> BankAccount.getInterestRate=> 6.5
In fact, the “new” method used to create instances of classes is actually a class method. Thus, when you type Rectangle.new in your program, you are actually calling on the new class method which Ruby provides by default.
Inheritance
One of the tenets of object-oriented programming is support for a class hierarchy. As in the classification of things in nature, classes are allowed to inherit characteristics from more generic classes. Characteristics in object-oriented programming are embodied in methods and variables. For example, a Square class inherits from the Rectangle class some characteristics or methods and variables. A Square is a more specific type of Rectangle (an instance of Rectangle with equal sized height and width) but it still has a height and width as well as area (also computed in the same way as a Rectangle’s by multiplying one side by the other side). In Ruby, the Square class could be created with the following definition:
class Square < Rectangleend
The < Rectangle signifies that Square is a subclass of Rectangle or, conversely, that Rectangle is the superclass of Square. By default, an instance of Square automatically has all the same attributes and methods that a Rectangle has to include height, width, and the area method. In order to insure the sides of Square instances are of equal length, you may want to override the existing initialize method of Square:
class Square < Rectangle def initialize (size) @height = size @width = size endend
Again, everything in Ruby is an object. Quite literally, this means that everything descends from the Object class. While it is not explicit in all class definitions (you won't see < Object in the definition), all classes descend from the Ruby base class Object. Knowing this fact makes this next point a little easier to understand.
When writing your application, you can define methods outside of a class definition. At the start of this article, you were shown a Celsius to Fahrenheit converter method that was not part of any class. As an additional example, here's a method outside of any class:
def feel? return "I feel fine."end
To execute this method, just enter the method name?no class or instance is needed:
irb(main):042:0> feel?=> "I feel fine."
These methods look like functions or procedures in another language like C. In fact, while the methods look like they do not belong to any class, these methods are actually methods you have added to the Object class, which (because Object is "the" superclass of all classes) in turn also adds the method to your classes. Therefore, you can now call this method on any object (like instances of Squares and Rectangles) or even a class (like the Rectangle class).
irb(main):043:0> sq1=Square.new(4)=> #irb(main):044:0> rect1=Rectangle.new(5,7)=> #irb(main):045:0> sq1.feel?=> "I feel fine."irb(main):046:0> rect1.feel?=> "I feel fine."irb(main):047:0> Rectangle.feel?=> "I feel fine."
Method Access Control
There is a small catch to the top-level methods. They are considered "private" methods. In many cases, as you design your applications, you want methods to be used internally by an object, but not by other objects. Ruby provides three keywords to limit access to methods.
- Private: Methods that can only be accessed by the object.
- Protected: Methods that can be accessed by the object and by instances of the class and direct inheritance descendants.
- Public: Methods can be accessed by any object (Public is the default setting for all methods).
The keywords are inserted in the code between methods. All methods defined from the keyword private are private until another access control keyword is put in the code. For example, in the code below, the accessors and area method are all public by default while the grow method is private. The doubleSize method is explicitly made public. The initialize method of a class is automatically private.
class Rectangle attr_accessor :height, :width def initialize (hgt, wdth) @height = hgt @width = wdth end def area () @height*@width end private #start making private methods def grow (heightMultiple, widthMultiple) @height = @height * heightMultiple @width = @width * widthMultiple return "New area:" + area().to_s end public #back to public methods again def doubleSize () grow(2,2) endend
As shown below, doubleSize can be executed on the object, but any calls to grow directly are rebuffed and return an error.
irb(main):075:0> rect2=Rectangle.new(3,4)=> #irb(main):076:0> rect2.doubleSize()=> "New area: 48"irb(main):077:0> rect2.grow()NoMethodError: private method 'grow' called for # from (irb):77 from :0
Instance and class variables are private by default in Ruby unless attribute accessors and mutators are provided.
Modules and Mixins vs. Multiple Inheritance
Some programming languages (C++ and CLOS) offer multiple inheritance: a class inheriting from more than one superclass. For example, a House might inherit from both a Building class (along with Office and Hospital classes) and Residence class (along with Apartment). Without getting into the religious arguments that have occurred in programming language research arenas, let's just say that multiple inheritance can be a very powerful feature, but increases complexity and ambiguity in a language and is not incorporated in many object-oriented languages.
Ruby provides single inheritance. However, it also offers "mixins" which provide many of the features of multiple inheritance. A mixin is a type of "module"...so you first must understand what a module is in Ruby.
A module is a means to group together methods and constants. It is similar to a class, but a module has no instances and has no subclasses. Perhaps the best way to explain a module is to define one as an example. Suppose you were developing a manufacturing application. The application needed access to a great number of general scientific equations/formulas and constants. You could either create a generic class to put these in or you could create a module. The module has the benefit of never having any instances to mess around with to get access to the formulas.
module Formulas ACCELERATION = 9.8 LIGHTSPEED = 299792458 def energy (mass) mass*(LIGHTSPEED**2) end def force (mass) mass*ACCELERATION endend
Now these formula methods and constants can be used by any number of other classes or just by themselves:
irb(main):046:0> Formulas.force(10)=> 98.0irb(main):047:0> Formulas::ACCELERATION=> 9.8
Note that to call on a module method or use a module constant, you must use notation similar to the notation used to call on a class method. To call on the module method, you need to use the module class name followed by a dot and then the module method name. For referencing the module constant; use the module name followed by two colons followed by the constant name.
Beyond their usefulness as method and constant "catch-alls," modules also help define a multiple inheritance like facility through mixins. A mixin is simply a module "included" with a class definition. When a class includes a module, all the module's methods and constants become instance methods and contants of the class. For example, suppose that the Formula module defined above was added as a mixin to the Rectangle class. To do this, you would use the "include" keyword:
class Rectangle include Formulasend
Now, instances of Rectangle have the force and energy methods that they can use and the Rectangle class has access to ACCELERATION and LIGHTSPEED constants:
irb(main):044:0> class Rectangleirb(main):045:1> include Formulasirb(main):046:1> end=> Rectangleirb(main):047:0> Rectangle.new(4,5).force(10)=> 98.0irb(main):048:0> Rectangle::LIGHTSPEED=> 299792458
This means that mixins give Ruby classes many of the benefits of multiple inheritance?but without the issues associated with multiple inheritance.
Control Flow
Like all programming languages, Ruby offers a set of control flow commands to include conditionals (if/else structures), case statements, and loops (do, while, and for), as well as offering exception handling like languages such as Ada and Java. Below are some examples of Ruby's general control flow statements:
if area > 100 "big"else "small"endcase height | when 1 | print "stubby
" | when 2..10 #height in the rage of 2 to 10 | print "short
" | when 10..20 #height in the rage of 2 to 10 | print "tall
" | endaRect = Rectangle.new(4,6)while aRect.area < 100 and aRect.height < 10 aRect.doubleSize()endfor element in [2, 9.8, "some string", Math::PI] #loop through a collection of objects print "The type is: " + element.type.to_s + "
&"end
Control statements are generally straightforward, but as shown in the examples of the case statement and for loop above, there are some neat wrinkles that Ruby has thrown in based on other languages and its object-oriented nature.
Exception handling is similar to that in Java with "try...catch...finally" statements. In Ruby, these are "begin...rescue...ensure" statements:
begin # do somethingrescue ## handle all errors or you can handle explicit errorsensure # do some clean up, like closing an open file.end
To cause an exception in your code, you simply call on the raise method:
if area < 0 raise else if area > 0 and area < 10 raise "Rectangle too small"else if area > 100 raise TooBigException "Rectangle too big"end
The first raise call creates a RuntimeError. The second creates a RuntimeError with a message. The final raise call creates a new instance of a presumably defined TooBigException error and sets its message appropriately.
A Little Ruby Program
To help you get a better feel for the basics of Ruby, I have included a little application with this article for you to explore. To get the application working, download and unzip the contents of the file onto your file system. It will create an examples folder wherever it is unzipped. There are nine Ruby code files (.rb files) in the examples directory. The bulk of the code in this article is in these files. Additionally, you will find a testShapes.rb file which serves as the main kick off point for testing Ruby Rectangle, Square, and Circle objects. Simply bring up a command prompt and use ruby to run the testShapes.rb file as shown in Figure 8.
![]() | |
Figure 8. A Small Ruby Example: After downloading the zip file, use a command prompt to go to the Ruby source code directory and type ruby testShapes.rb. The results should look something like what is seen in this picture. |
You will notice, in testShapes.rb and some of the other code, that the file begins with "require" and a file name (like rectangle.rb). This is the Ruby notation for bringing in or using code into your Ruby program.
Wrap Up
Will Ruby take over Java or C# as one of the leading modern software development languages? I doubt it?although Ruby is supposedly quite popular in Japan. As someone who has been in this industry many years, I am not pessimistic about its chances, but I am pragmatic. I found Smalltalk to be a far superior programming language to Java, but alas, superior does not always win. There is a lot of support behind existing languages?both technical and marketing. Libraries, toolkits, frameworks, architectures, connectors, adapters, platform support, services, knowledgebase, competent implementation teams, etc. have all been put in place to support programming languages like Java. And, like it or not, marketing machines at Sun and Microsoft will ensure the success of the current development environments for sometime to come.
So why explore Ruby? It could be particularly useful as a scripting language replacement for Perl or Python (which was its original purpose) or for quick prototyping. A few have also seen its power and principals and have adopted Ruby as a great way to teach programming. According to members of my local Ruby users group, a number of people are using it to help test production systems. Beyond that, I invite you, as Bruce Tate and Dave Thomas did me, to explore its power and beauty. Sometimes, we need to be reminded of the way things should be. Even if Ruby does not become a commonly used, supported, and marketed programming language, perhaps with enough awareness and a little use, some of its features will find their way to the programming environments we know?if not love?today.
Next Month
You have enough Ruby help now to get started. There is a lot more to cover, including some very powerful Ruby features such as Ruby's data structures, standard library, Blocks, Regular Expressions, I/O, graphical user interface, and of course, Ruby on Rails (Ruby's Web framework).