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

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

added examples documentation; documented the create_form function; updated README

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