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

Last change on this file since 60 was 60, checked in by peichman, 19 years ago

using the 'columns' argument to get columns of checkboxes (instead of 'ulist')
updated version number

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