File Coverage

blib/lib/Text/FormBuilder.pm
Criterion Covered Total %
statement 113 250 45.2
branch 22 110 20.0
condition 6 42 14.2
subroutine 15 26 57.6
pod 10 10 100.0
total 166 438 37.9


line stmt bran cond sub pod time code
1             package Text::FormBuilder;
2              
3 1     1   24492 use strict;
  1         2  
  1         31  
4 1     1   5 use warnings;
  1         3  
  1         25  
5              
6 1     1   3 use base qw(Exporter Class::ParseText::Base);
  1         2  
  1         657  
7 1     1   5 use vars qw($VERSION @EXPORT);
  1         8  
  1         120  
8              
9             $VERSION = '0.14';
10             @EXPORT = qw(create_form);
11              
12 1     1   5 use Carp;
  1         1  
  1         57  
13 1     1   4906 use Text::FormBuilder::Parser;
  1         21  
  1         137  
14 1     1   1269 use CGI::FormBuilder;
  1         23296  
  1         42  
15              
16 1     1   1158 use Data::Dumper;
  1         7616  
  1         3691  
17             $Data::Dumper::Terse = 1; # don't dump $VARn names
18             $Data::Dumper::Quotekeys = 0; # don't quote simple string keys
19              
20             # the static default options passed to CGI::FormBuilder->new
21             my %DEFAULT_OPTIONS = (
22             method => 'GET',
23             keepextras => 1,
24             );
25              
26             # the built in CSS for the template
27             my $DEFAULT_CSS = <
28             table { padding: 1em; }
29             td table { padding: 0; } /* exclude the inner checkbox tables */
30             #author, #footer { font-style: italic; }
31             caption h2 { padding: .125em .5em; background: #ccc; text-align: left; }
32             fieldset { margin: 1em 0; border: none; border-top: 2px solid #999; }
33             legend { font-size: 1.25em; font-weight: bold; background: #ccc; padding: .125em .25em; border: 1px solid #666; }
34             th { text-align: left; }
35             th h2 { padding: .125em .5em; background: #eee; font-size: 1.25em; }
36             .label { font-weight: normal; text-align: right; vertical-align: top; }
37             td ul { list-style: none; padding-left: 0; margin-left: 0; }
38             .note { background: #eee; padding: .5em 1em; }
39             .sublabel { color: #999; }
40             .invalid { background: red; }
41             END
42              
43             # default messages that can be localized
44             my %DEFAULT_MESSAGES = (
45             text_author => 'Created by %s',
46             text_madewith => 'Made with %s version %s',
47             text_required => 'Fields that are highlighted are required.',
48             text_invalid => 'Missing or invalid value.',
49             );
50              
51             my $DEFAULT_CHARSET = 'iso-8859-1';
52              
53             # options to clean up the code with Perl::Tidy
54             my $TIDY_OPTIONS = '-nolq -ci=4 -ce';
55              
56             my $HTML_EXTS = qr/\.html?$/;
57             my $MODULE_EXTS = qr/\.pm$/;
58             my $SCRIPT_EXTS = qr/\.(pl|cgi)$/;
59              
60             # superautomagical exported function
61             sub create_form {
62 0     0 1 0 my ($source, $options, $destination) = @_;
63 0         0 my $parser = __PACKAGE__->parse($source);
64 0 0       0 $parser->build(%{ $options || {} });
  0         0  
65 0 0       0 if ($destination) {
66 0 0       0 if (ref $destination) {
67 0         0 croak '[' . (caller(0))[3] . "] Don't know what to do with a ref for $destination";
68             #TODO: what DO ref dests mean?
69             } else {
70             # write webpage, script, or module
71 0 0       0 if ($destination =~ $MODULE_EXTS) {
    0          
72 0         0 $parser->write_module($destination, 1);
73             } elsif ($destination =~ $SCRIPT_EXTS) {
74 0         0 $parser->write_script($destination, 1);
75             } else {
76 0         0 $parser->write($destination);
77             }
78             }
79             } else {
80 0 0       0 defined wantarray ? return $parser->form : $parser->write;
81             }
82             }
83              
84             # subclass of Class::ParseText::Base
85             sub init {
86 5     5 1 173 my $self = shift;
87 5         42 $self->{parser} = Text::FormBuilder::Parser->new;
88 5         140 $self->{start_rule} = 'form_spec';
89 5         14 $self->{ensure_newline} = 1;
90 5         21 return $self;
91             }
92              
93             # this is where a lot of the magic happens
94             sub build {
95 5     5 1 16 my ($self, %options) = @_;
96            
97             # our custom %options:
98             # form_only: use only the form part of the template
99 5         11 my $form_only = $options{form_only};
100            
101             # css, extra_css: allow for custom inline stylesheets
102             # neat trick: css => '@import(my_external_stylesheet.css);'
103             # will let you use an external stylesheet
104             # CSS Hint: to get multiple sections to all line up their fields,
105             # set a standard width for th.label
106             # external_css: scalar for a single external stylesheet; array for
107             # multiple sheets; prepended to the beginning of the CSS as @import
108             # statetments
109 5         9 my $css;
110 5   33     33 $css = $options{css} || $DEFAULT_CSS;
111 5 50       18 if ($options{external_css}) {
112 0         0 my $ref = ref $options{external_css};
113 0 0       0 if ($ref eq 'ARRAY') {
    0          
114             # loop over the list of external sheets
115 0         0 my $external_sheets = join("\n", map { "\@import url($_);" } @{ $options{external_css} });
  0         0  
  0         0  
116 0         0 $css = "$external_sheets\n$css";
117             } elsif ($ref) {
118 0         0 croak '[' . (caller(0))[3] . "] Don't know how to handle $ref reference as an argument to external_css";
119             } else {
120 0         0 $css = "\@import url($options{external_css});\n$css";
121             }
122             }
123 5 50       13 $css .= $options{extra_css} if $options{extra_css};
124            
125             # messages
126             # code pulled (with modifications) from CGI::FormBuilder
127 5 50       16 if ($options{messages}) {
128             # if its a hashref, we'll just pass it on to CGI::FormBuilder
129            
130 0 0       0 if (my $ref = ref $options{messages}) {
131             # hashref pass on to CGI::FormBuilder
132 0 0       0 croak "[Text::FormBuilder] Argument to 'messages' option must be a filename or hashref" unless $ref eq 'HASH';
133 0         0 while (my ($key,$value) = each %DEFAULT_MESSAGES) {
134 0   0     0 $options{messages}{$key} ||= $DEFAULT_MESSAGES{$key};
135             }
136             } else {
137             # filename, just *warn* on missing, and use defaults
138 0 0 0     0 if (-f $options{messages} && -r _ && open(MESSAGES, "< $options{messages}")) {
      0        
139 0         0 $options{messages} = { %DEFAULT_MESSAGES };
140 0         0 while() {
141 0 0 0     0 next if /^\s*#/ || /^\s*$/;
142 0         0 chomp;
143 0         0 my($key,$value) = split ' ', $_, 2;
144 0         0 ($options{messages}{$key} = $value) =~ s/\s+$//;
145             }
146 0         0 close MESSAGES;
147             } else {
148 0         0 carp '[' . (caller(0))[3] . "] Could not read messages file $options{messages}: $!";
149             }
150             }
151             } else {
152 5         77 $options{messages} = { %DEFAULT_MESSAGES };
153             }
154            
155             # character set
156 5         16 my $charset = $options{charset};
157            
158             # save the build options so they can be used from write_module
159 5         16 $self->{build_options} = { %options };
160            
161             # remove our custom options before we hand off to CGI::FormBuilder
162 5         38 delete $options{$_} foreach qw(form_only css extra_css charset);
163            
164             # expand groups
165 5 50       12 if (my %groups = %{ $self->{form_spec}{groups} || {} }) {
  5 50       42  
166 0 0       0 for my $section (@{ $self->{form_spec}{sections} || [] }) {
  0         0  
167 0         0 foreach (grep { $$_[0] eq 'group' } @{ $$section{lines} }) {
  0         0  
  0         0  
168 0         0 $$_[1]{group} =~ s/^\%//; # strip leading % from group var name
169            
170 0 0       0 if (exists $groups{$$_[1]{group}}) {
171 0         0 my @fields; # fields in the group
172 0         0 push @fields, { %$_ } foreach @{ $groups{$$_[1]{group}} };
  0         0  
173 0         0 for my $field (@fields) {
174 0   0     0 $$field{label} ||= ucfirst $$field{name};
175 0         0 $$field{name} = "$$_[1]{name}_$$field{name}";
176             }
177             $_ = [
178 0   0     0 'group',
179             {
180             label => $$_[1]{label} || ucfirst(join(' ',split('_',$$_[1]{name}))),
181             comment => $$_[1]{comment},
182             group => \@fields,
183             },
184             ];
185             }
186             }
187             }
188             }
189            
190             # the actual fields that are given to CGI::FormBuilder
191             # make copies so that when we trim down the sections
192             # we don't lose the form field information
193 5         20 $self->{form_spec}{fields} = [];
194            
195 5 50       10 for my $section (@{ $self->{form_spec}{sections} || [] }) {
  5         27  
196 3         7 for my $line (@{ $$section{lines} }) {
  3         11  
197 10 50       56 if ($$line[0] eq 'group') {
    50          
198 0         0 push @{ $self->{form_spec}{fields} }, { %{$_} } foreach @{ $$line[1]{group} };
  0         0  
  0         0  
  0         0  
199             } elsif ($$line[0] eq 'field') {
200             #die $$line[1] unless ref $$line[1];
201 10         16 push @{ $self->{form_spec}{fields} }, { %{$$line[1]} };
  10         24  
  10         122  
202             }
203             }
204             }
205            
206             # substitute in custom validation subs and pattern definitions for field validation
207 5 50       9 my %patterns = %{ $self->{form_spec}{patterns} || {} };
  5         29  
208 5 50       10 my %subs = %{ $self->{form_spec}{subs} || {} };
  5         20  
209            
210 5         10 foreach (@{ $self->{form_spec}{fields} }) {
  5         12  
211 10 50       36 if ($$_{validate}) {
212 0 0       0 if (exists $patterns{$$_{validate}}) {
    0          
213 0         0 $$_{validate} = $patterns{$$_{validate}};
214             # TODO: need the Data::Dumper code to work for this
215             # for now, we just warn that it doesn't work
216             } elsif (exists $subs{$$_{validate}}) {
217 0         0 warn '[' . (caller(0))[3] . "] validate coderefs don't work yet";
218 0         0 delete $$_{validate};
219             ## $$_{validate} = $subs{$$_{validate}};
220             }
221             }
222             }
223            
224             # get user-defined lists; can't make this conditional because
225             # we need to be able to fall back to CGI::FormBuilder's lists
226             # even if the user didn't define any
227 5 50       11 my %lists = %{ $self->{form_spec}{lists} || {} };
  5         25  
228            
229             # substitute in list names
230 5         11 foreach (@{ $self->{form_spec}{fields} }) {
  5         16  
231 10 50       34 next unless $$_{list};
232            
233 0         0 $$_{list} =~ s/^\@//; # strip leading @ from list var name
234            
235             # a hack so we don't get screwy reference errors
236 0 0       0 if (exists $lists{$$_{list}}) {
237 0         0 my @list;
238 0         0 push @list, { %$_ } foreach @{ $lists{$$_{list}} };
  0         0  
239 0         0 $$_{options} = \@list;
240             } else {
241             # assume that the list name is a builtin
242             # and let it fall through to CGI::FormBuilder
243 0         0 $$_{options} = $$_{list};
244             }
245             } continue {
246 10         24 delete $$_{list};
247             }
248            
249             # special case single-value checkboxes
250 5 50       10 foreach (grep { $$_{type} && $$_{type} eq 'checkbox' } @{ $self->{form_spec}{fields} }) {
  10         61  
  5         20  
251 0 0       0 unless ($$_{options}) {
252 0   0     0 $$_{options} = [ { $$_{name} => $$_{label} || ucfirst join(' ',split(/_/,$$_{name})) } ];
253             }
254             }
255            
256             # use columns for displaying checkbox fields larger than 2 items
257 5         12 foreach (@{ $self->{form_spec}{fields} }) {
  5         16  
258 10 50 33     37 if (ref $$_{options} and @{ $$_{options} } >= 3) {
  0         0  
259 0         0 $$_{columns} = int(@{ $$_{options} } / 8) + 1;
  0         0  
260             }
261             }
262            
263             # remove extraneous undefined values
264             # also check for approriate version of CGI::FormBuilder
265             # for some advanced options
266 5         120 my $FB_version = CGI::FormBuilder->VERSION;
267 5         16 for my $field (@{ $self->{form_spec}{fields} }) {
  5         20  
268 10   100     18 defined $$field{$_} or delete $$field{$_} foreach keys %{ $field };
  10         271  
269            
270 10 50       57 unless ($FB_version >= '3.02') {
271 0         0 for (qw(growable other)) {
272 0 0       0 if ($$field{$_}) {
273 0         0 warn '[' . (caller(0))[3] . "] '$_' fields not supported by FB $FB_version (requires 3.02)";
274 0         0 delete $$field{$_};
275             }
276             }
277             }
278             }
279            
280             # assign the field names to the sections
281 5         10 foreach (@{ $self->{form_spec}{sections} }) {
  5         15  
282 3         9 for my $line (@{ $$_{lines} }) {
  3         11  
283 10 50       35 if ($$line[0] eq 'field') {
284 10         78 $$line[1] = $$line[1]{name};
285             }
286             }
287             }
288            
289 5         10 my %fb_params;
290 5 50       17 if ($self->{form_spec}->{fb_params}) {
291 0         0 require YAML;
292 0         0 eval { %fb_params = %{ YAML::Load($self->{form_spec}->{fb_params}) } };
  0         0  
  0         0  
293 0 0       0 if ($@) {
294 0         0 warn '[' . (caller(0))[3] . "] Bad !fb parameter block:\n$@";
295             }
296             }
297            
298             # gather together all of the form options
299 10         34 $self->{form_options} = {
300             %DEFAULT_OPTIONS,
301             # need to explicity set the fields so that simple text fields get picked up
302 5         19 fields => [ map { $$_{name} } @{ $self->{form_spec}{fields} } ],
  0         0  
303 5 50       22 required => [ map { $$_{name} } grep { $$_{required} } @{ $self->{form_spec}{fields} } ],
  10 50       51  
  5         35  
304             title => $self->{form_spec}{title},
305             text => $self->{form_spec}{description},
306             # use 'defined' so we are able to differentiate between 'submit = 0' (no submit button)
307             # and 'submit = undef' (use default submit button)
308             ( defined $self->{form_spec}{submit} ? (submit => $self->{form_spec}{submit}) : () ),
309             reset => $self->{form_spec}{reset},
310             template => {
311             type => 'Text',
312             engine => {
313             TYPE => 'STRING',
314             SOURCE => $form_only ? $self->_form_template : $self->_template($css, $charset),
315             DELIMITERS => [ qw(<% %>) ],
316             },
317             data => {
318             #TODO: make FB aware of sections
319             sections => $self->{form_spec}{sections},
320             author => $self->{form_spec}{author},
321             description => $self->{form_spec}{description},
322             },
323             },
324             #TODO: fields in fb_params are not getting recognized
325             %fb_params, # params from the formspec file
326             %options, # params from this method invocation
327             };
328            
329             # create the form object
330 5         23 $self->{form} = CGI::FormBuilder->new(%{ $self->{form_options} });
  5         55  
331            
332             # ...and set up its fields
333 5         37064 $self->{form}->field(%{ $_ }) foreach @{ $self->{form_spec}{fields} };
  5         58  
  10         1128  
334            
335             # mark structures as built
336 5         337 $self->{built} = 1;
337            
338 5         29 return $self;
339             }
340              
341             sub write {
342 0     0 1 0 my ($self, $outfile) = @_;
343            
344             # automatically call build if needed to
345             # allow the new->parse->write shortcut
346 0 0       0 $self->build unless $self->{built};
347            
348 0 0       0 if ($outfile) {
349 0         0 open FORM, "> $outfile";
350 0         0 print FORM $self->form->render;
351 0         0 close FORM;
352             } else {
353 0         0 print $self->form->render;
354             }
355             }
356              
357             # dump the form options as eval-able code
358             sub _form_options_code {
359 0     0   0 my $self = shift;
360 0         0 my $d = Data::Dumper->new([ $self->{form_options} ], [ '*options' ]);
361 0 0       0 return keys %{ $self->{form_options} } > 0 ? $d->Dump : '';
  0         0  
362             }
363             # dump the field setup subs as eval-able code
364             # pass in the variable name of the form object
365             # (defaults to '$form')
366             # TODO: revise this code to use the new 'fieldopts'
367             # option to the FB constructor (requires FB 3.02)
368             sub _field_setup_code {
369 0     0   0 my $self = shift;
370 0   0     0 my $object_name = shift || '$form';
371 0         0 return join(
372             "\n",
373 0         0 map { $object_name . '->field' . Data::Dumper->Dump([$_],['*field']) . ';' } @{ $self->{form_spec}{fields} }
  0         0  
374             );
375             }
376              
377             sub as_module {
378 0     0 1 0 my ($self, $package, $use_tidy) = @_;
379              
380 0 0       0 croak '[' . (caller(0))[3] . '] Expecting a package name' unless $package;
381            
382             # remove a trailing .pm
383 0         0 $package =~ s/\.pm$//;
384              
385             # auto-build
386 0 0       0 $self->build unless $self->{built};
387              
388 0         0 my $form_options = $self->_form_options_code;
389 0         0 my $field_setup = $self->_field_setup_code('$self');
390            
391             # old style of module
392             # TODO: how to keep this (as deprecated method)
393 0         0 my $old_module = <
394             package $package;
395             use strict;
396             use warnings;
397              
398             use CGI::FormBuilder;
399              
400             sub get_form {
401             my \$q = shift;
402              
403             my \$self = CGI::FormBuilder->new(
404             $form_options,
405             \@_,
406             );
407            
408             $field_setup
409            
410             return \$self;
411             }
412              
413             # module return
414             1;
415             END
416              
417             # new style of module
418 0         0 my $module = <
419             package $package;
420             use strict;
421             use warnings;
422              
423             use base qw(CGI::FormBuilder);
424              
425             sub new {
426             my \$invocant = shift;
427             my \$class = ref \$invocant || \$invocant;
428            
429             my \$self = CGI::FormBuilder->new(
430             $form_options,
431             \@_,
432             );
433            
434             $field_setup
435            
436             # re-bless into this class
437             bless \$self, \$class;
438             }
439              
440             # module return
441             1;
442             END
443              
444 0 0       0 $module = _tidy_code($module, $use_tidy) if $use_tidy;
445            
446 0         0 return $module;
447             }
448              
449             sub write_module {
450 0     0 1 0 my ($self, $package, $use_tidy) = @_;
451            
452 0         0 my $module = $self->as_module($package, $use_tidy);
453            
454 0         0 my $outfile = (split(/::/, $package))[-1];
455 0 0       0 $outfile .= '.pm' unless $outfile =~ /\.pm$/;
456 0         0 _write_output_file($module, $outfile);
457 0         0 return $self;
458             }
459              
460             sub as_script {
461 0     0 1 0 my ($self, $use_tidy) = @_;
462            
463             # auto-build
464 0 0       0 $self->build unless $self->{built};
465            
466 0         0 my $form_options = $self->_form_options_code;
467 0         0 my $field_setup = $self->_field_setup_code('$form');
468              
469 0         0 my $script = <
470             #!/usr/bin/perl
471             use strict;
472             use warnings;
473              
474             use CGI::FormBuilder;
475              
476             my \$form = CGI::FormBuilder->new(
477             $form_options
478             );
479              
480             $field_setup
481            
482             unless (\$form->submitted && \$form->validate) {
483             print \$form->render;
484             } else {
485             # do something with the entered data
486             }
487             END
488 0 0       0 $script = _tidy_code($script, $use_tidy) if $use_tidy;
489            
490 0         0 return $script;
491             }
492            
493             sub write_script {
494 0     0 1 0 my ($self, $script_name, $use_tidy) = @_;
495              
496 0 0       0 croak '[' . (caller(0))[3] . '] Expecting a script name' unless $script_name;
497              
498 0         0 my $script = $self->as_script($use_tidy);
499            
500 0         0 _write_output_file($script, $script_name);
501 0         0 return $self;
502             }
503              
504             sub _tidy_code {
505 0     0   0 my ($source_code, $use_tidy) = @_;
506 0         0 eval 'use Perl::Tidy';
507 0 0 0     0 carp '[' . (caller(0))[3] . "] Can't tidy the code: $@" and return $source_code if $@;
508            
509             # use the options string only if it begins with '_'
510 0 0       0 my $options = ($use_tidy =~ /^-/) ? $use_tidy : undef;
511            
512 0         0 my $tidy_code;
513 0   0     0 Perl::Tidy::perltidy(source => \$source_code, destination => \$tidy_code, argv => $options || $TIDY_OPTIONS);
514            
515 0         0 return $tidy_code;
516             }
517              
518              
519             sub _write_output_file {
520 0     0   0 my ($source_code, $outfile) = @_;
521 0 0       0 open OUT, "> $outfile" or croak '[' . (caller(1))[3] . "] Can't open $outfile for writing: $!";
522 0         0 print OUT $source_code;
523 0         0 close OUT;
524             }
525              
526              
527             sub form {
528 5     5 1 30 my $self = shift;
529            
530             # automatically call build if needed to
531             # allow the new->parse->write shortcut
532 5 100       40 $self->build unless $self->{built};
533              
534 5         31 return $self->{form};
535             }
536              
537             sub _form_template {
538 5     5   12 my $self = shift;
539 5         16 my $msg_required = $self->{build_options}{messages}{text_required};
540 5         10 my $msg_invalid = $self->{build_options}{messages}{text_invalid};
541 5         95 return q{<% $description ? qq[

$description

] : '' %>
542             <% (grep { $_->{required} } @fields) ? qq[

} . $msg_required . q{

] : '' %>
543             <% $start %>
544             <%
545             # drop in the hidden fields here
546             $OUT = join("\n", map { $$_{field} } grep { $$_{type} eq 'hidden' } @fields);
547             %>} .
548             q[
549             <%
550             SECTION: while (my $section = shift @sections) {
551             $OUT .= qq[
\n];
552             $OUT .= qq[ $$section{head}] if $$section{head};
553             $OUT .= qq[\n]; ] if $$section{head}; \n] \n] ] : qq[ ]; ]; '; ]; ]; \n]; \n] : qq[ \n]; \n]; \n]; \n];
554             #$OUT .= qq[

$$section{head}

555             TABLE_LINE: for my $line (@{ $$section{lines} }) {
556             if ($$line[0] eq 'head') {
557             $OUT .= qq[

$$line[1]

558             } elsif ($$line[0] eq 'note') {
559             $OUT .= qq[
$$line[1]
560             } elsif ($$line[0] eq 'field') {
561             local $_ = $field{$$line[1]};
562            
563             # skip hidden fields in the table
564             next TABLE_LINE if $$_{type} eq 'hidden';
565            
566             $OUT .= $$_{invalid} ? qq[
567            
568             # special case single value checkboxes
569             if ($$_{type} eq 'checkbox' && @{ $$_{options} } == 1) {
570             $OUT .= qq[
571             } else {
572             $OUT .= '' . ($$_{required} ? qq[$$_{label}] : "$$_{label}") . '
573             }
574            
575             # mark invalid fields
576             if ($$_{invalid}) {
577             $OUT .= qq[$$_{field} $$_{comment} $$_{error}
578             } else {
579             $OUT .= qq[$$_{field} $$_{comment}
580             }
581            
582             $OUT .= qq[
583            
584             } elsif ($$line[0] eq 'group') {
585             my @group_fields = map { $field{$_} } map { $$_{name} } @{ $$line[1]{group} };
586             $OUT .= (grep { $$_{invalid} } @group_fields) ? qq[
587            
588             $OUT .= ' ';
589             $OUT .= (grep { $$_{required} } @group_fields) ? qq[$$line[1]{label}] : "$$line[1]{label}";
590             $OUT .= qq[
591            
592             $OUT .= qq[ ];
593             $OUT .= join(' ', map { qq[$$_{label} $$_{field} $$_{comment}] } @group_fields);
594             if (my @invalid = grep { $$_{invalid} } @group_fields) {
595             $OUT .= ' ' . join('; ', map { $$_{error} } @invalid);
596             }
597             $OUT .= qq[ $$line[1]{comment}
598             $OUT .= qq[
599             }
600             }
601             # close the table if there are sections remaining
602             # but leave the last one open for the submit button
603             if (@sections) {
604             $OUT .= qq[
\n];
605             $OUT .= qq[\n];
606             }
607             }
608             %>
609            
<% $submit %> <% $reset %>
610            
611             612             <% $end %> 613             ]; 614             } 615               616             # usage: $self->_pre_template($css, $charset) 617             sub _pre_template { 618 5     5   9 my $self = shift; 619 5   33     17 my $css = shift || $DEFAULT_CSS; 620 5   33     85 my $charset = shift || $DEFAULT_CHARSET; 621 5         32 my $msg_author = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_author}) . '", $author)'; 622             return 623 5         321 q[ 624             625             626             <% $title %><% $author ? ' - ' . ucfirst $author : '' %> 627             629             <% $jshead %> 630             631             632               633            

<% $title %>

634             <% $author ? qq[

] . ] . $msg_author . q{ . q[

] : '' %> 635             }; 636             } 637               638             sub _post_template { 639 5     5   6 my $self = shift; 640 5         27 my $msg_madewith = 'sprintf("' . quotemeta($self->{build_options}{messages}{text_madewith}) . 641             '", q[CGI::FormBuilder], CGI::FormBuilder->VERSION)'; 642             643 5         138 return qq[
644             647             648             649             ]; 650             } 651               652             # usage: $self->_template($css, $charset) 653             sub _template { 654 5     5   11 my $self = shift; 655 5         26 return $self->_pre_template(@_) . $self->_form_template . $self->_post_template; 656             } 657               658             sub dump { 659 0     0 1   eval "use YAML;"; 660 0 0         unless ($@) { 661 0           print YAML::Dump(shift->{form_spec}); 662             } else { 663 0           warn '[' . (caller(0))[3] . "] Can't dump form spec structure using YAML: $@"; 664             } 665             } 666               667               668             # module return 669             1; 670               671             =head1 NAME 672               673             Text::FormBuilder - Create CGI::FormBuilder objects from simple text descriptions 674               675             =head1 SYNOPSIS 676               677             use Text::FormBuilder; 678             679             my $parser = Text::FormBuilder->new; 680             $parser->parse($src_file); 681             682             # returns a new CGI::FormBuilder object with 683             # the fields from the input form spec 684             my $form = $parser->form; 685             686             # write a My::Form module to Form.pm 687             $parser->write_module('My::Form'); 688               689             =head1 REQUIRES 690               691             L, 692             L, 693             L, 694             L 695               696             You will also need L, if you want to use the L|/dump> 697             method, or the L|/!fb> directive in your formspec files. 698               699             =head1 DESCRIPTION 700               701             This module is intended to extend the idea of making it easy to create 702             web forms by allowing you to describe them with a simple langauge. These 703             I are then passed through this module's parser and converted 704             into L objects that you can easily use in your CGI 705             scripts. In addition, this module can generate code for standalone modules 706             which allow you to separate your form design from your script code. 707               708             A simple formspec looks like this: 709               710             name//VALUE 711             email//EMAIL 712             language:select{English,Spanish,French,German} 713             moreinfo|Send me more information:checkbox 714             interests:checkbox{Perl,karate,bass guitar} 715               716             This will produce a required C text field, a required C text 717             field that must look like an email address, an optional select dropdown 718             field C with the choices English, Spanish, French, and German, 719             an optional C checkbox labeled ``Send me more information'', and 720             finally a set of checkboxes named C with the choices Perl, 721             karate, and bass guitar. 722               723             =head1 METHODS 724               725             =head2 new 726               727             my $parser = Text::FormBuilder->new; 728               729             =head2 parse 730               731             # parse a file (regular scalar) 732             $parser->parse($filename); 733             734             # or pass a scalar ref to parse a literal string 735             $parser->parse(\$string); 736             737             # or an array ref to parse lines 738             $parser->parse(\@lines); 739               740             Parse the file or string. Returns the parser object. This method, 741             along with all of its C siblings, may be called as a class 742             method to construct a new object. 743               744             =head2 parse_file 745               746             $parser->parse_file($src_file); 747             748             # or as a class method 749             my $parser = Text::FormBuilder->parse($src_file); 750               751             =head2 parse_text 752               753             $parser->parse_text($src); 754               755             Parse the given C<$src> text. Returns the parser object. 756               757             =head2 parse_array 758               759             $parser->parse_array(@lines); 760               761             Concatenates and parses C<@lines>. Returns the parser object. 762               763             =head2 build 764               765             $parser->build(%options); 766               767             Builds the CGI::FormBuilder object. Options directly used by C are: 768               769             =over 770               771             =item C 772               773             Only uses the form portion of the template, and omits the surrounding html, 774             title, author, and the standard footer. This does, however, include the 775             description as specified with the C directive. 776               777             =item C, C 778               779             These options allow you to tell Text::FormBuilder to use different 780             CSS styles for the built in template. A value given a C will 781             replace the existing CSS, and a value given as C will be 782             appended to the CSS. If both options are given, then the CSS that is 783             used will be C concatenated with C. 784               785             If you want to use an external stylesheet, a quick way to get this is 786             to set the C parameter to import your file: 787               788             css => '@import(my_external_stylesheet.css);' 789               790             =item C 791               792             If you want to use multiple external stylesheets, or an external stylesheet 793             in conjunction with the default styles, use the C option: 794               795             # single external sheet 796             external_css => 'my_styles.css' 797             798             # mutliple sheets 799             external_css => [ 800             'my_style_A.css', 801             'my_style_B.css', 802             ] 803               804             =item C 805               806             This works the same way as the C parameter to 807             C<< CGI::FormBuilder->new >>; you can provide either a hashref of messages 808             or a filename. 809               810             The default messages used by Text::FormBuilder are: 811               812             text_author Created by %s 813             text_madewith Made with %s version %s 814             text_required (Required fields are marked in bold.) 815             text_invalid Missing or invalid value. 816               817             Any messages you set here get passed on to CGI::FormBuilder, which means 818             that you should be able to put all of your customization messages in one 819             big file. 820               821             =item C 822               823             Sets the character encoding for the generated page. The default is ISO-8859-1. 824               825             =back 826               827             All other options given to C are passed on verbatim to the 828             L constructor. Any options given here override the 829             defaults that this module uses. 830               831             The C
, C, and C methods will all call 832             C with no options for you if you do not do so explicitly. 833             This allows you to say things like this: 834               835             my $form = Text::FormBuilder->new->parse('formspec.txt')->form; 836               837             However, if you need to specify options to C, you must call it 838             explictly after C. 839               840             =head2 form 841               842             my $form = $parser->form; 843               844             Returns the L object. Remember that you can modify 845             this object directly, in order to (for example) dynamically populate 846             dropdown lists or change input types at runtime. 847               848             =head2 write 849               850             $parser->write($out_file); 851             # or just print to STDOUT 852             $parser->write; 853               854             Calls C on the FormBuilder form, and either writes the resulting 855             HTML to a file, or to STDOUT if no filename is given. 856               857             =head2 as_module 858               859             my $module_code = $parser->as_module($package, $use_tidy); 860               861             =head2 write_module 862               863             I The code output from the C methods may be in flux for 864             the next few versions, as I coordinate with the B project.> 865               866             $parser->write_module($package, $use_tidy); 867               868             Takes a package name, and writes out a new module that can be used by your 869             CGI script to render the form. This way, you only need CGI::FormBuilder on 870             your server, and you don't have to parse the form spec each time you want 871             to display your form. The generated module is a subclass of L, 872             that will pass along any constructor arguments to FormBuilder, and set up 873             the fields for you. 874               875             First, you parse the formspec and write the module, which you can do as a one-liner: 876               877             $ perl -MText::FormBuilder -e"Text::FormBuilder->parse('formspec.txt')->write_module('My::Form')" 878               879             And then, in your CGI script, use the new module: 880               881             #!/usr/bin/perl -w 882             use strict; 883             884             use CGI; 885             use My::Form; 886             887             my $q = CGI->new; 888             my $form = My::Form->new; 889             890             # do the standard CGI::FormBuilder stuff 891             if ($form->submitted && $form->validate) { 892             # process results 893             } else { 894             print $q->header; 895             print $form->render; 896             } 897               898             If you pass a true value as the second argument to C, the parser 899             will run L on the generated code before writing the module file. 900               901             # write tidier code 902             $parser->write_module('My::Form', 1); 903               904             If you set C<$use_tidy> to a string beginning with `-' C will 905             interpret C<$use_tidy> as the formatting option switches to pass to Perl::Tidy. 906               907             =head2 as_script 908               909             my $script_code = $parser->as_script($use_tidy); 910               911             =head2 write_script 912               913             $parser->write_script($filename, $use_tidy); 914               915             If you don't need the reuseability of a separate module, you can have 916             Text::FormBuilder write the form object to a script for you, along with 917             the simplest framework for using it, to which you can add your actual 918             form processing code. 919               920             The generated script looks like this: 921               922             #!/usr/bin/perl 923             use strict; 924             use warnings; 925             926             use CGI::FormBuilder; 927             928             my $form = CGI::FormBuilder->new( 929             # lots of stuff here... 930             ); 931             932             # ...and your field setup subs are here 933             $form->field(name => '...'); 934             935             unless ($form->submitted && $form->validate) { 936             print $form->render; 937             } else { 938             # do something with the entered data 939             } 940               941             Like C, you can optionally pass a true value as the second 942             argument to have Perl::Tidy make the generated code look nicer. 943               944             =head2 dump 945               946             Uses L to print out a human-readable representation of the parsed 947             form spec. 948               949             =head1 EXPORTS 950               951             There is one exported function, C, that is intended to ``do the 952             right thing'' in simple cases. 953               954             =head2 create_form 955               956             # get a CGI::FormBuilder object 957             my $form = create_form($source, $options, $destination); 958             959             # or just write the form immediately 960             create_form($source, $options, $destination); 961               962             C<$source> accepts any of the types of arguments that C does. C<$options> 963             is a hashref of options that should be passed to C. Finally, C<$destination> 964             is a simple scalar that determines where and what type of output C 965             should generate. 966               967             /\.pm$/ ->write_module($destination) 968             /\.(cgi|pl)$/ ->write_script($destination) 969             everything else ->write($destination) 970               971             For anything more than simple, one-off cases, you are usually better off using the 972             object-oriented interface, since that gives you more control over things. 973               974             =head1 DEFAULTS 975               976             These are the default settings that are passed to C<< CGI::FormBuilder->new >>: 977               978             method => 'GET' 979             keepextras => 1 980               981             Any of these can be overriden by the C method: 982               983             # use POST instead 984             $parser->build(method => 'POST')->write; 985               986             =head1 LANGUAGE 987               988             # name field_size growable label hint type other default option_list validate 989             990             field_name[size]|descriptive label[hint]:type=default{option1[display string],...}//validate 991             992             !title ... 993             994             !author ... 995             996             !description { 997             ... 998             } 999             1000             !pattern NAME /regular expression/ 1001             1002             !list NAME { 1003             option1[display string], 1004             option2[display string], 1005             ... 1006             } 1007             1008             !group NAME { 1009             field1 1010             field2 1011             ... 1012             } 1013             1014             !section id heading 1015             1016             !head ... 1017             1018             !note { 1019             ... 1020             } 1021             1022             !submit label, label 2, ... 1023             1024             !reset label 1025               1026             =head2 Directives 1027               1028             All directives start with a C followed by a keyword. There are two types of 1029             directives: 1030               1031             =over 1032               1033             =item Line directives 1034               1035             Line directives occur all on one line, and require no special punctuation. Examples 1036             of line directives are L|/!title> and L|/!section>. 1037               1038             =item Block directives 1039               1040             Block directives consist of a directive keyword followed by a curly-brace delimited 1041             block. Examples of these are L|/!group> and L|/!description>. 1042             Some of these directives have their own internal structure; see the list of directives 1043             below for an explanation. 1044               1045             =back 1046               1047             And here is the complete list of directives 1048               1049             =over 1050               1051             =item C 1052               1053             Defines a validation pattern. 1054               1055             =item C 1056               1057             Defines a list for use in a C, C, or C field that includes an "other" option, 1236             append the string C<+other> to the field type: 1237               1238             position:select+other 1239               1240             Or, to let FormBuilder decide whether to use radio buttons or a dropdown: 1241               1242             position+other 1243               1244             Like growable fields, 'other' fields require FormBuilder 3.02 or higher. 1245               1246             For the input types that can have options (C