It’s just data

Wunderbar

W

Clearly if you want to develop a real web application, you need a router, a templating language, ability to separate out your model, view, and controller, scalability, and much more.

However, at times this is both too much, and yet not enough.  I find that I write a lot of scripts that do report generation, execution of shell commands, and the like, and in many cases would like to present a richer output than plain text: things like tables, fonts, and most importantly hypertext links.  I don’t want to worry too much about DOCTYPEs, charsets, and escaping, but instead on structure, style, and content.

I’ve been extracting some of the common logic from these scripts out into a library, and recently have started refactoring that library.  Yesterday, I focused on the HTML generation parts.

What I settled on was to define all methods that start with a low line character will generate a HTML tag.  As with builder on which this library is based, these tags can have text content and attributes.  Tags can also be nested.  Logic can be freely intermixed.

Here’s an example using the library.  The example will personally greet you if you provide your name.  If no name is provided, a form is provided which enables you to provide one.

#!/usr/bin/ruby1.9.1
require 'wunderbar'

Wunderbar.html do
  _head do
    _title 'Greeter'
    _style %{
      input {display: block; margin: 2em}
    }
  end

  _body? do
    if $param.name
      _p "Hello #{$param.name}!"
    else
      _form method: 'post' do
        _p 'Please enter your name:'
        _input name: 'name'
        _input type: 'submit'
      end
    end
  end
end

Here’s example output from that script:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>Greeter</title>
    <style type="text/css">
      input {display: block; margin: 2em}
    </style>
  </head>
  <body>
    <form method="post">
      <p>Please enter your name:</p>
      <input name="name"/>
      <input type="submit"/>
    </form>
  </body>
</html>

As you can see, by default it takes care of indenting and generation of HTML.  It even knows which tags support explicit close tags and which ones do not.  Not shown in this example, but these default behaviors can be overridden by adding an exclamation mark at the end of the method name.  An example would be something like:

_p! { _ "Hello "; _span $param.name, class: 'name'; _ '!' }

An underbar which is not followed by a name generates text.  Example output:

<p>Hello <span class="name">Sam</span>!</p>

The span can be styled using css.

If your web server is set up to execute CGI scripts, deployment is as easy as copying the script into the appropriate directory.


Both the paragraph created by _p "Hello #{$param.name}!" in the first example and the one created by _p! { _ "Hello "; _span $param.name, class: 'name'; _ '!' } in the exclamation-mark-overrides-closing-tag-behavior example show opening and closing tags for p. Just a typo, a bug, or am I missing something about the exclamation mark overriding feature?

Posted by Giulio Piancastelli at

Giulio: You definitely will get a closing tag if there is any nested content.  The relevant difference is when there is no nested content.  Consider:

_script src="/jquery-min.js"

vs:

_br

In the former, you want a close tag (at least when the content is served with the MIME type of text/html).  In the latter you do not.

In the example cited, if you omit the !, the output will look like this:

<p>
  Hello 
  <span class="name">Sam</span>
  !
</p>

While pretty, this will have the unfortunate side effect of inserting a space between the name and the exclamation mark in the output.

Posted by Sam Ruby at

Add your comment