RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


10 Minutes to Your First Ruby Application : Page 2

There's no better way to experience the elegance and power of Ruby than to fire up your code editor and start writing Ruby code. Create a small, useful Ruby application, and along the way, you'll learn what makes the language tick.

Version 0: The Launcher Code
First, create a sparse Ruby file. Ruby files end with .rb and have the pivotal line that defines the path to your Ruby interpreter up top. Call the file launcher.rb:


     # Example application to demonstrate some basic Ruby features
     # This code loads a given file into an associated application

      class Launcher

Notice you can use a pound sign (#) to start a line-level comment. Everything to the right of the # is hidden from the interpreter. Ruby has a means for commenting multiple lines of code, too. Class names begin with a capital letter; classes are constants, and all Ruby constants start with a capital letter. (For a more complete overview of Ruby syntax, please see "Ruby—A Diamond of a Programming Language?", Part 1 and Part 2.)

While this code seemingly does nothing, it is executable. If you're playing along at home, you should see that your copy of the code executes. A simple way to run a Ruby script is to simply call the ruby interpreter and pass the name of the file, like this (see Sidebar 1. Instructions for Executing launcher.rb in Unix and Windows):

$ ruby launcher.rb

When you run the file, you should see nothing—unless there's an error of some sort in the code. So, nothing is good. It doesn't mean nothing is happening; when the ruby interpreter parses your file, it encounters your class definition and makes it available for creating objects. The following code adds the class definition to your code:


     # Example application to demonstrate some basic Ruby features
     # This code loads a given file into an associated application

      class Launcher

     launcher = Launcher.new

The code first creates a variable (launcher) that is assigned a reference to a new instance of the class Launcher. You do not have to declare the type of the variable. Ruby uses strong, dynamic typing, and variables can hold references to objects of any type. Pretty much everything in Ruby is an object, including strings, numbers, and regular expressions. Each of these has a formal creation method (e.g., String.new), but Ruby tries to make it easy and fluid to work with the common cases.

Secondly, Ruby creates the object instance by invoking new on your Launcher class. New is a class method; it's analogous to constructor methods in Java. Of course, an empty object won't get you far, so you must add some behavior.

Adding Behavior
The essence of your application takes a given file name and passes it to an associated application for processing of some sort. The launcher code will need to know how to do this mapping, so when you create an instance of a Launcher class, you must pass in some sort of mapping. You've seen that you can use the class method new to create an instance of a class. To create an instance that starts life with some set of data, you can pass in arguments to new. To handle this, you of course will have to add some code to Launcher:

  def initialize( app_map ) 
    @app_map =  app_map

You define methods in Ruby using the def keyword, followed by the method name, and then the augment list, if any. The argument list is in parentheses for clarity, though Ruby will allow you to omit them when the meaning of the code is unambiguous (see Sidebar 2. Why You Add initialize Method When Passing Arguments to new Method).

It's worth noting then that Ruby objects begin life with assorted built-in behavior. You can use these as is, or opt to override them.

Instance Variables
Your initialize method takes one argument, app_map. Again, as with the earlier variable, you do not give the types of method arguments. You just say that the method takes one argument (app_map), and in the body of the method this argument gets assigned to the variable @app_map. The @ symbol indicates that the variable is an instance variable (i.e., it is available to all the code in this object). You create this instance variable when you create your object, and it will be available to any other methods you add to your code.

To have your application execute a given file using the associated application, drop some more code into it:

class Launcher

  def initialize( app_map )
    @app_map =  app_map

    # Execute the given file using the associate app
    def run( file_name )
        application = select_app( file_name )
    system( "#{application} #{file_name}" ) 

    # Given a file, look up the matching application
    def select_app( file_name )
        ftype = file_type( file_name )
        @app_map[ ftype ]

    # Return the part of the file name string after the last '.'
    def file_type( file_name )
        File.extname( file_name ).gsub( /^\./, '' ).downcase 


The method run takes a file name as its argument, passes it to select_app to find out which application to execute, and then uses Ruby's system method to invoke that application, passing the file name. The system method simply kicks the given command into a sub-shell. While select_app takes the file name, calls file_type to get a 'normalized' file extension, and then uses that as a key into @app_map to see which application to run.

Finally, file_type takes the file name and uses a class method on Ruby's File class to get the extension. The string returned by extname includes the period (.) that precedes the file extension. You don't need that, so the code uses gsub (or global substitute) to strip it; it then converts what remains to all lowercase letters with downcase.

For compactness, all these method calls are chained together. The string returned from File.extname is the receiver of the gsub request; the string returned from gsub then becomes the receiver of the call to downcase.

The example code so far has used objects that you expect to be Strings and Hashes, but what you really care about is that these objects will respond to particular messages in an appropriate way. (Before delving into how to call your shiny new object, see Sidebar 3. A Few Words About Objects, Types, and Behavior.) For such a small application, the subtlety and power of an object system based on messages and run-time behavior may not be critical, but it is important to understand this as you go on to write larger Ruby applications.

Rounding Out Version 0
Finish up this first version by putting it to use. You can add the following code to the end of the file to create an instance of Launcher and use it to run an application:

def help
  print " 
  You must pass in the path to the file to launch.

  Usage: #{__FILE__} target_file

if ARGV.empty?
  app_map = {
     'html' => 'firefox',
     'rb' => 'gvim',
     'jpg' => 'gimp'

  l = Launcher.new( app_map )
  target = ARGV.join( ' ' )
  l.run( target )

The method help will render instructions if needed. ARGV is the argument vector; it is a built-in Ruby object that holds all the parameters passed to your program. If it's empty, then your program has nothing to work with, so it displays the help and exits. Otherwise, it creates a hash object and assigns it to the variable app_map.

The { ... } notation is Ruby's literal syntax for creating a Hash object. You could have used Hash.new, but it's verbose. Using the literal notation, you map hash keys to values using =>. The hash is used to populate your Launcher instance, while the command-line arguments are collected into a single string stored in the variable target, which is passed into run.

Before trying this code, you need to change the application values used in app_map so that they refer to the proper executable. Assuming you have "rb" mapped to a text editor, you can try the code like this:

$ ruby launcher.rb launcher.rb

This should open your source code in your editor.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date