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

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

fallthrough to CGI::FormBuilder builtin lists working (again); added a !note directive; discovered bug in parsing of !directive and !note

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