source: text-formbuilder/trunk/lib/Text/FormBuilder.pm @ 59

Last change on this file since 59 was 59, checked in by peichman, 20 years ago

added a class="fieldgroup" attr to field group spans
added a brace_block to the parser, to parse [...] with nested [...]'s

File size: 36.7 KB
Line 
1package Text::FormBuilder;
2
3use strict;
4use warnings;
5
6use base qw(Exporter Class::ParseText::Base);
7use vars qw($VERSION @EXPORT);
8
9$VERSION = '0.09_01';
10@EXPORT = qw(create_form);
11
12use Carp;
13use Text::FormBuilder::Parser;
14use CGI::FormBuilder;
15
16# the static default options passed to CGI::FormBuilder->new
17my %DEFAULT_OPTIONS = (
18    method => 'GET',
19    javascript => 0,
20    keepextras => 1,
21);
22
23# the built in CSS for the template
24my $DEFAULT_CSS = <<END;
25table { padding: 1em; }
26#author, #footer { font-style: italic; }
27caption h2 { padding: .125em .5em; background: #ccc; text-align: left; }
28th { text-align: left; }
29th h3 { padding: .125em .5em; background: #eee; }
30th.label { font-weight: normal; text-align: right; vertical-align: top; }
31td ul { list-style: none; padding-left: 0; margin-left: 0; }
32.note { background: #eee; }
33.sublabel { color: #999; }
34.invalid { background: red; }
35END
36
37# default messages that can be localized
38my %DEFAULT_MESSAGES = (
39    text_author   => 'Created by %s',
40    text_madewith => 'Made with %s version %s',
41    text_required => '(Required fields are marked in <strong>bold</strong>.)',
42    text_invalid  => 'Missing or invalid value.',
43);
44
45my $DEFAULT_CHARSET = 'iso-8859-1';
46
47# options to clean up the code with Perl::Tidy
48my $TIDY_OPTIONS = '-nolq -ci=4 -ce';
49
50my $HTML_EXTS   = qr/\.html?$/;
51my $MODULE_EXTS = qr/\.pm$/;
52my $SCRIPT_EXTS = qr/\.(pl|cgi)$/;
53
54# superautomagical exported function
55sub create_form {
56    my ($source, $options, $destination) = @_;
57    my $parser = __PACKAGE__->parse($source);
58    $parser->build(%{ $options || {} });
59    if ($destination) {
60        if (ref $destination) {
61            croak '[' . (caller(0))[3] . "] Don't know what to do with a ref for $destination";
62            #TODO: what DO ref dests mean?
63        } else {
64            # write webpage, script, or module
65            if ($destination =~ $MODULE_EXTS) {
66                $parser->write_module($destination, 1);
67            } elsif ($destination =~ $SCRIPT_EXTS) {
68                $parser->write_script($destination, 1);
69            } else {
70                $parser->write($destination);
71            }
72        }
73    } else {
74        defined wantarray ? return $parser->form : $parser->write;
75    }
76}
77
78# subclass of Class::ParseText::Base
79sub init {
80    my $self = shift;
81    $self->{parser}         = Text::FormBuilder::Parser->new;
82    $self->{start_rule}     = 'form_spec';
83    $self->{ensure_newline} = 1;
84    return $self;
85}
86
87# this is where a lot of the magic happens
88sub build {
89    my ($self, %options) = @_;
90   
91    # our custom %options:
92    # form_only: use only the form part of the template
93    my $form_only = $options{form_only};
94   
95    # css, extra_css: allow for custom inline stylesheets
96    #   neat trick: css => '@import(my_external_stylesheet.css);'
97    #   will let you use an external stylesheet
98    #   CSS Hint: to get multiple sections to all line up their fields,
99    #   set a standard width for th.label
100    my $css;
101    $css = $options{css} || $DEFAULT_CSS;
102    $css .= $options{extra_css} if $options{extra_css};
103   
104    # messages
105    # code pulled (with modifications) from CGI::FormBuilder
106    if ($options{messages}) {
107        # if its a hashref, we'll just pass it on to CGI::FormBuilder
108       
109        if (my $ref = ref $options{messages}) {
110            # hashref pass on to CGI::FormBuilder
111            croak "[Text::FormBuilder] Argument to 'messages' option must be a filename or hashref" unless $ref eq 'HASH';
112            while (my ($key,$value) = each %DEFAULT_MESSAGES) {
113                $options{messages}{$key} ||= $DEFAULT_MESSAGES{$key};
114            }
115        } else {
116            # filename, just *warn* on missing, and use defaults
117            if (-f $options{messages} && -r _ && open(MESSAGES, "< $options{messages}")) {
118                $options{messages} = { %DEFAULT_MESSAGES };
119                while(<MESSAGES>) {
120                    next if /^\s*#/ || /^\s*$/;
121                    chomp;
122                    my($key,$value) = split ' ', $_, 2;
123                    ($options{messages}{$key} = $value) =~ s/\s+$//;
124                }
125                close MESSAGES;
126            } else {
127                carp '[' . (caller(0))[3] . "] Could not read messages file $options{messages}: $!";
128            }
129        }
130    } else {
131        $options{messages} = { %DEFAULT_MESSAGES };
132    }
133   
134    # character set
135    my $charset = $options{charset};
136   
137    # save the build options so they can be used from write_module
138    $self->{build_options} = { %options };
139   
140    # remove our custom options before we hand off to CGI::FormBuilder
141    delete $options{$_} foreach qw(form_only css extra_css charset);
142   
143    # expand groups
144    if (my %groups = %{ $self->{form_spec}{groups} || {} }) {
145        for my $section (@{ $self->{form_spec}{sections} || [] }) {
146            foreach (grep { $$_[0] eq 'group' } @{ $$section{lines} }) {
147                $$_[1]{group} =~ s/^\%//;       # strip leading % from group var name
148               
149                if (exists $groups{$$_[1]{group}}) {
150                    my @fields; # fields in the group
151                    push @fields, { %$_ } foreach @{ $groups{$$_[1]{group}} };
152                    for my $field (@fields) {
153                        $$field{label} ||= ucfirst $$field{name};
154                        $$field{name} = "$$_[1]{name}_$$field{name}";               
155                    }
156                    $_ = [ 'group', { label => $$_[1]{label} || ucfirst(join(' ',split('_',$$_[1]{name}))), group => \@fields } ];
157                }
158            }
159        }
160    }
161   
162    # the actual fields that are given to CGI::FormBuilder
163    # make copies so that when we trim down the sections
164    # we don't lose the form field information
165    $self->{form_spec}{fields} = [];
166   
167    for my $section (@{ $self->{form_spec}{sections} || [] }) {
168        for my $line (@{ $$section{lines} }) {
169            if ($$line[0] eq 'group') {
170                push @{ $self->{form_spec}{fields} }, { %{$_} } foreach @{ $$line[1]{group} };
171            } elsif ($$line[0] eq 'field') {
172                push @{ $self->{form_spec}{fields} }, { %{$$line[1]} };
173            }
174        }
175    }
176   
177    # substitute in custom validation subs and pattern definitions for field validation
178    my %patterns = %{ $self->{form_spec}{patterns} || {} };
179    my %subs = %{ $self->{form_spec}{subs} || {} };
180   
181    foreach (@{ $self->{form_spec}{fields} }) {
182        if ($$_{validate}) {
183            if (exists $patterns{$$_{validate}}) {
184                $$_{validate} = $patterns{$$_{validate}};
185            # TODO: need the Data::Dumper code to work for this
186            # for now, we just warn that it doesn't work
187            } elsif (exists $subs{$$_{validate}}) {
188                warn '[' . (caller(0))[3] . "] validate coderefs don't work yet";
189                delete $$_{validate};
190##                 $$_{validate} = $subs{$$_{validate}};
191            }
192        }
193    }
194   
195    # get user-defined lists; can't make this conditional because
196    # we need to be able to fall back to CGI::FormBuilder's lists
197    # even if the user didn't define any
198    my %lists = %{ $self->{form_spec}{lists} || {} };
199   
200    # substitute in list names
201    foreach (@{ $self->{form_spec}{fields} }) {
202        next unless $$_{list};
203       
204        $$_{list} =~ s/^\@//;   # strip leading @ from list var name
205       
206        # a hack so we don't get screwy reference errors
207        if (exists $lists{$$_{list}}) {
208            my @list;
209            push @list, { %$_ } foreach @{ $lists{$$_{list}} };
210            $$_{options} = \@list;
211        } else {
212            # assume that the list name is a builtin
213            # and let it fall through to CGI::FormBuilder
214            $$_{options} = $$_{list};
215        }
216    } continue {
217        delete $$_{list};
218    }
219   
220    # special case single-value checkboxes
221    foreach (grep { $$_{type} && $$_{type} eq 'checkbox' } @{ $self->{form_spec}{fields} }) {
222        unless ($$_{options}) {
223            $$_{options} = [ { $$_{name} => $$_{label} || ucfirst join(' ',split(/_/,$$_{name})) } ];
224        }
225    }
226   
227    # use the list for displaying checkbox groups
228    foreach (@{ $self->{form_spec}{fields} }) {
229        $$_{ulist} = 1 if ref $$_{options} and @{ $$_{options} } >= 3;
230    }
231   
232    # remove extraneous undefined values
233    for my $field (@{ $self->{form_spec}{fields} }) {
234        defined $$field{$_} or delete $$field{$_} foreach keys %{ $field };
235    }
236   
237    # remove false $$_{required} params because this messes up things at
238    # the CGI::FormBuilder::field level; it seems to be marking required
239    # based on the existance of a 'required' param, not whether it is
240    # true or defined
241    $$_{required} or delete $$_{required} foreach @{ $self->{form_spec}{fields} };
242
243    foreach (@{ $self->{form_spec}{sections} }) {
244        #for my $line (grep { $$_[0] eq 'field' } @{ $$_{lines} }) {
245        for my $line (@{ $$_{lines} }) {
246            if ($$line[0] eq 'field') {
247                $$line[1] = $$line[1]{name};
248##                 $_ eq 'name' or delete $$line[1]{$_} foreach keys %{ $$line[1] };
249##             } elsif ($$line[0] eq 'group') {
250##                 $$line[1] = [ map { $$_{name} } @{ $$line[1]{group} } ];
251            }
252        }
253    }
254   
255    $self->{form} = CGI::FormBuilder->new(
256        %DEFAULT_OPTIONS,
257        # need to explicity set the fields so that simple text fields get picked up
258        fields   => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ],
259        required => [ map { $$_{name} } grep { $$_{required} } @{ $self->{form_spec}{fields} } ],
260        title => $self->{form_spec}{title},
261        text  => $self->{form_spec}{description},
262        template => {
263            type => 'Text',
264            engine => {
265                TYPE       => 'STRING',
266                SOURCE     => $form_only ? $self->_form_template : $self->_template($css, $charset),
267                DELIMITERS => [ qw(<% %>) ],
268            },
269            data => {
270                sections    => $self->{form_spec}{sections},
271                author      => $self->{form_spec}{author},
272                description => $self->{form_spec}{description},
273            },
274        },
275        %options,
276    );
277    $self->{form}->field(%{ $_ }) foreach @{ $self->{form_spec}{fields} };
278   
279    # mark structures as built
280    $self->{built} = 1;
281   
282    return $self;
283}
284
285sub write {
286    my ($self, $outfile) = @_;
287   
288    # automatically call build if needed to
289    # allow the new->parse->write shortcut
290    $self->build unless $self->{built};
291   
292    if ($outfile) {
293        open FORM, "> $outfile";
294        print FORM $self->form->render;
295        close FORM;
296    } else {
297        print $self->form->render;
298    }
299}
300
301# generates the core code to create the $form object
302# the generated code assumes that you have a CGI.pm
303# object named $q
304sub _form_code {
305    my $self = shift;
306   
307    # automatically call build if needed to
308    # allow the new->parse->write shortcut
309    $self->build unless $self->{built};
310   
311    # conditionally use Data::Dumper
312    eval 'use Data::Dumper;';
313    die "Can't write module; need Data::Dumper. $@" if $@;
314   
315    $Data::Dumper::Terse = 1;           # don't dump $VARn names
316    $Data::Dumper::Quotekeys = 0;       # don't quote simple string keys
317   
318    my $css;
319    $css = $self->{build_options}{css} || $DEFAULT_CSS;
320    $css .= $self->{build_options}{extra_css} if $self->{build_options}{extra_css};
321   
322    my %options = (
323        %DEFAULT_OPTIONS,
324        title => $self->{form_spec}{title},
325        text  => $self->{form_spec}{description},
326        fields   => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ],
327        required => [ map { $$_{name} } grep { $$_{required} } @{ $self->{form_spec}{fields} } ],
328        template => {
329            type => 'Text',
330            engine => {
331                TYPE       => 'STRING',
332                SOURCE     => $self->{build_options}{form_only} ? 
333                                $self->_form_template : 
334                                $self->_template($css, $self->{build_options}{charset}),
335                DELIMITERS => [ qw(<% %>) ],
336            },
337            data => {
338                sections    => $self->{form_spec}{sections},
339                author      => $self->{form_spec}{author},
340                description => $self->{form_spec}{description},
341            },
342        }, 
343        %{ $self->{build_options} },
344    );
345   
346    # remove our custom options
347    delete $options{$_} foreach qw(form_only css extra_css);
348   
349    my %module_subs;
350    my $d = Data::Dumper->new([ \%options ], [ '*options' ]);
351   
352    use B::Deparse;
353    my $deparse = B::Deparse->new;
354##     
355##     #TODO: need a workaround/better solution since Data::Dumper doesn't like dumping coderefs
356##     foreach (@{ $self->{form_spec}{fields} }) {
357##         if (ref $$_{validate} eq 'CODE') {
358##             my $body = $deparse->coderef2text($$_{validate});
359##             #$d->Seen({ "*_validate_$$_{name}" => $$_{validate} });
360##             #$module_subs{$$_{name}} = "sub _validate_$$_{name} $$_{validate}";
361##         }
362##     }   
363##     my $sub_code = join("\n", each %module_subs);
364   
365    my $form_options = keys %options > 0 ? $d->Dump : '';
366   
367    my $field_setup = join(
368        "\n", 
369        map { '$form->field' . Data::Dumper->Dump([$_],['*field']) . ';' } @{ $self->{form_spec}{fields} }
370    );
371   
372    return <<END;
373my \$form = CGI::FormBuilder->new(
374    params => \$q,
375    $form_options
376);
377
378$field_setup
379END
380}
381
382sub write_module {
383    my ($self, $package, $use_tidy) = @_;
384
385    croak '[' . (caller(0))[3] . '] Expecting a package name' unless $package;
386   
387    # remove a trailing .pm
388    $package =~ s/\.pm$//;
389##     warn  "[Text::FromBuilder::write_module] Removed extra '.pm' from package name\n" if $package =~ s/\.pm$//;
390   
391    my $form_code = $self->_form_code;
392   
393    my $module = <<END;
394package $package;
395use strict;
396use warnings;
397
398use CGI::FormBuilder;
399
400sub get_form {
401    my \$q = shift;
402
403    $form_code
404   
405    return \$form;
406}
407
408# module return
4091;
410END
411
412    _write_output_file($module, (split(/::/, $package))[-1] . '.pm', $use_tidy);
413    return $self;
414}
415
416sub write_script {
417    my ($self, $script_name, $use_tidy) = @_;
418
419    croak '[' . (caller(0))[3] . '] Expecting a script name' unless $script_name;
420   
421    my $form_code = $self->_form_code;
422   
423    my $script = <<END;
424#!/usr/bin/perl
425use strict;
426use warnings;
427
428use CGI;
429use CGI::FormBuilder;
430
431my \$q = CGI->new;
432
433$form_code
434   
435unless (\$form->submitted && \$form->validate) {
436    print \$form->render;
437} else {
438    # do something with the entered data
439}
440END
441   
442    _write_output_file($script, $script_name, $use_tidy);   
443    return $self;
444}
445
446sub _write_output_file {
447    my ($source_code, $outfile, $use_tidy) = @_;
448    if ($use_tidy) {
449        # clean up the generated code, if asked
450        eval 'use Perl::Tidy';
451        unless ($@) {
452            Perl::Tidy::perltidy(source => \$source_code, destination => $outfile, argv => $TIDY_OPTIONS);
453        } else {
454            carp '[' . (caller(0))[3] . "] Can't tidy the code: $@" if $@;
455            # fallback to just writing it as-is
456            open OUT, "> $outfile" or die $!;
457            print OUT $source_code;
458            close OUT;
459        }
460    } else {
461        # otherwise, just print as is
462        open OUT, "> $outfile" or die $!;
463        print OUT $source_code;
464        close OUT;
465    }
466}
467
468
469sub form {
470    my $self = shift;
471   
472    # automatically call build if needed to
473    # allow the new->parse->write shortcut
474    $self->build unless $self->{built};
475
476    return $self->{form};
477}
478
479sub _form_template {
480    my $self = shift;
481    my $msg_required = $self->{build_options}{messages}{text_required};
482    my $msg_invalid = $self->{build_options}{messages}{text_invalid};
483    return q{<% $description ? qq[<p id="description">$description</p>] : '' %>
484<% (grep { $_->{required} } @fields) ? qq[<p id="instructions">} . $msg_required . q{</p>] : '' %>
485<% $start %>
486<%
487    # drop in the hidden fields here
488    $OUT = join("\n", map { $$_{field} } grep { $$_{type} eq 'hidden' } @fields);
489%>} .
490q[
491<%
492    SECTION: while (my $section = shift @sections) {
493        $OUT .= qq[<table id="] . ($$section{id} || '_default') . qq[">\n];
494        $OUT .= qq[  <caption><h2 class="sectionhead">$$section{head}</h2></caption>] if $$section{head};
495        TABLE_LINE: for my $line (@{ $$section{lines} }) {
496            if ($$line[0] eq 'head') {
497                $OUT .= qq[  <tr><th class="subhead" colspan="2"><h3>$$line[1]</h3></th></tr>\n]
498            } elsif ($$line[0] eq 'note') {
499                $OUT .= qq[  <tr><td class="note" colspan="2">$$line[1]</td></tr>\n]
500            } elsif ($$line[0] eq 'field') {
501                local $_ = $field{$$line[1]};
502               
503                # skip hidden fields in the table
504                next TABLE_LINE if $$_{type} eq 'hidden';
505               
506                $OUT .= $$_{invalid} ? qq[  <tr class="invalid">] : qq[  <tr>];
507               
508                # special case single value checkboxes
509                if ($$_{type} eq 'checkbox' && @{ $$_{options} } == 1) {
510                    $OUT .= qq[<th></th>];
511                } else {
512                    $OUT .= '<th class="label">' . ($$_{required} ? qq[<strong class="required">$$_{label}:</strong>] : "$$_{label}:") . '</th>';
513                }
514               
515                # mark invalid fields
516                if ($$_{invalid}) {
517                    $OUT .= "<td>$$_{field} $$_{comment} ] . $msg_invalid . q[</td>";
518                } else {
519                    $OUT .= qq[<td>$$_{field} $$_{comment}</td>];
520                }
521               
522                $OUT .= qq[</tr>\n];
523               
524            } elsif ($$line[0] eq 'group') {
525                my @group_fields = map { $field{$_} } map { $$_{name} } @{ $$line[1]{group} };
526                $OUT .= (grep { $$_{invalid} } @group_fields) ? qq[  <tr class="invalid">\n] : qq[  <tr>\n];
527               
528                $OUT .= '    <th class="label">';
529                $OUT .= (grep { $$_{required} } @group_fields) ? qq[<strong class="required">$$line[1]{label}:</strong>] : "$$line[1]{label}:";
530                $OUT .= qq[</th>\n];
531               
532                $OUT .= qq[    <td><span class="fieldgroup">];
533                $OUT .= join(' ', map { qq[<small class="sublabel">$$_{label}</small> $$_{field} $$_{comment}] } @group_fields);
534                $OUT .= " $msg_invalid" if $$_{invalid};
535               
536                $OUT .= qq[    </span></td>\n];
537                $OUT .= qq[  </tr>\n];
538            }   
539        }
540        # close the table if there are sections remaining
541        # but leave the last one open for the submit button
542        $OUT .= qq[</table>\n] if @sections;
543    }
544%>
545  <tr><th></th><td style="padding-top: 1em;"><% $submit %></td></tr>
546</table>
547<% $end %>
548];
549}
550
551# usage: $self->_pre_template($css, $charset)
552sub _pre_template {
553    my $self = shift;
554    my $css = shift || $DEFAULT_CSS;
555    my $charset = shift || $DEFAULT_CHARSET;
556    my $msg_author = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_author}) . '", $author)';
557    return 
558q[<html>
559<head>
560  <meta http-equiv="Content-Type" content="text/html; charset=] . $charset . q[" />
561  <title><% $title %><% $author ? ' - ' . ucfirst $author : '' %></title>
562  <style type="text/css">
563] . $css . q[  </style>
564  <% $jshead %>
565</head>
566<body>
567
568<h1><% $title %></h1>
569<% $author ? qq[<p id="author">] . ] . $msg_author . q{ . q[</p>] : '' %>
570};
571}
572
573sub _post_template {
574    my $self = shift;
575    my $msg_madewith = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_madewith}) .
576        '", q[<a href="http://formbuilder.org/">CGI::FormBuilder</a>], CGI::FormBuilder->VERSION)';
577   
578    return qq[<hr />
579<div id="footer">
580  <p id="creator"><% $msg_madewith %></p>
581</div>
582</body>
583</html>
584];
585}
586
587# usage: $self->_template($css, $charset)
588sub _template {
589    my $self = shift;
590    return $self->_pre_template(@_) . $self->_form_template . $self->_post_template;
591}
592
593sub dump { 
594    eval "use YAML;";
595    unless ($@) {
596        print YAML::Dump(shift->{form_spec});
597    } else {
598        warn '[' . (caller(0))[3] . "] Can't dump form spec structure using YAML: $@";
599    }
600}
601
602
603# module return
6041;
605
606=head1 NAME
607
608Text::FormBuilder - Create CGI::FormBuilder objects from simple text descriptions
609
610=head1 SYNOPSIS
611
612    use Text::FormBuilder;
613   
614    my $parser = Text::FormBuilder->new;
615    $parser->parse($src_file);
616   
617    # returns a new CGI::FormBuilder object with
618    # the fields from the input form spec
619    my $form = $parser->form;
620   
621    # write a My::Form module to Form.pm
622    $parser->write_module('My::Form');
623
624=head1 REQUIRES
625
626L<Parse::RecDescent>,
627L<CGI::FormBuilder>,
628L<Text::Template>,
629L<Class::Base>
630
631=head1 DESCRIPTION
632
633This module is intended to extend the idea of making it easy to create
634web forms by allowing you to describe them with a simple langauge. These
635I<formspecs> are then passed through this module's parser and converted
636into L<CGI::FormBuilder> objects that you can easily use in your CGI
637scripts. In addition, this module can generate code for standalone modules
638which allow you to separate your form design from your script code.
639
640A simple formspec looks like this:
641
642    name//VALUE
643    email//EMAIL
644    langauge:select{English,Spanish,French,German}
645    moreinfo|Send me more information:checkbox
646    interests:checkbox{Perl,karate,bass guitar}
647
648This will produce a required C<name> test field, a required C<email> text
649field that must look like an email address, an optional select dropdown
650field C<langauge> with the choices English, Spanish, French, and German,
651an optional C<moreinfo> checkbox labeled ``Send me more information'', and
652finally a set of checkboxes named C<interests> with the choices Perl,
653karate, and bass guitar.
654
655=head1 METHODS
656
657=head2 new
658
659    my $parser = Text::FormBuilder->new;
660
661=head2 parse
662
663    # parse a file (regular scalar)
664    $parser->parse($filename);
665   
666    # or pass a scalar ref for parse a literal string
667    $parser->parse(\$string);
668   
669    # or an array ref to parse lines
670    $parser->parse(\@lines);
671
672Parse the file or string. Returns the parser object. This method,
673along with all of its C<parse_*> siblings, may be called as a class
674method to construct a new object.
675
676=head2 parse_file
677
678    $parser->parse_file($src_file);
679   
680    # or as a class method
681    my $parser = Text::FormBuilder->parse($src_file);
682
683=head2 parse_text
684
685    $parser->parse_text($src);
686
687Parse the given C<$src> text. Returns the parser object.
688
689=head2 parse_array
690
691    $parser->parse_array(@lines);
692
693Concatenates and parses C<@lines>. Returns the parser object.
694
695=head2 build
696
697    $parser->build(%options);
698
699Builds the CGI::FormBuilder object. Options directly used by C<build> are:
700
701=over
702
703=item C<form_only>
704
705Only uses the form portion of the template, and omits the surrounding html,
706title, author, and the standard footer. This does, however, include the
707description as specified with the C<!description> directive.
708
709=item C<css>, C<extra_css>
710
711These options allow you to tell Text::FormBuilder to use different
712CSS styles for the built in template. A value given a C<css> will
713replace the existing CSS, and a value given as C<extra_css> will be
714appended to the CSS. If both options are given, then the CSS that is
715used will be C<css> concatenated with C<extra_css>.
716
717If you want to use an external stylesheet, a quick way to get this is
718to set the C<css> parameter to import your file:
719
720    css => '@import(my_external_stylesheet.css);'
721
722=item C<messages>
723
724This works the same way as the C<messages> parameter to
725C<< CGI::FormBuilder->new >>; you can provide either a hashref of messages
726or a filename.
727
728The default messages used by Text::FormBuilder are:
729
730    text_author       Created by %s
731    text_madewith     Made with %s version %s
732    text_required     (Required fields are marked in <strong>bold</strong>.)
733    text_invalid      Missing or invalid value.
734
735Any messages you set here get passed on to CGI::FormBuilder, which means
736that you should be able to put all of your customization messages in one
737big file.
738
739=item C<charset>
740
741Sets the character encoding for the generated page. The default is ISO-8859-1.
742
743=back
744
745All other options given to C<build> are passed on verbatim to the
746L<CGI::FormBuilder> constructor. Any options given here override the
747defaults that this module uses.
748
749The C<form>, C<write>, and C<write_module> methods will all call
750C<build> with no options for you if you do not do so explicitly.
751This allows you to say things like this:
752
753    my $form = Text::FormBuilder->new->parse('formspec.txt')->form;
754
755However, if you need to specify options to C<build>, you must call it
756explictly after C<parse>.
757
758=head2 form
759
760    my $form = $parser->form;
761
762Returns the L<CGI::FormBuilder> object. Remember that you can modify
763this object directly, in order to (for example) dynamically populate
764dropdown lists or change input types at runtime.
765
766=head2 write
767
768    $parser->write($out_file);
769    # or just print to STDOUT
770    $parser->write;
771
772Calls C<render> on the FormBuilder form, and either writes the resulting
773HTML to a file, or to STDOUT if no filename is given.
774
775=head2 write_module
776
777    $parser->write_module($package, $use_tidy);
778
779Takes a package name, and writes out a new module that can be used by your
780CGI script to render the form. This way, you only need CGI::FormBuilder on
781your server, and you don't have to parse the form spec each time you want
782to display your form. The generated module has one function (not exported)
783called C<get_form>, that takes a CGI object as its only argument, and returns
784a CGI::FormBuilder object.
785
786First, you parse the formspec and write the module, which you can do as a one-liner:
787
788    $ perl -MText::FormBuilder -e"Text::FormBuilder->parse('formspec.txt')->write_module('My::Form')"
789
790And then, in your CGI script, use the new module:
791
792    #!/usr/bin/perl -w
793    use strict;
794   
795    use CGI;
796    use My::Form;
797   
798    my $q = CGI->new;
799    my $form = My::Form::get_form($q);
800   
801    # do the standard CGI::FormBuilder stuff
802    if ($form->submitted && $form->validate) {
803        # process results
804    } else {
805        print $q->header;
806        print $form->render;
807    }
808
809If you pass a true value as the second argument to C<write_module>, the parser
810will run L<Perl::Tidy> on the generated code before writing the module file.
811
812    # write tidier code
813    $parser->write_module('My::Form', 1);
814
815=head2 write_script
816
817    $parser->write_script($filename, $use_tidy);
818
819If you don't need the reuseability of a separate module, you can have
820Text::FormBuilder write the form object to a script for you, along with
821the simplest framework for using it, to which you can add your actual
822form processing code.
823
824The generated script looks like this:
825
826    #!/usr/bin/perl
827    use strict;
828    use warnings;
829   
830    use CGI;
831    use CGI::FormBuilder;
832   
833    my $q = CGI->new;
834   
835    my $form = CGI::FormBuilder->new(
836        params => $q,
837        # ... lots of other stuff to set up the form ...
838    );
839   
840    $form->field( name => 'month' );
841    $form->field( name => 'day' );
842   
843    unless ( $form->submitted && $form->validate ) {
844        print $form->render;
845    } else {
846        # do something with the entered data ...
847        # this is where your form processing code should go
848    }
849
850Like C<write_module>, you can optionally pass a true value as the second
851argument to have Perl::Tidy make the generated code look nicer.
852
853=head2 dump
854
855Uses L<YAML> to print out a human-readable representation of the parsed
856form spec.
857
858=head1 EXPORTS
859
860There is one exported function, C<create_form>, that is intended to ``do the
861right thing'' in simple cases.
862
863=head2 create_form
864
865    # get a CGI::FormBuilder object
866    my $form = create_form($source, $options, $destination);
867   
868    # or just write the form immediately
869    create_form($source, $options, $destination);
870
871C<$source> accepts any of the types of arguments that C<parse> does. C<$options>
872is a hashref of options that should be passed to C<build>. Finally, C<$destination>
873is a simple scalar that determines where and what type of output C<create_form>
874should generate.
875
876    /\.pm$/             ->write_module($destination)
877    /\.(cgi|pl)$/       ->write_script($destination)
878    everything else     ->write($destination)
879
880For anything more than simple, one-off cases, you are usually better off using the
881object-oriented interface, since that gives you more control over things.
882
883=head1 DEFAULTS
884
885These are the default settings that are passed to C<< CGI::FormBuilder->new >>:
886
887    method => 'GET'
888    javascript => 0
889    keepextras => 1
890
891Any of these can be overriden by the C<build> method:
892
893    # use POST instead
894    $parser->build(method => 'POST')->write;
895
896=head1 LANGUAGE
897
898    field_name[size]|descriptive label[hint]:type=default{option1[display string],...}//validate
899   
900    !title ...
901   
902    !author ...
903   
904    !description {
905        ...
906    }
907   
908    !pattern NAME /regular expression/
909   
910    !list NAME {
911        option1[display string],
912        option2[display string],
913        ...
914    }
915   
916    !list NAME &{ CODE }
917   
918    !group NAME {
919        field1
920        field2
921        ...
922    }
923   
924    !section id heading
925   
926    !head ...
927   
928    !note {
929        ...
930    }
931
932=head2 Directives
933
934=over
935
936=item C<!pattern>
937
938Defines a validation pattern.
939
940=item C<!list>
941
942Defines a list for use in a C<radio>, C<checkbox>, or C<select> field.
943
944=item C<!group>
945
946Define a named group of fields that are displayed all on one line. Use with
947the C<!field> directive.
948
949=item C<!field>
950
951Include a named instance of a group defined with C<!group>.
952
953=item C<!title>
954
955Title of the form.
956
957=item C<!author>
958
959Author of the form.
960
961=item C<!description>
962
963A brief description of the form. Suitable for special instructions on how to
964fill out the form.
965
966=item C<!section>
967
968Starts a new section. Each section has its own heading and id, which are
969written by default into spearate tables.
970
971=item C<!head>
972
973Inserts a heading between two fields. There can only be one heading between
974any two fields; the parser will warn you if you try to put two headings right
975next to each other.
976
977=item C<!note>
978
979A text note that can be inserted as a row in the form. This is useful for
980special instructions at specific points in a long form.
981
982=back
983
984=head2 Fields
985
986First, a note about multiword strings in the fields. Anywhere where it says
987that you may use a multiword string, this means that you can do one of two
988things. For strings that consist solely of alphanumeric characters (i.e.
989C<\w+>) and spaces, the string will be recognized as is:
990
991    field_1|A longer label
992
993If you want to include non-alphanumerics (e.g. punctuation), you must
994single-quote the string:
995
996    field_2|'Dept./Org.'
997
998To include a literal single-quote in a single-quoted string, escape it with
999a backslash:
1000
1001    field_3|'\'Official\' title'
1002
1003Now, back to the beginning. Form fields are each described on a single line.
1004The simplest field is just a name (which cannot contain any whitespace):
1005
1006    color
1007
1008This yields a form with one text input field of the default size named `color'.
1009The generated label for this field would be ``Color''. To add a longer or more\
1010descriptive label, use:
1011
1012    color|Favorite color
1013
1014The descriptive label can be a multiword string, as described above. So if you
1015want punctuation in the label, you should single quote it:
1016
1017    color|'Fav. color'
1018
1019To use a different input type:
1020
1021    color|Favorite color:select{red,blue,green}
1022
1023Recognized input types are the same as those used by CGI::FormBuilder:
1024
1025    text        # the default
1026    textarea
1027    password
1028    file
1029    checkbox
1030    radio
1031    select
1032    hidden
1033    static
1034
1035To change the size of the input field, add a bracketed subscript after the
1036field name (but before the descriptive label):
1037
1038    # for a single line field, sets size="40"
1039    title[40]:text
1040   
1041    # for a multiline field, sets rows="4" and cols="30"
1042    description[4,30]:textarea
1043
1044To also set the C<maxlength> attribute for text fields, add a C<!> after
1045the size:
1046
1047    # ensure that all titles entered are 40 characters or less
1048    title[40!]:text
1049
1050This currently only works for single line text fields.
1051   
1052For the input types that can have options (C<select>, C<radio>, and
1053C<checkbox>), here's how you do it:
1054
1055    color|Favorite color:select{red,blue,green}
1056
1057Values are in a comma-separated list of single words or multiword strings
1058inside curly braces. Whitespace between values is irrelevant.
1059
1060To add more descriptive display text to a value in a list, add a square-bracketed
1061``subscript,'' as in:
1062
1063    ...:select{red[Scarlet],blue[Azure],green[Olive Drab]}
1064
1065If you have a list of options that is too long to fit comfortably on one line,
1066you should use the C<!list> directive:
1067
1068    !list MONTHS {
1069        1[January],
1070        2[February],
1071        3[March],
1072        # and so on...
1073    }
1074   
1075    month:select@MONTHS
1076
1077There is another form of the C<!list> directive: the dynamic list:
1078
1079    !list RANDOM &{ map { rand } (0..5) }
1080
1081The code inside the C<&{ ... }> is C<eval>ed by C<build>, and the results
1082are stuffed into the list. The C<eval>ed code can either return a simple
1083list, as the example does, or the fancier C<< ( { value1 => 'Description 1'},
1084{ value2 => 'Description 2}, ... ) >> form.
1085
1086I<B<NOTE:> This feature of the language may go away unless I find a compelling
1087reason for it in the next few versions. What I really wanted was lists that
1088were filled in at run-time (e.g. from a database), and that can be done easily
1089enough with the CGI::FormBuilder object directly.>
1090
1091If you want to have a single checkbox (e.g. for a field that says ``I want to
1092recieve more information''), you can just specify the type as checkbox without
1093supplying any options:
1094
1095    moreinfo|I want to recieve more information:checkbox
1096
1097In this case, the label ``I want to recieve more information'' will be
1098printed to the right of the checkbox.
1099
1100You can also supply a default value to the field. To get a default value of
1101C<green> for the color field:
1102
1103    color|Favorite color:select=green{red,blue,green}
1104
1105Default values can also be either single words or multiword strings.
1106
1107To validate a field, include a validation type at the end of the field line:
1108
1109    email|Email address//EMAIL
1110
1111Valid validation types include any of the builtin defaults from L<CGI::FormBuilder>,
1112or the name of a pattern that you define with the C<!pattern> directive elsewhere
1113in your form spec:
1114
1115    !pattern DAY /^([1-3][0-9])|[1-9]$/
1116   
1117    last_day//DAY
1118
1119If you just want a required value, use the builtin validation type C<VALUE>:
1120
1121    title//VALUE
1122
1123By default, adding a validation type to a field makes that field required. To
1124change this, add a C<?> to the end of the validation type:
1125
1126    contact//EMAIL?
1127
1128In this case, you would get a C<contact> field that was optional, but if it
1129were filled in, would have to validate as an C<EMAIL>.
1130
1131=head2 Field Groups
1132
1133You can define groups of fields using the C<!group> directive:
1134
1135    !group DATE {
1136        month:select@MONTHS//INT
1137        day[2]//INT
1138        year[4]//INT
1139    }
1140
1141You can then include instances of this group using the C<!field> directive:
1142
1143    !field %DATE birthday
1144
1145This will create a line in the form labeled ``Birthday'' which contains
1146a month dropdown, and day and year text entry fields. The actual input field
1147names are formed by concatenating the C<!field> name (e.g. C<birthday>) with
1148the name of the subfield defined in the group (e.g. C<month>, C<day>, C<year>).
1149Thus in this example, you would end up with the form fields C<birthday_month>,
1150C<birthday_day>, and C<birthday_year>.
1151
1152=head2 Comments
1153
1154    # comment ...
1155
1156Any line beginning with a C<#> is considered a comment.
1157
1158=head1 TODO
1159
1160Document the commmand line tool
1161
1162Allow renaming of the submit button; allow renaming and inclusion of a
1163reset button
1164
1165Allow groups to be used in normal field lines something like this:
1166
1167    !group DATE {
1168        month
1169        day
1170        year
1171    }
1172   
1173    dob|Your birthday:DATE
1174
1175Pieces that wouldn't make sense in a group field: size, row/col, options,
1176validate. These should cause C<build> to emit a warning before ignoring them.
1177
1178Make the generated modules into subclasses of CGI::FormBuilder
1179
1180Allow for custom wrappers around the C<form_template>
1181
1182Maybe use HTML::Template instead of Text::Template for the built in template
1183(since CGI::FormBuilder users may be more likely to already have HTML::Template)
1184
1185C<!include> directive to include external formspec files
1186
1187Better tests!
1188
1189=head1 BUGS
1190
1191Creating two $parsers in the same script causes the second one to get the data
1192from the first one.
1193
1194I'm sure there are more in there, I just haven't tripped over any new ones lately. :-)
1195
1196Suggestions on how to improve the (currently tiny) test suite would be appreciated.
1197
1198=head1 SEE ALSO
1199
1200L<http://textformbuilder.berlios.de>
1201
1202L<CGI::FormBuilder>, L<http://formbuilder.org>
1203
1204=head1 THANKS
1205
1206Thanks to eszpee for pointing out some bugs in the default value parsing,
1207as well as some suggestions for i18n/l10n and splitting up long forms into
1208sections.
1209
1210=head1 AUTHOR
1211
1212Peter Eichman C<< <peichman@cpan.org> >>
1213
1214=head1 COPYRIGHT AND LICENSE
1215
1216Copyright E<copy>2004-2005 by Peter Eichman.
1217
1218This program is free software; you can redistribute it and/or
1219modify it under the same terms as Perl itself.
1220
1221=cut
Note: See TracBrowser for help on using the repository browser.