At the Forge - Getting Started with Ruby

What's behind all the Ruby hype? Reuven walks us through a couple of examples to let the code speak for itself.
WEBrick

The above are what we might expect from simple CGI programs—easy to write, easy to work with and slow to execute. If our programs get any more complicated, we have to deal with new issues that we might prefer to ignore, such as personalization.

Luckily, Ruby comes with its own HTTP server, known as WEBrick, that is similar in some ways to AOLserver or mod_perl. There is also mod_ruby, if you are interested in a more direct equivalent to mod_perl, that runs under Apache. To start a basic HTTP server on port 8000, looking at the same static documents as Apache, use the following code:

#!/usr/bin/env ruby
# *-ruby-*-

require 'webrick'
include WEBrick

# Create an HTTP server
s = HTTPServer.new(
  :Port            => 8000,
  :DocumentRoot    => "/usr/local/apache/htdocs/"
)

# When the server gets a control-C, kill it
trap("INT"){ s.shutdown }

# Start the server
s.start

There are several things to note here. First, there isn't much code. You indicate what port WEBrick should listen to, tell it where files are located and then start it up.

Before we start the server, we have to make sure it is possible to stop it easily. To do that, we invoke trap, indicating that we want to trap SIGINT (that is, Ctrl-C) and that s.shutdown should be invoked upon receiving that signal.

If you put the above program in a file named server.rb and execute it, you should have a fully functional HTTP server running on your system. Creating a Web server has never been simpler.

Ruby Servlets

Of course, no one runs WEBrick instead of Apache for its speed or to serve static documents. Rather, WEBrick shines when you want to create custom behaviors. In spirit and terminology, there is a fair amount of overlap between WEBrick servlets and Java servlets. The basic idea is the same: define a new class and then attach an instance of that class to a particular URL. For example, if we want to create a servlet that prints the time of day, we can create the following:


#!/sw/bin/ruby
require 'webrick'
include WEBrick

# ---------------------------------------------
# Define a new class
class CurrentTimeServlet
  < WEBrick::HTTPServlet::AbstractServlet

  def do_GET(request, response)
    response['Content-Type'] = 'text/plain'
    response.status = 200
    response.body = Time.now.to_s + "\n"
  end
end

# ----------------------------------------------
# Create an HTTP server
s = HTTPServer.new(
  :Port            => 8000,
  :DocumentRoot    => "/usr/local/apache/htdocs/"
)

s.mount("/time", CurrentTimeServlet)

# When the server gets a control-C, kill it
trap("INT"){ s.shutdown }

# Start the server
s.start

Our one file contains both the class definition for CurrentTimeServlet and the commands for starting WEBrick. This is not the most elegant style for creating a servlet, and you typically want to put each servlet in its own file. That said, Ruby makes it easy and convenient to define or redefine classes and methods wherever it might be best to do so. This is one of those features in Ruby that reminds me of Perl: the language gives you a great deal of flexibility when writing your code but expects you to be responsible enough to avoid making a mess of it.

We define our servlet, CurrentTimeServlet, to be a subclass of WEBrick::HTTPServlet::AbstractServlet, making it a simple servlet indeed. We then define the do_GET method along with the do_POST method, if you so desire, which gets both a request and a response object. If you have written Java servlets, this should look familiar to you. We set the content type of the response, the status code (200) for the response and even the body of the response with a few simple lines of code. And that's it; our servlet has been defined and is ready to go. All that is left to do is connect the servlet to a URL:

s.mount("/time", CurrentTimeServlet)

If we want, we can pass parameters to the servlet when we initialize it. Anything beyond the first two parameters to s.mount is sent:

s.mount("/time", CurrentTimeServlet, 'a parameter')

Conclusion

Is it amazing that we can do this much in so few lines of code? Perhaps—although similar functionality certainly exists in other languages. For example, Perl programmers can download HTTP::Server::Simple from CPAN and do many of the same things. And if I really was interested in modifying the behavior of an HTTP server to do interesting things, I probably would think of using mod_perl or AOLserver first, for reasons of performance and flexibility.

That said, WEBrick is extremely easy to get running and for creating custom HTTP-based behaviors. I can imagine using it to handle Web services, for example, because of the flexibility that Ruby brings to the table, or to test applications written in Rails.

And, although people are using Ruby and WEBrick for plain-vanilla Web development, most of the excitement seems to be over the specific Rails framework, rather than Ruby or WEBrick themselves. In my next article, we will start to explore Rails—how to install it, how to develop applications with it and how it stacks up against other open-source application frameworks.

Resources for this article: /article/8397.

Reuven M. Lerner, a longtime Web/database consultant and developer, now is a graduate student in the Learning Sciences program at Northwestern University. His Weblog is at altneuland.lerner.co.il, and you can reach him at reuven@lerner.co.il.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Setting up a Linux Rails Development Environment

Jim Rutherford's picture

If you looking to give Rails a try on linux, checkout my tutorial on Installing Ruby on Rails with Lighttpd and MySQL on Fedora Core 4

Cheers!

indention in CGI code

Robby Russell's picture

Is the weird indenting in the CGI example intentional?

A few python pals looked at that and immediately thought it might be some Ruby-ism. I showed them an example like this to clear up the confusion:

nevermind, linuxjournal doesn't allow a pre tag so my indenting doesn't stay in the comment. I'd prefer not confuse anyone else. :-)

indents in ruby are 2 spaces

Anonymous's picture

indents in ruby are 2 spaces...if you want the community to like you.

Thanks

Eric Anderson's picture

Thanks for the quick intro, it's a good starting point for server-side Java developers. I'm looking forward to the Rails article.

One thing though: how about a look into the Ruby debugging environment. What tools/approaches do I use to debug complex server-side Ruby applications? I hope the answer is not "use print statements" ... effectively taking us back to the Dark Ages of programming. I like the idea of object-oriented scripting, but do not like the idea of _not_ having tools as powerful as say, the Eclipse or Netbeans debuggers for my work.

You can use Eclipse, for sure :o)

mpathy's picture

There is a very nice plugin for eclipse I use.

Use the Eclipse Update Manager with this URL:
http://rubyeclipse.sf.net/updatesite

There is a Test::Unit included.
Thats what you need (if I understood you right).

Try Ruby on Rails

michael's picture

RoR has a console for debugging purposes which allows you to directly interact with your development model.

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState