Trellis Tutorial #3 - Creating a Stateless Component

Posted by Brian Sam-Bodden Wed, 10 Feb 2010 19:31:00 GMT

Creating a Stateless Component

A component-driven framework would be pretty pointless if you couldn’t create your own components. Component creation is how developers can encapsulate a complex and/or repetitive piece of functionality and provide a clear API to access that functionality.

In Trellis, components wrap both logic and presentation in a small manageable package. A Trellis component provides a template to be rendered and logic that can be used to respond to external events.

In the first installment of the Trellis tutorial series we got to use some of the simple components made available through the core library. The core components provide very basic functionality expected in a component-driven web framework. But things only get interesting when you get to build your own components. Whether they are general purpose, domain specific or application specific components, a well-crafted set of components can truly improve the understanding of an application, ease maintenance and improve testability.

In this tutorial we’ll walk through the development of a simple stateless component to display images using the Flickr API. This example is included in the Trellis distribution under examples/flickr

Project Setup

Setting up a Trellis project is quite simple. We’ll start with the simple directory structure shown in Figure 1. I’ve named the root directory of the application ‘flickr’. The ruby file flickr.rb will contain our application and the file spec/flickr_spec.rb will contain our RSpec specifications.

Directory Structure

Figure 1 - Flickr Application Directory Structure

Test Driven Development with Trellis with RSpec

In this tutorial we’ll work in a more realistic way that in previous tutorials. We’ll developed the Flickr example in a test-driven/test-first fashion. We’ll start with a bare bones skeleton for a Trellis application, as shown next (flickr.rb):

require 'rubygems'
require 'trellis'

include Trellis

module Flickr
  class FlickrApp < Application
  end
end

RSpec

For our TDD efforts we’ll use RSpec, “the original Behavior Driven Development framework for Ruby”. With RSpec you create “specifications” which are tests that describe the behavior of the system under certain conditions. We will try to follow the red-green-refactor mantra as close as possible:

  1. Writing a Test that describes a particular behavior of interest in the system.
  2. Running the Test (Red): Since the behavior hasn’t been implemented the test will fail.
  3. Implement: Writing enough code to pass the test
  4. Re-Running the Test (Green): With the implementation in place the test should now pass
  5. Refactor: With a basic foundation of how to fulfill the behavior and a test to prove the implementation we can now “refactor without fear”.

In the /spec directory we’ll add simple RSpec spec as follows (flickr_spec.rb):

require 'rubygems'
require 'spec'
require 'rack'
require 'rack/test'
require File.dirname(__FILE__) + '/../flickr.rb'

describe Flickr::FlickrApp do
  include Rack::Test::Methods

  def app
    Flickr::FlickrApp.new
  end

  it "should have a home page declared" do
    Flickr::FlickrApp.homepage == :home
  end
end

Let’s talk about the spec we’ve just created. At the top, besides requiring rubygems, we need the RSpec library (spec), Rack (rack) and Rack::Test (rack/test). We will also need to make the file under test, flickr.rb available.

Rack::Test enables you to test a Rack-based application without having a running server. Rack::Test mocks HTTP requests and provides a DSL to test against the response.

The describe block, “describes” an scenario. In RSpec an scenario consists of one or more examples. Each example describes a discrete behavior of the class under test.

In the scenario above we have only one example so far which states that our application should have a home page named “home”. With the bare bones application code and the spec in place we can now run it to get our TDD going.

Failed Spec

Figure 2 - Failed Spec (no home page)

As expected the test fails. We got to the “red” stage. To pass the test and get to “green” we can simply declare the home page as shown next:

module Flickr
  class FlickrApp < Application
    home :home
  end
end

Running the tests again shows that we’ve accomplish what we set out to do in this simple example.

Passed Example

Figure 3 - Passed Spec (after adding a home page)

Testing with Rack::Test

With an understanding of the basic mechanics of TDD we can now move onto fleshing out the rest of the application. Our next example will make use of Rack::Test to make sure that our application returns an HTTP status code of 200 (OK). Previously we provided the spec with an #app method which returned an instance of the Flickr application. The #app method is required by Rack::Test and it enables the use of a simple DSL to interact with the application in a mocked HTTP server environment. Rack::Test provides a way to issue a mock HTTP request to the application, inspect the response, follow redirects and maintain cookies across requests.

it "should return an OK HTTP status" do
  get "/"
  last_response.status.should be(200)
end

This test requests the root url of the application, which should redirect to a home page and then checks that the last response has a status of 200.

Failed Example

Figure 4 - Failed Spec (no OK response)

To pass this next example we need to provide a bare bones implementation of the Home page. The Home page provides a simple html template as shown next:

class Home < Page
  template %[
    <html xml:lang="en" lang="en" 
          xmlns:trellis="http://trellisframework.org/schema/trellis_1_0_0.xsd" 
          xmlns="http://www.w3.org/1999/xhtml">
      <body>
        

Some Interesting Pictures...

</body> </html> ], :format => :html end

Let’s run the spec again and confirm that we get a 200 response.

Passed Example

Figure 5 - Passed Spec (after barebones home page impl)

Running what we have so far

At this point we do have enough of the application in place so that we can also run it and visually inspect the progress so far.

To be able to launch the application self-contained we need an instance of the application on which we can invoke the #start method. Add the two following lines at the end of the Flick module in flickr.rb:

web_app = FlickrApp.new
web_app.start 3006 if __FILE__ == $PROGRAM_NAME

To launch the application run the flickr.rb ruby script like:

ruby flickr.rb

Lauching the Flickr App

Figure 6 - Launching the Flickr Trellis App

Open a browser and point it to http://localhost:3006 and you should see:

Barebones Flickr App

Figure 7 - Bare bones Flickr Trellis App

The Flickr Interestingness Component

The Flickr Interestingess Trellis Component will use the Flickr API to make a call to the “interestiness” XML-RPC web service method which returns one or more random images from Flick that have been deemed “interesting” (warning to the easily offended).

We’ll start with a simple test to get the component to render something (anything really!). Our basic test will simply expect to find an html DIV with and id attribute of “flickr_viewer” and with text content equals to “Hello”:

it "should render the flickr component" do
  get '/'
  last_response.body.should include(%[
Hello
]) end

Failed Component Test

Figure 8 - Failed Component Test

To pass this test we can provide the bare bones implementation of a Trellis stateless component. Inside the Flickr module in flickr.rb we declare the FlickrInterestingness component which descends from Trellis::Component:

class FlickrInterestingness < Component
   tag_name "flickr_interestingness"

   render do |tag|
     %[
Hello
] end end

A Trellis component has a tag_name, which by default is just the name of the component underscored and lower-cased. To provide the template or content for the component the Trellis::Component class provides the #render method which takes a block that expects a “tag” object as a parameter. We’ll go into more detail about the “tag” soon.

Next we’ll use the component in the page template via the tag, prefixed with the namespace ‘trellis’:

class Home < Page
  template %[
    <html xml:lang="en" lang="en" 
          xmlns:trellis="http://trellisframework.org/schema/trellis_1_0_0.xsd" 
          xmlns="http://www.w3.org/1999/xhtml">
      <body>
        

Some Interesting Pictures...

<trellis:flickr_interestingness/> </body> </html> ], :format => :html end

The return value of the render method is expected to be a string value that will be rendered on the page using the component. In our simple case we simply hardcoded a return value with the expected HTML snippet.

Passed Render Component Test

Figure 9 - Passed Render Component Test

As you can see a Trellis stateless component is simply a way to produce content; a tag that it is available to a Trellis template.

Read more...

Tags ,