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

Last change on this file since 42 was 42, checked in by peter, 19 years ago

added a create_form exported method to "do the right thing" in simple cases
added parse_array method to parse an array of lines making up a formspec
some internal cleanup of the lines structure

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