Section 19.7. Ruby and the Web Server


19.6. Web Development with IOWA

IOWA (Interpreted Objects for Web Applications) is a web framework written by Kirk Haines. IOWA enables development with reusable, encapsulated web components for site generation.

19.6.1. Basic IOWA Concepts

An IOWA application runs in a persistent Ruby process that listens on a socket for requests. IOWA includes various adapters so that the source of that request may be CGI, Mongrel, WEBrick, and so on.

The IOWA home page includes a good explanation of the underlying architecture plus a tutorial, so here we'll just take a look at some key features.

IOWA is available for downloading from rubyforge.org. A gem version may be ready when version 1.0 is released. The examples here were built with a preview release of version 1.0, available as a zip or tgz file.

The installation includes some examples and test cases demonstrating a variety of uses. Here we'll look at a simple application derived from those examples.

An IOWA application needs some code to start off the persistent server process, and we'll use the built-in WEBrick server as the front end. This script, app.rb, handles both:

require 'iowa_webrick' class HWApplication < Iowa::Application   self.daemonize = true   attr_accessor :dbpool   def initialize(*args)     super    Iowa.config[Iowa::Capplication][Iowa::Croot_url] = 'http://127.0.0.1:2000'   end end Iowa.run


By default it will try to read a configuration file, app.cnf, in the same directory. Here's our app.cnf:

socket:   hostname: localhost   path: .. logging:   basedir: ../log   minlevel: 0   maxsize: 10000000   maxage: 86400 application:   daemonize: false   sessioncache:     class: LRUCache     maxsize: 20     ttl: 3600   dispatcher:     class: StandardDispatcher   policy:     class: iowa/Policy


The preceding file is a YAML file with assorted information describing how IOWA should behave. One more configuration file is needed as well (mapfile.cnf). It tells IOWA how to map page requests to components. Here is a one-line mapfile.cnf file:

/main.html: Main


IOWA requests are typically handled by a combination of HTML template files and IOWA components. Template and component source files share the same base name but use different file extensions. The default template/object is Main, so our sample application has Main.html and Main.iwa files.

Files ending with .iwa are just Ruby files; IOWA uses that extension to distinguish them from other Ruby code that may be part of the application. These files act much like controller classes in Nitro or Rails. Methods defined in a component class are available in the corresponding HTML file.

Our demo Main.html file is as follows:

<html>     <head><title>The Time Is...</title></head>     <body>         <p>The time is @now.</p>     <p>The count is @count.</p>        <a o>RELOAD</a>     </body> </html>


IOWA templates allow the mixing of plain HTML and component instance variables. Note that those variables do not need to be "interpolated" in the usual way; you just drop them into your markup.

There is also the special oid variable; IOWA uses this to dynamically alter the template during rendering. In our example, it is used to create a link back to the reload method in the component class defined in Main.iwa. If you hover your mouse over that link in the rendered page (or view the generated source), you see something like this:

http://127.0.0.1:2000/main.html/6b38f6fb-4f087af7-ab6JaqUM9KyWE.a.1.7


IOWA uses such URLs to track session state; if you click that link a few times, you'll see how it changes. If you manually edit it to a prior value, you'll retrieve the session state for that URL.

In this application, that state is in the @count instance variable. Here's Main.iwa:

class Main < Iowa::Component   attr_accessor :count   def awake     @count = 0   end   def setup     @count += 1   end   def now     Time.now.asctime   end end


19.6.2. Templating in IOWA

Although most web applications will benefit from a separation of application code and presentation templates, IOWA, somewhat like Nitro, allows you to skip components entirely and put Ruby code in the view. Here's PureView.html, containing both class and HTML:

<%   class PureView  < Iowa::Component     def right_now       Time.now     end   end %> <html>     <head><title>A Self-contained View</title></head>   <body>         <p>The time is @right_now.</p>   </body> </html>


Unlike Nitro, though, this only works if there is no corresponding component for the view. When you decide to have both a separate component file and a template, IOWA will not parse the embedded code in the HTML file.

The template file may still contain looping and conditional instructions. Suppose we add a new method to the Main.iwa file:

def after_dinner?   Time.now.hour > 19 end


We can then add some conditional rendering to Main.html using IOWA's if element:

<if oid='after_dinner?'>  <p>It's after dinner.  What's for dessert?</p> </if>


Good question! What is for dessert? Let's have IOWA tell us. We'll have Main.iwa produce a dessert menu in the form of an array:

def desserts   %w{ Cake       Brownies       Fruit       Gelato   } end


We'll then have Main.html display it. We update the conditional content to include the list of desserts:

<p>It's after dinner.  Here's what we have for dessert:</p>    <ul o>      <li>@dessert_item</li>    </ul>   </if> <p>


We also have to tell IOWA how to populate the iteration, so at the end of Main.iwa after the class definition we add this binding definition section:

<? dessert_list {   item = dessert_item   list = desserts  } ?>


This creates an IOWA binding for the template list dessert_items. During the iteration, each list item is available from a variable named dessert_item, with list data coming from the desserts component method.

19.6.3. Component Control Transfer

It can be useful to partition application logic among multiple component classes. We've seen how URLs may be mapped to components. You may also transfer control without changing the base URL path.

We'll add a new method to Main.iwa to handle the link from the dessert selection:

def dessert_choice   new_page = page_named('DessertChoice')   new_page.choice = @dessert_item   yield new_page end


We'll also change the dessert choice loop in Main.html:

<ul o>   <li><a oid='dessert_choice'>@dessert_item</a></li> </ul>


There's a fair amount of magic occurring here; the oid in the ul element guides the loop content, whereas the oid in the anchor element will create a special link to our new dessert_choice method. To top things off, the text value of the link will be passed (albeit cryptically) in that page request as well. The dessert_choice method is short; it uses the IOWA method page_named to create an instance of another component class, DessertChoice. The choice= method is called to pass along the dessert choice. The call to yield then transfers control to this new component.

The new component is defined like any other, using a pair of .iwa and .html files.

Here's the class code:

class DessertChoice < Iowa::Component   attr_accessor :choice   def details       "Details about #{@choice} should really come from a database."   end end


DessertChoice.html renders the details:

<html>  <head><title>Your Dessert Choice</title></head>   <body>  <h1>Dessert!</h1>   <p>@details</p>  </body> </html>


There is still more to IOWA than can be shown here. To learn more, visit the IOWA home page (http://enigo.com/projects/iowa/) and IOWA's project page on RubyForge (http://rubyforge.org/projects/iowa).




The Ruby Way(c) Solutions and Techniques in Ruby Programming
The Ruby Way, Second Edition: Solutions and Techniques in Ruby Programming (2nd Edition)
ISBN: 0672328844
EAN: 2147483647
Year: 2004
Pages: 269
Authors: Hal Fulton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net