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

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

added growable field support (release pending release of FB 3.002)
upped FB required version to 3.001
added a belated thank you to Nate

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