Recently I began to doubt that the compiler hints were a worthwhile
thing to use when creating DOM-like accessor classes to HTML documents.

This post shows the current usage of Seamstress with compiler
hints. And then gives a plethora of reasons why such a design was, on
the whole, a waste of time and should be dropped immediately :).

Overview

    HTML::Seamstress is a Perl module which supports HTML templating via
    tree-manipulations. It is based on HTML::Tree. The latest version of
    this module was inspired by the amazingly concise code that one can
    write with Class::DBI after setting up an object-oriented hierarchy.

    Here are two samples of tree-based templating as the module is developed
    now:

  Text substitution
    In our first example, we want to perform simple text substitution on the
    HTML template document. The HTML file html/hello_world.htm has klass
    attributes which serve as compiler (kompiler?) hints to Seamstress:

         <html>
         <head>
           <title>Hello World</title>
         </head>
         <body>
         <h1>Hello World</h1>
           <p>Hello, my name is <klass=content span id="name">dummy_name</span>.
           <p>Today's date is <klass=content span id="date">dummy_date</span>.
         </body>
         </html>

   Seamstress compiles HTML to "html::hello_world"
     shell> seamc html/hello_world.htm
     Seamstress v2.91 generating html::hello_world from html/hello_world.htm
    Now you simply use the compiled version of HTML with object-oriented
    accessors.

         use html::hello_world; 
 
         my $tree = html::hello_world->new; 
         $tree->name('terrence brannon')->date('5/11/1969')->as_HTML;

  If-then-else with the highlander kompiler hint
    The "highlander" kompiler hint is used to mark a subtree of HTML in
    which only one child should survive:

         <span klass="highlander" id="age_dialog">
            <span id="under10">
               Hello, does your mother know you're 
               using her AOL account?
            </span>
            <span id="under18">
               Sorry, you're not old enough to enter 
               (and too dumb to lie about your age)
            </span>
            <span id="welcome">
               Welcome
            </span>
         </span>

   Compile and use the module:
         use html::highlander;

         my $tree = html::highlander->new;

         $tree->age_dialog
            (
             [
              under10 => sub { $_[0] < 10} , 
              under18 => sub { $_[0] < 18} ,
              welcome => sub { 1 }
             ],
             $age
            )->as_HTML;

          # will only output one of the 3 dialogues based on which closure 
          # fires first 

The dilemmas
  Use of the klass tag as a kompiler hint
    The biggest dilemma I have is whether to alter the HTML by use of the
    "klass" attribute as a kompiler hint. The original reason for writing
    Seamstress was to provide HTML templating via pure Perl and pure HTML.
    The original connection between the two was the "id" tag, a standard
    HTML attribute which must be unique for every element within an HTML4.01
    document. The Java framework which inspired the development of
    Seamstress, XMLC, uses only standard "class" and "id" tags to generate
    Java accessors to HTML documents.

    If I wanted to eliminate the "klass" attribute, then I would have to
    provide command line arguments to the Seamstress compiler to generate
    certain types of methods:

    $> ./seamc -klass="name content" -klass="date content" hello_world.html

    But that would get tedious when dealing with a ton of files.

    So, even though the HTML would be slightly modified with the use of the
    "klass" tag, I think I would prefer that over having to supply kompiler
    hints at the shell.

  Use of any magic whatsoever
    Currently, Seamstress supplies accessors which are "intelligent" in two
    ways. One, they acts as getters or setters based on whether or not they
    are supplied arguments:

      $tree->name ; # returns $tree->look_down(id => 'name');
      $tree->name(12); # will call a setter method based on compiler hint

    Two, they act as specialized setters based on compiler hints. Since
    there are numerous ways to "set" a node in a tree (you can set its
    contents, you can set its children's contents, you can set an attribute,
    you can delete all but one of the children, etc.), the tree operation
    that is called is based on the compiler hint.

    However, it is not clear that all the extra work to make the inline code
    succint is worthwhile. The "magical" version of the hello_world.pm
    program is:

      $tree->name('terrence brannon')->date('5/11/1969')->as_HTML;

    The "plain Jane" version is:

      $tree->get_name->replace_content('terrence brannon')
           ->get_date->replace_conent('5/11/69);

    I like the explictness of the plain version.

    The plain version would simply have the Seamstress compiler create
    get_$id accessors for any HTML element in the document with an id tag. This
    plain version is very attractive for a number of reasons:

    * the HTML file has zero shock value to the HTML designer
    * no kompiler hints need to be written
    * no worry about needing to expand the kompiler hints into a
    mini-langauge
        Over time, mini-languages tend to need more and more. If all
        shortcuts and idioms are handled by library methods, then the full
        power of Perl can be brought to bear on any situation.

    * Similar to the way XMLC works for Java
        XMLC does not use any extra tags when creating DOM accessor classes
        to HTML files. The widespread success and usage of XMLC implies that
        none are necessary.

        If I wanted 100% compatibility with XMLC I would be using Terrence
        Mather's XML::DOM. However, HTML::ElementTable is an excellent
        module for imperative tree-building in Perl and I want to be
        able to integrate its results into my HTML templates.
 

Conclusion
    It is very depressing to have to rip out my compiler's guts. I spent a
    good amount of time building the compiler and code-generator and
    creating tests for it. Now, the compiler is going to be much simpler and
    all of the idiomatic processing will exist in standalone tree-processing
    libraries such as HTML::Element::Library (to be uploaded) or
    HTML::ElementTable.

    However, I think this is a change for the better. In fact, it is nice to
    know that all tree processing actions will be handled like this:

      $tree->$id_name->$library_method(@method_args);

    instead of

      $tree->$id_name(@args_to_magic_method)

-- 
        Carter's Compass: I know I'm on the right track when,
           by deleting something, I'm adding functionality.


_______________________________________________
sw-design mailing list
sw-design@metaperl.com
http://metaperl.com/cgi-bin/mailman/listinfo/sw-design

Reply via email to