File Coverage

blib/lib/HTML/Seamstress.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             package HTML::Seamstress;
2              
3 5     5   385696 use strict;
  5         18  
  5         204  
4 5     5   28 use warnings;
  5         9  
  5         179  
5              
6 5     5   36 use Carp qw(confess);
  5         9  
  5         313  
7 5     5   26 use Cwd;
  5         9  
  5         327  
8 5     5   5365 use Data::Dumper;
  5         56358  
  5         401  
9 5     5   1961 use File::Slurp;
  5         31762  
  5         442  
10 5     5   39 use File::Spec;
  5         12  
  5         144  
11              
12              
13              
14 5     5   137634 use HTML::Element::Library;
  0            
  0            
15             use HTML::Element::Replacer;
16             use base qw/HTML::TreeBuilder HTML::Element/;
17              
18              
19             our $VERSION = '6.0' ;
20              
21              
22             sub bless_tree {
23              
24             my ($node, $class) = @_;
25              
26              
27             if (ref $node) {
28             # warn "root node($class): ", $node->as_HTML;
29             bless $node, $class ;
30              
31             foreach my $c ($node->content_list) {
32             bless_tree($c, $class);
33             }
34             }
35             }
36              
37              
38              
39             sub new_from_file { # or from a FH
40              
41             my ($class, $file) = @_;
42              
43             $class = ref $class ? ref $class : $class ;
44              
45             my $new = HTML::TreeBuilder->new_from_file($file);
46             bless_tree($new, $class);
47             #warn "CLASS: $class TREE:", $new;
48             # warn "here is new: $new ", $new->as_HTML;
49             $new;
50              
51             }
52              
53             sub new_file { # or from a FH
54              
55             my ($class, $file, %args) = @_;
56              
57             -e $file or die 'File $file does not exist';
58              
59             my $new = HTML::TreeBuilder->new;
60              
61             for my $k (keys %args) {
62             next if $k =~ /guts/ ; # scales for more actions later
63             $new->$k($args{$k});
64             }
65              
66             -e $file or die "$file does not exist";
67             $new->parse_file($file);
68             bless_tree($new, $class);
69              
70             if ($args{guts}) {
71             $new->guts;
72             } else {
73             $new;
74             }
75              
76             }
77              
78             sub html {
79             my ($class, $file, $extension) = @_;
80              
81             $extension ||= 'html';
82              
83             my $pm = File::Spec->rel2abs($file);
84             $pm =~ s!pm$!$extension!;
85             $pm;
86             }
87              
88              
89             sub eval_require {
90             my $module = shift;
91              
92             return unless $module;
93              
94             eval "require $module";
95              
96             confess $@ if $@;
97             }
98              
99             sub HTML::Element::xepand_replace {
100             my $node = shift;
101            
102             my $seamstress_module = ($node->content_list)[0] ;
103             eval "require $seamstress_module";
104             die $@ if $@;
105             $node->replace_content($seamstress_module->new) ;
106              
107             }
108              
109              
110             1;
111             __END__
112              
113             =head1 NAME
114              
115             HTML::Seamstress - HTML::Tree subclass for HTML templating via tree rewriting
116              
117             =head1 SYNOPSIS
118              
119              
120              
121             =head2 Text substitution via replace_content() API call.
122              
123             In our first example, we want to perform simple text substitution on
124             the HTML template document. The HTML file html/hello_world.htm has
125             klass attributes which serve as compiler (kompiler?) hints to Seamstress:
126              
127             <html>
128             <head>
129             <title>Hello World</title>
130             </head>
131             <body>
132             <h1>Hello World</h1>
133             <p>Hello, my name is <span id="name">dummy_name</span>.
134             <p>Today's date is <span id="date">dummy_date</span>.
135             </body>
136             </html>
137              
138             =head3 Seamstress compiles HTML to C<html::hello_world>
139              
140             shell> seamc html/hello_world.htm
141             Seamstress v2.91 generating html::hello_world from html/hello_world.htm
142              
143             Now you simply use the "compiled" version of HTML with API calls to
144             HTML::TreeBuilder, HTML::Element, and HTML::Element::LIbrary
145              
146             use html::hello_world;
147            
148             my $tree = html::hello_world->new;
149             $tree->look_down(id => name)->replace_content('terrence brannon');
150             $tree->look_down(id => date)->replace_content('5/11/1969');
151             print $tree->as_HTML;
152              
153             =head2 If-then-else with the highlander API call
154              
155             (But also see C<< $tree->passover() >> in L<HTML::Element::Library>).
156              
157             <span id="age_dialog">
158             <span id="under10">
159             Hello, does your mother know you're
160             using her AOL account?
161             </span>
162             <span id="under18">
163             Sorry, you're not old enough to enter
164             (and too dumb to lie about your age)
165             </span>
166             <span id="welcome">
167             Welcome
168             </span>
169             </span>
170              
171              
172             =head3 Compile and use the module:
173              
174             use html::age_dialog;
175              
176             my $tree = html::dialog->new;
177              
178             $tree->highlander
179             (age_dialog =>
180             [
181             under10 => sub { $_[0] < 10} ,
182             under18 => sub { $_[0] < 18} ,
183             welcome => sub { 1 }
184             ],
185             $age
186             );
187              
188             print $tree->as_HTML;
189              
190             # will only output one of the 3 dialogues based on which closure
191             # fires first
192              
193              
194             The following libraries are always available for more complicated
195             manipulations:
196              
197             =over
198              
199             =item * L<HTML::ElementTable>
200              
201             =item * L<HTML::Element::Library>
202              
203             =item * L<HTML::Element>
204              
205             =item * L<HTML::Tree>
206              
207             =back
208              
209              
210              
211             =head1 PHILOSOPHY and MOTIVATION of HTML::Seamstress
212              
213             Welcome to push-style dynamic HTML generation!
214              
215             When looking at HTML::Seamstress, we are looking at a uniquely
216             positioned 4th-generation HTML generator. Seamstress offers two sets
217             of advantages: those common to all 4th generation htmlgens and those
218             common to a subclass of L<HTML::Tree>.
219              
220              
221              
222             I think a Perlmonks node:
223             L<http://perlmonks.org/?node_id=669956>
224             sums up the job of Seamstress quite well:
225              
226             Monks,
227              
228             I'm tired of writing meta code in templating languages.
229             I'm really good at writing Perl, and good at writing HTML,
230             but I'm lousy at the templating languages (and I'm not too
231             fired up to learn more about them).
232              
233              
234             =head2 Reap 4th generation dynamic HTML generation benefits
235              
236             What advantages does this fourth way of HTML manipulation offer? Let's
237             take a look:
238              
239             =head3 Guarantee yourself well-formed HTML
240              
241             Because lower-generation dynamic HTML generators treat HTML as a
242             string, there is no insurance against poorly formed HTML.
243              
244             Take a look at these two Mason components, from
245             L<http://masonbook.com/book/chapter-5.mhtml#TOC-ANCHOR-5> :
246              
247             =over
248              
249             =item * Example 5-3. /autohandler
250              
251             <html>
252             % $m->call_next;
253             </html>
254             <%method .body_tag>
255             <%args>
256             $bgcolor => 'white'
257             $textcolor => 'black'
258             </%args>
259             <body onLoad="prepare_images( )" bgcolor="<% $bgcolor %>" text="<% $textcolor %>">
260             </%method>
261              
262             =item * Example 5-4. /important_advice.mas
263              
264             <head><title>A Blue Page With Red Text</title></head>
265            
266             <& SELF:.body_tag, bgcolor=>'blue', textcolor=>'red' &>
267             Never put anything bigger than your elbow into your ear.
268             </body>
269              
270             =back
271              
272             There is nothing guaranteeing that open tags will match close tags or
273             that close tags will even exist.
274             To make the correspondence between open and close tags even more troublesome,
275             they are in different files. And it is not easy for an HTML designer and/or
276             design tool to manipulate things once they have been shredded apart
277             like this.
278              
279              
280             With the tree-based approach of Seamstress, the end tag will exist
281             and it will match the open tag. Well-formedness is job 1 in tree-based
282             HTML rewriting!
283              
284              
285              
286              
287             =head4 HTML will be properly escaped
288              
289             =head3 Separate HTML development and its programmatic modification
290              
291             Software engineers refer to this as B<orthogonality>.
292             The contents of the document remain legal HTML/XML that can be be
293             developed using standard interactive design tools. The flow of control
294             of the code remains separate from the page. Technologies that mix
295             content and data in a single file result in code that is often
296             difficult to understand and has trouble taking full advantage of the
297             object oriented programming paradigm.
298              
299             =head3 Work at meta-level instead of object-level
300              
301             The book "Godel, Escher, Bach: An Eternal Golden Braid" by Douglas R
302             Hofstadter makes it clear what it means to operate at object-level as
303             opposed to meta-level. When you buy into earlier-generation HTML
304             generation systems you are working at object-level: you can only speak
305             and act I<as> the HTML with no ability to speak I<about> the HTML.
306              
307             Compare a bird's eye view of a city with standing on a city block and
308             you have the difference between the 4th generation of HTML development
309             versus all prior generations.
310              
311              
312             =head3 Reduced learning curve
313              
314             If you have a strong hold on
315             object-oriented Perl and a solid understand of the tree-based nature
316             of HTML, then all you need to do is read the manual pages showing how
317             Seamstress and related modules offer tree manipulation routines and
318             you are done.
319              
320             Extension just requires writing new Perl methods - a snap for any
321             object oriented Perler.
322              
323             =head3 Static validation and formatting
324              
325             Mixing Perl and HTML (by any of the generation 1-3 approaches)
326             makes it impossible to use standard validation and formatting tools
327             for either Perl or HTML.
328              
329              
330             =head3 Two full-strength programming languages: HTML and Perl
331              
332             Perl and HTML are solid technologies with years of effort behind
333             making them robust and flexible enough to meet real-world
334             technological demands.
335              
336             =head3 Object-oriented reuse and extension of HTML
337              
338             Class-based object-oriented programming makes use of inheritance and
339             other techniques to achieve maximum code reuse. This typically
340             happens by a certain base/superclass method containing common actions
341             and a derived/subclass/mixin method containing extra actions.
342              
343             A genuine tree-based approach (such as HTML::Seamstress) to HTML
344             generation is supportive of all methods of object-oriented reuse:
345             because manipulator and manipulated are separate and manipulators are
346             written in oo Perl, we can compose manipulators as we please.
347              
348             This is in contrast to inline simple object systems (as in Mason) and
349             also in contrast to the if-then approach of tt-esque systems.
350              
351             =head4 Per-page stereotyped substitution
352              
353             [ FYI: you can run the two Seamstress approaches. They are in
354             F<$DISTRO/samples/perpage> ]
355              
356             In the HTML::Mason book by O'Reilly:
357             L<http://masonbook.com/book/chapter-1.mhtml#TOC-ANCHOR-4>
358              
359             we see a technique for doing simple text insertion which varies per
360             page:
361              
362             <html>
363             <head><title>Welcome to Wally World!</title></head>
364             <body bgcolor="#CCFFCC">
365             <center><h1><% $m->base_comp->attr('head') %></h1></center>
366             % $m->call_next;
367             <center><a href="/">Home</a></center>
368             </body></html>
369              
370             # homepage.html
371             <%attr>
372             head => "Wally World Home"
373             </%attr>
374             Here at Wally World you'll find all the finest accoutrements.
375              
376             # productpage.html
377             <%attr>
378             head => "Wally World Products"
379             </%attr>
380            
381             <table> ... </table>
382              
383             So, how would we do this using Seamstress' pure Perl approach to HTML
384             refinement?
385              
386            
387             <html>
388             <head><title>Welcome to Wally World!</title></head>
389             <body bgcolor="#CCFFCC">
390             <center><h1 id=head>DUMMY_HEAD</h1></center>
391             <span id=body>DUMMY_BODY</span>
392             <center><a href="/">Home</a></center>
393             </body></html>
394              
395             # homepage.pm
396             package html::homepage;
397              
398             use base qw( HTML::Seamstress ) ;
399              
400             sub new {
401             my ($class, $c) = @_;
402              
403             my $html_file = 'html/base.html';
404              
405             my $tree = __PACKAGE__->new_from_file($html_file);
406              
407             $tree;
408             }
409              
410             sub process {
411             my ($tree, $c, $stash) = @_;
412              
413             $tree->content_handler(head => 'Wally World Home');
414             $tree->content_handler(body =>
415             'Here at Wally World you'll find all the finest accoutrements.');
416             }
417              
418             # productpage.pm
419             package html::productpage;
420              
421             use base qw( HTML::Seamstress ) ;
422              
423             sub new {
424             my ($class, $c) = @_;
425              
426             my $html_file = 'html/base.html';
427              
428             my $tree = __PACKAGE__->new_from_file($html_file);
429              
430             $tree;
431             }
432              
433             sub process {
434             my ($tree, $c, $stash) = @_;
435              
436             $tree->content_handler(head => 'Wally World Products);
437             $tree->content_handler(body => html::productpage::body->new->guts)
438             }
439              
440             We have solved our problem. However, we can create even more re-use
441             because the both of these classes are very similar. They only vary in
442             2 things: the particular head and body they provide.
443             You can abstract this with whatever methodmaker you like. I tend to
444             prefer prototype-based oop
445             over class-based, so with L<Class::Prototyped|Class::Prototyped>,
446             here's how we might do it:
447              
448             package html::abstract::common;
449              
450             use base qw(HTML::Seamstress Class::Prototyped);
451              
452              
453             sub head { 'ABSTRACT BASE METHOD' }
454             sub body { 'ABSTRACT BASE METHOD' }
455              
456             __PACKAGE__->reflect->addSlots(
457             html_file => 'html/base.html',
458             );
459              
460             sub new {
461             my $self = shift;
462              
463             my $tree = $self->new_from_file($self->html_file);
464             }
465              
466             sub process {
467             my ($tree, $c, $stash) = @_;
468             $tree->content_handler(head => $tree->head);
469             $tree->content_handler(body => $tree->body);
470             }
471              
472             1;
473              
474             and then have both of the above classes instantiate and
475             specialize this common class accordingly.
476            
477             [ Again: you can run the two Seamstress approaches. They are in
478             F<$DISTRO/samples/perpage> ]
479              
480              
481              
482             =head3 Parallel generation of a single page natural
483              
484             A tree of HTML usually contains subtrees with no
485             inter-dependance. They therefore can be manipulated in parallel. If a
486             page contains 5 areas each of which takes C<N> time, then one could
487             realize an N-fold speedup.
488              
489             =head2 Reap the benefits of using HTML::Tree
490              
491             =head3 Pragmatic HTML instead of strict X(HT)ML
492              
493             The real world is unfortunately more about getting HTML to work with
494             IE and maybe 1 or 2 other browsers. Strict XHTML may not be acceptable
495             under time and corporate pressures to get things to work with quirky
496             browsers.
497              
498             =head3 Rich API and User Contributions
499              
500             L<HTML::Tree> has a nice large set of accessor/modifier functions. If
501             that is not enough, then take a gander at Matthew Sisk's
502             contributions: L<http://search.cpan.org/~msisk/> as well as
503             L<HTML::Element::Library>.
504              
505             =head1 Seamstress contains no voodoo elements whatsoever
506              
507             If you know object-oriented Perl and know how to rewrite trees, then
508             everything that Seamstress offers will make sense: it's just various
509             boilerplates and scripts that allow your mainline code to be very
510             succinct: think of it as Class::DBI for HTML::Tree.
511              
512              
513             =over
514              
515             =item * unifying HTML and the HTML processing via a Perl class
516              
517             Seamstress contains two scripts, F<spkg.pl> and F<sbase.pl> which
518             together make it easy to access and modify an HTML file in very few
519             lines of startup code. If you have a file named
520             F<html/hello_world.html>, Seamstress makes it easy for that to become
521             the Perl module C<html::hello_world> with a C<new()> method that
522             loads and parses the HTML into an L<HTML::Tree|HTML::Tree>.
523              
524             =item * a Catalyst View class with meat-skeleton processing
525              
526             The meat-skeleton HTML production concept is discussed below.
527             L<Catalyst::Seamstress::View|Catalyst::Seamstress::View> is all ready
528             to go for rendering simple or more complex pages.
529              
530             =item * Loading in the HTML::Tree support classes
531              
532             One a Perl class has been built for your HTML, it has
533             L<HTML::Element|HTML::Element> and
534             L<HTML::Element::Library|HTML::Element::Library> as superclasses, ready
535             for you to use to rewrite the tree.
536              
537             =back
538              
539             =head2 Seamstress is here to help you use HTML::Tree, that's all.
540              
541             =head2 Unify HTML and the processing of the HTML via a Perl class
542              
543             Let's see why this is a good idea. In Mason, your Perl and HTML are
544             right there together in the same file.
545             Same with Template. Now, since Seamstress
546             operates on the HTML without touching the HTML, the operations and
547             the HTML are not in the same file. So we create a Perl module to
548             glue the HTML file to the operations we plan to perform on it.
549              
550             This module (auto-created by F<spkg.pl> and perhaps F<sbase.pl>)
551             has a constructor C<new()>, which grabs the HTML file and
552             constructs an L<HTML::Element|HTML::Element> tree from it and
553             returns it to you.
554              
555             It also contains a C<process()> subroutine which processes the
556             HTML in some way: text substitutions, unrolling list elements,
557             building tables, and whatnot.
558              
559             Finally, it contains a C<fixup()> subroutine. This subroutine is
560             designed to support the meat-skeleton paradigm, discussed above.
561             The C<process()> subroutine generated the C<$meat>. After <$meat>
562             has been placed in C<$skeleton>, there may be some page-specific
563             processing to the whole HTML page that you want to: pop in some
564             javascript, remove a copyright notice, whatever. That's what
565             this routine is for.
566              
567             Now that I've said all that, please understand that you are perfectly
568             free to call C<new()> and do what you want with the HTML tree. You
569             don't have to use C<process()> and C<fixup()>. But they are there and
570             are used by L<Catalyst::View::Seamstress> to make meat-skeleton
571             dynamic HTML development quick-and-easy (and non-greasy).
572              
573             =head3 A Perl class created by spkg.pl
574              
575             Here is our venerable little HTML file:
576              
577             metaperl@pool-71-109-151-76:/ernest/dev/catalyst-simpleapp/MyApp/root/html$ cat hello_world.html
578             <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
579             <html>
580             <head>
581             <title>Hello World</title>
582             </head>
583             <body>
584             <h1>Hello World</h1>
585             <p>Hello, my name is <span id="name">dummy_name</span>.
586             <p>Today's date is <span id="date">dummy_date</span>.
587             </body>
588             </html>
589              
590              
591             Now let's abstract this as a Perl class:
592              
593             metaperl@pool-71-109-151-76:/ernest/dev/catalyst-simpleapp/MyApp/root/html$ spkg.pl --base_pkg=MyApp::View::Seamstress --base_pkg_root=`pwd`/../../lib hello_world.html
594             comp_root........ /ernest/dev/catalyst-simpleapp/MyApp/root/
595             html_file_path... /ernest/dev/catalyst-simpleapp/MyApp/root/html/
596             html_file........ hello_world.html
597             html_file sans... hello_world
598             hello_world.html compiled to package html::hello_world
599             metaperl@pool-71-109-151-76:/ernest/dev/catalyst-simpleapp/MyApp/root/html$
600              
601             Now lets see what html::hello_world looks like. Everything other than
602             C<process()> was auto-generated:
603              
604             package html::hello_world;
605              
606             use strict;
607             use warnings;
608              
609             use HTML::TreeBuilder;
610              
611              
612             use base qw(MyApp::View::Seamstress);
613              
614             our $tree;
615              
616              
617             sub new {
618             my $file = __PACKAGE__->comp_root() . 'html/hello_world.html' ;
619              
620             -e $file or die "$file does not exist. Therefore cannot load";
621              
622             $tree =HTML::TreeBuilder->new;
623             $tree->parse_file($file);
624             $tree->eof;
625            
626             bless $tree, __PACKAGE__;
627             }
628              
629             sub process {
630             my ($self, $c, $stash) = @_;
631              
632             $tree->look_down(id => $_)->replace_content($stash->{$_})
633             for qw(name date);
634             }
635              
636             sub fixup { $tree }
637              
638             1;
639              
640              
641              
642             =head2 The meat-skeleton paradigm
643              
644             This section is written to help understanding of
645             L<Catalyst::View::Seamstress> for people who want to use Seamstress as
646             the view for their L<Catalyst|Catalyst> apps.
647              
648             HTML pages typically have meat and a skeleton. The meat varies from page
649             to page while the skeleton is fairly (though not completely)
650             static. For example, the skeleton of a webpage is usually a header, a
651             footer, and a navbar. The meat is what shows up when you click on a
652             link on the page somewhere. While the meat will change with each
653             click, the skeleton is rather static.
654              
655             The perfect example of
656              
657             Mason accomodates the meat-skeleton paradigm via
658             an C<autohandler> and C<< $m->call_next() >>. Template
659             accomodates it via its C<WRAPPER> directive.
660              
661             And Seamstress? Well, here's what you _can_ do:
662              
663             =over
664              
665             =item 1 generate the meat, C<$meat>
666              
667             This is typically what you see in the C<body> part of an HTML page
668              
669             =item 2 generate the skeleton, C<$skeleton>
670              
671             This is typically the html, head, and maybe some body
672              
673             =item 3 put the meat in the skeleton
674              
675             =back
676              
677             So, nothing about this is forced. This is just how I typically do
678             things and that is why
679             L<Catalyst::View::Seamstress|Catalyst::View::Seamstress> has support
680             for this.
681              
682             In all honesty, the meat-skeleton paradigm should be supported here
683             and called from C<Catalyst::View::Seamstress>. But the problem is, I
684             don't
685             want to create an abstract API here unless I have used the
686             meat-skeleton paradigm from one other framework besides Catalyst. Then
687             I will have a good idea of how to refactor it so any framework can
688             make good use of the paradigm.
689              
690              
691              
692            
693              
694              
695             =head1 USAGE
696              
697             The best example of usage is the F<Quickstart> directory in this
698             distribution. You can read L<HTML::Seamstress::Quickstart> and
699             actually run the code in that directory at the same time. After doing
700             so, the following sections are additional instruction.
701              
702              
703             =head2 Understand that HTML is a tree
704              
705             The best representation of this fact is this slide right here:
706              
707             L<http://xmlc.objectweb.org/doc/xmlcSlides/xmlcSlides.html#de>
708              
709             If you understand this (and maybe the rest of the slides), then you
710             have a good grip on seeing HTML as a tree.
711              
712             L<HTML::Tree::AboutTrees> does also teach this, but it takes a while
713             before he gets to what matters to us. It's a fun read nonetheless.
714              
715             Now that we've got this concept under our belts let's try some full examples.
716              
717             =head2 Install and Setup Seamstress
718              
719             The first thing to remember is that Seamstress is really just
720             convenience functions for L<HTML::Tree|HTML::Tree>. You can do
721             entirely without
722             Seamstress. It's just that my daily real-world obligations have lead
723             to a set of library functions (HTML::Element::Library) and a
724             convenient way to locate "templates" (C<spkg.pl>) that work well on
725             top of L<HTML::Tree|HTML::Tree>
726              
727             =over
728              
729             =item * move spkg.pl and sbase.pl onto your execution C<$PATH>
730              
731             C<sbase.pl> and C<spkg.pl> are used to simplify the process of
732             parsing an HTML file into HTML::Treebuilder object. In other words
733             instead of having to do this in your Perl programs:
734              
735             use HTML::TreeBuilder;
736              
737             my $tree = HTML::TreeBuilder->new_from_file('/usr/htdocs/hello.html');
738              
739             You can do this:
740              
741             use htdocs::hello;
742              
743             my $tree = htdocs::hello->new;
744              
745             The lines of code is not much different, but abstracting away absolute
746             paths is important in production environments where the absolute path
747             may come from who knows where via who knows how.
748              
749             =item * run sbase.pl
750              
751             sbase.pl will ask you 2 very simple questions. Just answer them.
752             When it is finished, it will have installed a package named
753             C<HTML::Seamstress::Base> on your C<@INC>. This module contains one
754             function, C<comp_root()> which points to a place you wouldn't
755             typically have on your C<@INC> but which you must have because your
756             HTML file and corresponding C<.pm> abstracting it are going to be
757             there.
758              
759             =item * run spkg.pl
760              
761             In the default seutp,
762             no options need be supplied to this script. They
763             are useful in cases where you have more than one document root or want
764             to inherit from more than one place.
765              
766              
767             metaperl@pool-71-109-151-76:~/www$ spkg.pl moose.html
768             comp_root........ /home/metaperl/
769             html_file_path... /home/metaperl/www/
770             html_file........ moose.html
771             html_file sans... moose
772             moose.html compiled to package www::moose
773              
774             =item * load your abstracted HTML and manipulate it
775              
776             Now, from Perl, to get the TreeBuilder object
777             representing this HTML file, we simply do this:
778              
779             use www::moose;
780            
781             my $tree = www::moose->new;
782             # manipulate tree...
783             $tree->as_HTML;
784              
785             In a mod_perl setup, you would want to pre-load your HTML and
786             L<Class::Cache|Class::Cache> was designed for this very purpose. But
787             that's a topic for another time.
788              
789             In a setup with HTML files in numerous places, I recommend setting up
790             multiple C<HTML::Seamstress::Base::here>,
791             C<HTML::Seamstress::Base::there> for each file root. To do this, you
792             will need to use the C<--base_pkg> and C<--base_pkg_root> options to
793             spkg.pl
794              
795              
796             =item * That's it!
797              
798             Now you are ready to abstract away as many files as you want with the
799             same C<spkg.pl> call. Just supply it with a different HTML file to
800             create a different package. Then C<use> them, C<new> them and
801             manipulate them and C<< $tree->as_HTML >> them at will.
802              
803             Now it's time to rock and roll!
804              
805              
806             =back
807              
808              
809             =head2 Text substitution == node mutation
810              
811             In our first example, we want to perform simple text substitution on
812             the HTML template document:
813              
814             <html>
815             <head>
816             <title>Hello World</title>
817             </head>
818             <body>
819             <h1>Hello World</h1>
820             <p>Hello, my name is <span id="name">dummy_name</span>.
821             <p>Today's date is <span id="date">dummy_date</span>.
822             </body>
823             </html>
824              
825             First save this somewhere on your document root. Then compile it with
826             C<spkg.pl>. Now you simply use
827             the "compiled" version of HTML with API calls to
828             HTML::TreeBuilder, HTML::Element, and HTML::Element::Library.
829              
830             use html::hello_world;
831            
832             my $tree = html::hello_world->new;
833             $tree->look_down(id => name)->replace_content('terrence brannon');
834             $tree->look_down(id => date)->replace_content('5/11/1969');
835             print $tree->as_HTML;
836              
837             C<replace_content()> is a convenience function in
838             L<HTML::Element::Library>.
839              
840              
841              
842             =head2 If-then-else == node(s) deletion
843              
844             (But also see C<< $tree->passover() >> in L<HTML::Element::Library>).
845              
846             <span id="age_dialog">
847             <span id="under10">
848             Hello, does your mother know you're
849             using her AOL account?
850             </span>
851             <span id="under18">
852             Sorry, you're not old enough to enter
853             (and too dumb to lie about your age)
854             </span>
855             <span id="welcome">
856             Welcome
857             </span>
858             </span>
859              
860              
861             Again, compile and use the module:
862              
863             use html::age_dialog;
864              
865             my $tree = html::dialog->new;
866              
867             $tree->highlander
868             (age_dialog =>
869             [
870             under10 => sub { $_[0] < 10} ,
871             under18 => sub { $_[0] < 18} ,
872             welcome => sub { 1 }
873             ],
874             $age
875             );
876              
877             print $tree->as_HTML;
878              
879             # will only output one of the 3 dialogues based on which closure
880             # fires first
881              
882              
883             And once again,
884             the function we used is the highlander method, also a part
885             of L<HTML::Element::Library>.
886              
887              
888             The following libraries are always available for more complicated
889             manipulations:
890              
891             =over
892              
893             =item * L<HTML::ElementSuper>
894              
895             =item * L<HTML::ElementTable>
896              
897             =item * L<HTML::Element::Library>
898              
899             =item * L<HTML::Element>
900              
901             =item * L<HTML::Tree>
902              
903             =back
904              
905              
906              
907             =head2 Looping == child/sibling proliferation
908              
909             Table unrolling, pulldown creation, C<li> unrolling, and C<dl>
910             unrolling are
911             all examples of a tree operation in which you take a child of a node
912             and clone it and then alter it in some way (replace the content, alter
913             some of its attributes), and then stick it under its parent.
914              
915             Functions for use with the common HTML elements --- C<< <table> >>,
916             C<< <ol> >>,
917             C<< <ul> >>, C<< <dl> >>, C<< <select> >>
918             are documented in
919             L<HTML::Element::Library> and are
920             prefaced with the words "Tree Building Methods".
921              
922              
923             =head2 What Seamstress offers
924              
925             Beyond the "compilation" support documented above, Seamstress offers
926             nothing more than a simple structure-modifying method,
927             expand_replace(). And to be honest, it probably shouldn't offer
928             that. But once, when de-Mason-izing a site, it was easier to keep
929             little itty-bitty components all over and so I wrote this method to
930             facilitate the process.
931              
932             Let's say you have this HTML:
933              
934             <div id="sidebar">
935              
936             <div class="sideBlock" id=mpi>mc::picBar::index</div>
937              
938             <div class="sideBlock" id=mnm>mc::navBox::makeLinks</div>
939              
940             <div class="sideBlock" id=mg>mc::gutenBox</div>
941              
942             </div>
943              
944             In this case, the content of each sideBlock is the name of a Perl
945             Seamstress-style class. As you know, when the constructor for such a
946             class is called an
947             HTML::Element, C<$E>, will be returned for it's parsed content.
948              
949             In this case, we want the content of the div element to go from the
950             being the class name to being the HTML::Element that the class
951             constructs. So to inline all 3 tags you would do the following;
952              
953             $tree->look_down(id => $_)->expand_replace for qw(mpi mnm mg);
954              
955              
956              
957             =head2 What Seamstress works with
958              
959             =head3 Class::Cache
960              
961             Useful in mod_perl environments and anywhere you want control over the
962             timing of object creation.
963              
964             =head3 The family of HTML::Tree contributions
965              
966             =over 4
967              
968             =item * L<HTML::ElementTable>
969              
970             =item * L<HTML::Element::Library>
971              
972             =item * L<HTML::Element>
973              
974             =item * L<HTML::Tree>
975              
976             =back
977              
978             =head1 METHODS
979              
980             =head2 ->new_from_file()
981              
982             This does the same thing as the TreeBuilder C<new_from_file()> method,
983             but it blesses the object into the invocant class. This makes the
984             invocant class derive from Seamstress which means it has
985             L<HTML::TreeBuilder|HTML::TreeBuilder>,
986             L<HTML::Element|HTML::Element> , and
987             L<HTML::Element::Library|HTML::Element::Library> at its disposal.
988              
989             =head2 ->html()
990              
991             This method takes C<__FILE__>, and optionally a desired C<$extension>
992             (defaults to 'html' if not given) and
993             changes the extension on C<__FILE__> from C<.pm> to C<$extension>.
994             This works well for common situations.
995              
996             =head1 A BRIEF HISTORY of Dynamic HTML Generation (Templating)
997              
998             HTML::Seamstress provides "fourth generation" dynamic HTML generation
999             (templating).
1000              
1001             In the beginning we had...
1002              
1003              
1004             =head2 First generation dynamic HTML production - server side includes
1005              
1006             First generation dynamic HTML production used server-side
1007             includes:
1008              
1009             <p>Today's date is <!--#echo var="DATE_LOCAL" --> </p>
1010              
1011             =head2 Second generation dynamic HTML production - HTML in Perl
1012              
1013             The next phase of HTML generation saw
1014             embedded HTML snippets in Perl code. For example:
1015              
1016             sub header {
1017             my $title = shift;
1018             print <<"EOHEADER";
1019             <head>
1020             <title>$title</title>
1021             </head>
1022             EOHEADER
1023             }
1024              
1025             =head2 Third generation dynamic HTML production - Perl/minilanguage in HTML
1026              
1027             The 3rd generation solutions embed
1028             programming language constructs with HTML. The language constructs
1029             are either a real language (as is with L<HTML::Mason>) or a
1030             pseudo/mini-language (as is with L<PeTaL>, L<Template> or
1031             L<HTML::Template>). Let's see some L<Template> code:
1032              
1033             <p>Hi there [% name %], are you enjoying your stay?</p>
1034              
1035             =head2 Talkin' bout them generations...
1036              
1037             Up to now, all approaches to this issue tamper with the
1038             HTML in some form or fashion:
1039              
1040             =over
1041              
1042             =item * Generation 1 adds SSI processing instructions
1043              
1044             =item * Generation 2 rips the HTML apart and adds programming elements
1045              
1046             =item * Generation 3 sprinkles programming constructs in the HTML
1047              
1048             =back
1049              
1050             =head2 Enter fourth generation dynamic HTML production - DOM style
1051              
1052             The fourth generation of HTML production is distinguished by no need
1053             for tampering with the HTML. There are a wealth of XML-based modules
1054             which provide this approach (L<XML::Twig>, L<XML::LibXML>,
1055             L<XML::TreeBuilder>, L<XML::DOM>). HTML::Seamstress is the one CPAN
1056             module based around HTML and L<HTML::Tree> for this approach.
1057              
1058             The fourth generation is also the way that a language like Javascript rewrites HTML.
1059             By using Seamstress, you can always think about manipulating your HTML in the same way!
1060              
1061              
1062              
1063             =head1 SEE ALSO
1064              
1065             =head2 Object-oriented goodies
1066              
1067             Seamstress is just glue for object-oriented tree processing in Perl (I can see my SEO rank climbing right now from that sentence!).
1068             Anyway, here is your LOOM - (List of object-oriented modules):
1069              
1070             =over 4
1071              
1072             =item * L<HTML::ELement::Replacer|HTML::Element::Replacer>
1073              
1074             =item * L<HTML::ELement::Library|HTML::Element::Library>
1075              
1076             =back
1077              
1078             =head2 Related Software
1079              
1080             I created a node at Perlmonks which catalogues push-style templating systems
1081             both in and outside of Perl:
1082              
1083             L<http://perlmonks.org/?node_id=674225>
1084              
1085             Here are two common ones:
1086             L<http://xmlc.enhydra.org>
1087             L<http://www.plope.com/software/meld3>
1088              
1089              
1090              
1091              
1092             =over
1093              
1094             =item * L<Template::Recall>
1095              
1096             The author uses what he called "reverse callbacks" to create a style very
1097             similar to Seamstress.
1098              
1099             =item * L<Petal>
1100              
1101             Based on Zope's TAL, this is a very nice and complete framework that is
1102             the basis of MkDoc, a XML application server. It offers a
1103             mini-language for XML rewriting, Seamstress does not. The philosophy
1104             of the Seamstress is the orthogonal integration of Perl and HTML not a
1105             mini-language and HTML.
1106              
1107             =item * L<XML::LibXML>
1108              
1109             By the XML guru Matt Sergeant, who is also the author of AxKit, another XML
1110             application server. This offers XPath for finding nodes
1111              
1112             =item * L<XML::DOM>
1113              
1114             If I wanted to ape XMLC entirely, I would have used TJ Mather's
1115             L<XML::DOM>. Because XMLC is based around DOM API calls. However,
1116             TreeBuilder is very handy and has a lot of nice libraries around it
1117             such L<HTML::PrettyPrinter>. The biggest win of XML::DOM is it's easy
1118             integration with L<XML::Generator>
1119              
1120             From the docs, it looks like L<XML::GDOME> is the successor to this
1121             module.
1122              
1123              
1124             =back
1125              
1126              
1127             =head2 Articles, Publications, Discussion
1128              
1129              
1130             =head3 Push style templating systems
1131              
1132             http://perlmonks.org/?node_id=674225
1133              
1134             =head3 Form Validation in CGI::Application with Seamstress
1135              
1136             L<http://perlmonks.org/?node_id=742427>
1137              
1138             =head3 Easy table rendering in modern HTML::Seamstress
1139              
1140             L<http://perlmonks.org/?node_id=768430>
1141              
1142              
1143             =head3 HTML Templating as Tree Rewriting: Part I: "If Statements"
1144              
1145             L<http://perlmonks.org/index.pl?node_id=302606>
1146              
1147             =head3 HTATR II: HTML table generation via DWIM tree rewriting
1148              
1149             L<http://perlmonks.org/index.pl?node_id=303188>
1150              
1151             =head3 Survey of Surveys on HTML Templating systems
1152              
1153             L<http://perlmonks.org/?node_id=433729>
1154              
1155             A fierce head-to-head between PeTaL and Seamstress goes on for several
1156             days in this thread!
1157              
1158              
1159             =head3 The disadvantages of mini-languages
1160              
1161             The disadvantages of mini-languages is discussed here:
1162             L<http://perlmonks.org/?node_id=428053>
1163              
1164             A striking example of the limitations of mini-languages is shown here:
1165             L<http://perlmonks.org/?node_id=493477>
1166              
1167             But the most cogent argument for using full-strength languages as
1168             opposed to mixing them occurs in the L<Text::Template> docs:
1169              
1170             When people make a template module like this one, they almost always
1171             start by inventing a special syntax for substitutions. For example,
1172             they build it so that a string like %%VAR%% is replaced with the
1173             value of $VAR. Then they realize the need extra formatting, so they
1174             put in some special syntax for formatting. Then they need a loop, so
1175             they invent a loop syntax. Pretty soon they have a new little
1176             template language.
1177              
1178             This approach has two problems: First, their little language is
1179             crippled. If you need to do something the author hasn't thought of,
1180             you lose. Second: Who wants to learn another language? You already
1181             know Perl, so why not use it?
1182              
1183             And for the Mason users whose retort is "we do use Perl!" the obvious
1184             reply is: "granted, but in an embedded fashion with ad hoc,
1185             inflexible object mechanisms, non-tree-based (hence syntactically
1186             suspect) HTML manipulation, and no ability to statically validate the
1187             Perl or HTML"
1188              
1189              
1190             =head3 Problems with JSP (JSP is similar to HTML::Mason)
1191              
1192             L<http://www.servlets.com/soapbox/problems-jsp-reaction.html>
1193              
1194             L<http://www-106.ibm.com/developerworks/library/w-friend.html?dwzone=web>
1195              
1196             L<http://www.theserverside.com/resources/article.jsp?l=XMLCvsJSP>
1197              
1198             =head3 Los Angeles Perl Mongers Talk on HTML::Seamstress
1199              
1200             L<http://www.metaperl.org>
1201              
1202             =head3 "Inside-out Templates in Perl"
1203              
1204             L<http://www.webquills.net/web-development/perl/insideout-templates-in-perl.html>
1205              
1206              
1207             =head1 SUPPORT and DEVELOPMENT
1208              
1209              
1210              
1211             =head2 IRC
1212              
1213             L<irc://irc.perl.org/#html-seamstress>
1214              
1215             =head2 Mailing List
1216              
1217             L<http://lists.sourceforge.net/lists/listinfo/seamstress-discuss>
1218              
1219             =head2 Source repo
1220              
1221             L<http://github.com/metaperl/html-seamstress/tree/master>
1222              
1223             =head1 AUTHOR
1224              
1225             Terrence Brannon, C<< tbone@cpan.org >>
1226              
1227             =head2 ACKNOWLEDGEMENTS
1228              
1229             I would like to thank
1230              
1231             =over
1232              
1233             =item * Chris Winters for exposing me to XMLC
1234              
1235             =item * Paul Lucas for writing C<HTML_Tree>
1236              
1237             L<http://homepage.mac.com/pauljlucas/software/html_tree/>
1238              
1239             HTML_Tree is a C++ HTML manipulator with a Perl interface. Upon using
1240             his Perl interface, I began to notice limitations and extended his
1241             Perl interface. The author was not interested in working with me or my
1242             extensions, so I had to continue on a separate path.
1243              
1244             =item * C<johnnywang> for his post about dynamic HTML generation
1245              
1246             L<http://perlmonks.org/?node_id=505080>.
1247              
1248             =item * Matthew Sisk and John Porter for lively personal discussions
1249              
1250             =item * Matthew Hodgson (Arathorn on #catalyst)
1251              
1252             for brainstorming with me on how to produce a Catalyst view
1253             for Seamstress
1254              
1255             =item * Gary Ashton-Jones
1256              
1257             for a patch to spkg.pl and being the first person to join
1258             the C<seamstress-discuss> mailing list without any
1259             solicitation from me C<:)>.
1260              
1261             =item * Brock Wilcox
1262              
1263             for ramming heads with me over possibly using CSS to specify tree
1264             rewrite actions:
1265              
1266             sub fix_age : ID(age) {
1267              
1268             (shift)->replace_content(shift()) ;
1269              
1270             }
1271              
1272             Just an idea...
1273              
1274             =item * Ian Tegebo
1275              
1276             For noticing some doc bugs in the Quickstart guide.
1277              
1278             =item *
1279              
1280             =back
1281              
1282              
1283             =head1 COPYRIGHT AND LICENSE
1284              
1285             Copyright RANGE(1999,NOW()) by Terrence Brannon.
1286              
1287             This library is free software; you can redistribute it and/or modify
1288             it under the same terms as Perl itself.
1289              
1290             =cut