Meniu

The Scalability of Ruby

There are lots of reasons to like Ruby. It's a pure object oriented language. The syntax is elegant, and the use of blocks creates a novel feel. Another reason to like Ruby is its scalability. I don't mean scalability in the performance sense, but in regards to how you can code simple Ruby macros to solve small problems and also use Ruby in its object oriented form to support very large or complex applications.

The scalability of a language is a critical factor in understanding how broad of a range of applications it can support. How many times have you started with a ten line macro, only to end with a 15,000 line GUI application as the true requirements were uncovered? A scalable language reduces the barriers to scaling an application from 10 lines to 15,000 lines.

For this article, I will scale the solution of a simple problem to show the various forms of Ruby, from a simple scripting language to one which supports functions, libraries, and, finally, object oriented programming. For the problem, I'll use a simple implementation of the Unix "cat" command. "cat" outputs the contents of all of the files specified on the commandline to STDOUT.

Macros

First, here's a simple macro solution:

ARGV.each{ |fileName| inHandle = File::open( fileName ) inText = inHandle.read() print inText }

This iterates through each item of the commandline argument array, opens the file, reads the contents, and prints it. A shortened form looks like this:

ARGV.each{ |fileName| print File::open( fileName ).read() }

What about errors? Ruby has easy exception handling built in; here's an example:

ARGV.each{ |fileName| begin print File::open( fileName ).read() rescue print "Couldn't open file '" + fileName.to_s + "'\n" end }

If any of the expressions with the begin block raise an exception, the block will be terminated and the rescue portion of the block will be called. In this case, we take any exception to mean that the file could not be opened for some reason.

Functions

The next example is a function-based solution:

def print_file( fileName ) 
print File::open( fileName ).read() 
end ARGV.each{ |fileName| 
print_file( fileName ); }

First, we define a function named "print_file" that takes one string, a filename, opens the file, reads the contents, and prints it. As above, we iterate through the commandline argument array, but in this case, we send the fileName string to the print_file function.

Libraries

I implement the library approach in this example using a static member function of a class:

class FilePrinter 
def FilePrinter::print_it( fileName ) 
print File::open( fileName ).read() 
end end ARGV.each{ |fileName| FilePrinter.print_it( fileName ) }

FilePrinter::print_it is really just the print_file function above, but it is wrapped in the FilePrinter class for some sense of namespace containment.

Objects

An object oriented approach is shown below (even though an OO solution to the "cat" problem is probably overkill...).

class FilePrinter < File def print_it() $stdout.print read() end end ARGV.each{ |fileName| FilePrinter.open( fileName ).print_it() }

We extend File into FilePrinter and add the print_it method to it. As we go through each commandline argument, we create a FilePrinter object (instead of a File object) and send the print_it message to it.

Note the use of "$stdout.print" as opposed to just print. The File class supports a print method, but would print to the file instead of to STDOUT. We use the global $stdout to tell Ruby exactly where to print the contents of the file.

Another approach to the object oriented solution is to encapsulate a file within our object instead of extending the file object:

class FilePrinter def initialize( fileName ) 
@fileName = fileName @text = "" read() 
end def print_it() print @text end private def read() 
@text = File::open( @fileName ).read() 
end end ARGV.each{ |fileName| FilePrinter.new( fileName ).print_it() }

The "FilePrinter" class in this example derives directly from "Object" instead of File. It has two member variables, @fileName and @text. When the FilePrinter object is initialized, it sets the @fileName member variable and calls a private read method. Implicit support for access control is unique to Ruby when it is compared with languages like Python and Perl.

Conclusions

While there is no one programming language that can be used to implement every application, Ruby does have the flexibility to scale all the way from simple macros to a large and complex set of classes. This flexibility is one of the attributes that makes Ruby such a fun language to learn and to work in.

John Doe

Articole publicate de la contributori ce nu detin un cont pe gnulinux.ro. Continutul este verificat sumar, iar raspunderea apartine contributorilor.
  • | 340 articole

Nici un comentariu inca. Fii primul!
  • powered by Verysign