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

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

added examples documentation; documented the create_form function; updated README

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