Trellis Tutorial #1 - The HiLo Web Application

Posted by Brian Sam-Bodden Tue, 06 Oct 2009 19:08:00 GMT

Trellis HiLo Game

The Trellis Hilo Game is a simple application where the user guesses a number between one and ten. This example was ‘borrowed’ from the Apache Tapestry project and ported to Trellis.

The simple diagram shows the application’s page flow, which consists of three pages: Start, Guess and Game over.

Trellis Hilo Page Flow

Figure 1 - Hilo Application Page Flow

The Start page simply provides a link to start guessing. The guessing happens in the Guess page. The Guess page presents the user with ten links for the numbers from 1 to 10. When the user selects incorrectly the page responds with an appropriate message such as “Guess X is too low” or “Guess X is too high”. If the user selects the correct number the application navigates to the GameOver page, which reports how many guesses it took to find the correct answer.

The Application Structure

The HiLo web application structure consists of 1 Ruby file and possibly 3 XHTML templates:

Trellis Hilo Directory Structure

Figure 2 - Trellis Hilo Directory Structure

It is not required that you organized your application as shown but if you want to avoid having to specify your view template locations, Trellis will assume the structure above when searching for a template.

Installing Trellis

gem install trellis

The Trellis Application Class

Let’s start at the beginning and create a Trellis application. Let’s call it HiLoGame and tuck it in a module named Hilo. At the top we’ll require the RubyGems and Trellis Gems and to simplify the code we’ll include the Trellis module:

require 'rubygems'
require 'trellis'

include Trellis

module HiLo
  class HiLoGame < Application
    home :start
  end
end

The class HiLoGame extends Trellis::Application which represents a Web Application composed of one or more pages. Inside the class body the ‘home’ class method is used to declare the home page of the application. That is, the entry point and what the URI ‘/’ will be resolved to. In the case of the HiLoGame application the entry point is indicated by the symbol :start. The Trellis convention is that there will be a Trellis Page class named Start.

The Start Page

The Start page will provide a simple welcome message and a link for the users to start guessing numbers. Let’s start with the view and show the HTML markup:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Hi/Lo Game Start Page</title>
    </head>
    <body>
      <h1>Hi/Lo Guess</h1>
      <p>I'm thinking of a number between one and ten ... </p>
      <p>
        <trellis:action_link>Start guessing</trellis:action_link>
      </p>
    </body>
</html>

Everything in the markup above should be familiar except for the <trellis:action_link> tag. The tag represents one of Trellis’ core components, the ActionLink component. ActionLink is a simple stateless component that provides a hyperlink to trigger an action. The URI produced represents the creation of an event. Events in Trellis have names. The name of the event generated by the ActionLink component is called “select”. Now that we have a template, let’s create the Trellis page class that will serve that template. The Start page is a simple class that extends the Trellis Page class.

  class Start < Page
  end

Launching the Application

Next, let’s add a bit of code so that we can launch the application. In order to run the application we need an instance of HiLoGame for which we will invoke the start() method, as follows:

  web_app = HiLoGame.new
  web_app.start if __FILE__ == $PROGRAM_NAME

Note: The HiLoGame and all page classes are contained inside the HiLo module as well as the two lines above to instantiate and run the application.

With the skeleton page in place and its corresponding template we can now run the application like:

ruby hilo.rb

At the console you should see output similar to (Trellis uses Mongrel by default):

091005 19:51:51 INFO: Starting Trellis Application HiLo::HiLoGame on port 3000 
091005 19:51:51 INFO: watching /Users/bsbodden/Documents/projects/trellis/examples/test/source/../html/ for template changes... 

Launch your browser and point it to http://localhost:3000 and you should see the home page of our Hilo application as shown next:

Trellis Hilo Start Page v1.0

Figure 3 - Trellis Hilo Start Page

On the console we can see the GET request for the root “/” URI:

090921 15:30:22 INFO: 127.0.0.1 - - [21/Sep/2009 15:30:22] "GET / HTTP/1.1" 200 558 0.0025 

By now, you probably have already clicked on the “Start Guessing” link and the application has appropriately blown chunks and showed you an error page describing the problem such as:

Trellis Error Page

Figure 4 - Trellis Error Page

Events

The error page indicates that the application could not find a method named on_select(). If you remember I mentioned that the ActionLink component generates an event called ‘select’. When a page gets an event with a name “bacon”, it looks for an event handler method named on_bacon().

Start Guessing Link

Figure 5 - Start Guessing Link

The return value of an event handler method determines where the application will navigate to next. Inside of a page for example, returning ‘self’ will make the application navigate to the same page.

Let’s add a place holder on_select() event handler to the start page and for now let’s just make it navigate back to the start page.

    def on_select
      self
    end

Go back to / or /start to refresh the page. If you hover over the link on the page you can see the URI generated by the ActionLink component. As you can see a page has an /events namespace in which we can ‘drop’ and event. In this case ‘select’. You can see the pattern now: /page/events/event

Component Event Produced Event Handler
ActionLink select on_select()

Clicking on the “Start Guessing” link again should now take you back to the start page.

By now you have probably noticed that it wasn’t necessary to restart the application after each change. Trellis will detect changes to your application’s code and templates and automatically reload them. We can now navigate to the same page but what we really want to do is navigate to the not-yet-existent Guess page.

Navigating To Other Pages

Trellis pages need to declare any other pages that they might redirect to. To declare the possible page transitions we use the class method ‘pages’. Since the Start page can only navigate to the Guess page, we declare that using the :guess symbol referring to a Guess page that we’ll develop next.

  class Start < Page
    pages :guess

    def on_select
      self
    end
  end

Injected pages such as :guess get their own instance variables (@guess) available to the page. We can change the on_select() event handler to return an instance of the Guess page and also perform some work along the way as shown below:

    def on_select
      @guess.initialize_target
    end

Obviously we haven’t yet implemented the initialize_target() method, hell we don’t even have a Guess page yet!

Stand In Pages

Yet, if you refresh the start page and click the “Start Guessing” link you should see something like:

Trellis Stand-In Page for Guess

Figure 6 - Trellis Stand-In Page for Guess

In development mode (which is the default) Trellis will generate synthetic pages or “Stand-In” pages for any injected pages for which it cannot find an implementation. Invoking any method on a stand in page returns the page object itself. In the case of the on_select() method, the return value is the guess page itself, since calling the initialize_target() method will just return the guess page object.

Stand-In pages enable incremental development, you can think of them as virtual scaffolding that automatically fades away as you provide a page’s implementation.

Read more...

Tags , , ,