Changeset 39 in text-formbuilder for trunk


Ignore:
Timestamp:
12/07/04 16:18:02 (20 years ago)
Author:
peter
Message:

added write_script function to write a complete CGI script using the form
abstracted some of the internal code generating and writing code to be easily reused by write_* functions
started work on allowing validation coderefs in the formspec

Location:
trunk/lib/Text
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/Text/FormBuilder.pm

    r38 r39  
    4141 
    4242my $DEFAULT_CHARSET = 'iso-8859-1'; 
     43 
     44# options to clean up the code with Perl::Tidy 
     45my $TIDY_OPTIONS = '-nolq -ci=4 -ce'; 
    4346 
    4447sub new { 
     
    177180    } 
    178181     
    179     # substitute in custom pattern definitions for field validation 
    180     if (my %patterns = %{ $self->{form_spec}{patterns} || {} }) { 
    181         foreach (@{ $self->{form_spec}{fields} }) { 
    182             if ($$_{validate} and exists $patterns{$$_{validate}}) { 
     182    # substitute in custom validation subs and pattern definitions for field validation 
     183    my %patterns = %{ $self->{form_spec}{patterns} || {} }; 
     184    my %subs = %{ $self->{form_spec}{subs} || {} }; 
     185     
     186    foreach (@{ $self->{form_spec}{fields} }) { 
     187        if ($$_{validate}) { 
     188            if (exists $patterns{$$_{validate}}) { 
    183189                $$_{validate} = $patterns{$$_{validate}}; 
     190            # TODO: need the Data::Dumper code to work for this 
     191            # for now, we just warn that it doesn't work 
     192            } elsif (exists $subs{$$_{validate}}) { 
     193                warn "[Text::FormBuilder] validate coderefs don't work yet"; 
     194                delete $$_{validate}; 
     195##                 $$_{validate} = eval "sub $subs{$$_{validate}}"; 
    184196            } 
    185197        } 
     
    229241    $$_{required} or delete $$_{required} foreach @{ $self->{form_spec}{fields} }; 
    230242 
     243    foreach (@{ $self->{form_spec}{sections} }) { 
     244        for my $line (grep { $$_[0] eq 'field' } @{ $$_{lines} }) { 
     245            $_ eq 'name' or delete $$line[1]{$_} foreach keys %{ $$line[1] }; 
     246        } 
     247    } 
     248     
    231249    $self->{form} = CGI::FormBuilder->new( 
    232250        %DEFAULT_OPTIONS, 
     
    275293} 
    276294 
    277 sub write_module { 
    278     my ($self, $package, $use_tidy) = @_; 
    279  
    280     croak '[Text::FormBuilder::write_module] Expecting a package name' unless $package; 
    281      
     295sub _form_code { 
     296    my $self = shift; 
    282297    # automatically call build if needed to 
    283298    # allow the new->parse->write shortcut 
     
    322337    delete $options{$_} foreach qw(form_only css extra_css); 
    323338     
    324     my $form_options = keys %options > 0 ? Data::Dumper->Dump([\%options],['*options']) : ''; 
     339    my %module_subs; 
     340    my $d = Data::Dumper->new([ \%options ], [ '*options' ]); 
     341     
     342    #TODO: need a workaround/better solution since Data::Dumper doesn't like dumping coderefs 
     343##     foreach (@{ $self->{form_spec}{fields} }) { 
     344##         if (ref $$_{validate} eq 'CODE') { 
     345##             $d->Seen({ "*_validate_$$_{name}" => $$_{validate} }); 
     346##             $module_subs{$$_{name}} = "sub _validate_$$_{name} $$_{validate}"; 
     347##         } 
     348##     } 
     349##      
     350##     my $sub_code = join("\n", each %module_subs); 
     351    my $form_options = keys %options > 0 ? $d->Dump : ''; 
    325352     
    326353    my $field_setup = join( 
    327354        "\n",  
    328         map { '$cgi_form->field' . Data::Dumper->Dump([$_],['*field']) . ';' } @{ $self->{form_spec}{fields} } 
     355        map { '$form->field' . Data::Dumper->Dump([$_],['*field']) . ';' } @{ $self->{form_spec}{fields} } 
    329356    ); 
     357     
     358    return <<END; 
     359my \$form = CGI::FormBuilder->new( 
     360    params => \$q, 
     361    $form_options 
     362); 
     363 
     364$field_setup 
     365END 
     366} 
     367 
     368sub write_module { 
     369    my ($self, $package, $use_tidy) = @_; 
     370 
     371    croak '[Text::FormBuilder::write_module] Expecting a package name' unless $package; 
     372     
     373    my $form_code = $self->_form_code; 
    330374     
    331375    my $module = <<END; 
     
    337381 
    338382sub get_form { 
    339     my \$cgi = shift; 
    340     my \$cgi_form = CGI::FormBuilder->new( 
    341         params => \$cgi, 
    342         $form_options 
    343     ); 
    344      
    345     $field_setup 
    346      
    347     return \$cgi_form; 
     383    my \$q = shift; 
     384 
     385    $form_code 
     386     
     387    return \$form; 
    348388} 
    349389 
     
    354394    my $outfile = (split(/::/, $package))[-1] . '.pm'; 
    355395     
     396    _write_output_file($module, $outfile, $use_tidy); 
     397    return $self; 
     398} 
     399 
     400sub write_script { 
     401    my ($self, $script_name, $use_tidy) = @_; 
     402 
     403    croak '[Text::FormBuilder::write_script] Expecting a script name' unless $script_name; 
     404     
     405    my $form_code = $self->_form_code; 
     406     
     407    my $script = <<END; 
     408#!/usr/bin/perl 
     409use strict; 
     410use warnings; 
     411 
     412use CGI; 
     413use CGI::FormBuilder; 
     414 
     415my \$q = CGI->new; 
     416 
     417$form_code 
     418     
     419unless (\$form->submitted && \$form->validate) { 
     420    print \$form->render; 
     421} else { 
     422    # do something with the entered data 
     423} 
     424END 
     425     
     426    _write_output_file($script, $script_name, $use_tidy);    
     427    return $self; 
     428} 
     429 
     430sub _write_output_file { 
     431    my ($source_code, $outfile, $use_tidy) = @_; 
    356432    if ($use_tidy) { 
    357433        # clean up the generated code, if asked 
    358434        eval 'use Perl::Tidy'; 
    359435        die "Can't tidy the code: $@" if $@; 
    360         Perl::Tidy::perltidy(source => \$module, destination => $outfile, argv => '-nolq -ci=4'); 
     436        Perl::Tidy::perltidy(source => \$source_code, destination => $outfile, argv => $TIDY_OPTIONS); 
    361437    } else { 
    362438        # otherwise, just print as is 
    363         open FORM, "> $outfile"; 
    364         print FORM $module; 
    365         close FORM; 
    366     } 
    367 } 
     439        open OUT, "> $outfile" or die $!; 
     440        print OUT $source_code; 
     441        close OUT; 
     442    } 
     443} 
     444 
    368445 
    369446sub form { 
     
    696773    $parser->write_module('My::Form', 1); 
    697774 
     775=head2 write_script 
     776 
     777    $parser->write_script($filename, $use_tidy); 
     778 
     779If you don't need the reuseability of a separate module, you can have 
     780Text::FormBuilder write the form object to a script for you, along with 
     781the simplest framework for using it, to which you can add your actual 
     782form processing code. 
     783 
     784The generated script looks like this: 
     785 
     786    #!/usr/bin/perl 
     787    use strict; 
     788    use warnings; 
     789     
     790    use CGI; 
     791    use CGI::FormBuilder; 
     792     
     793    my $q = CGI->new; 
     794     
     795    my $form = CGI::FormBuilder->new( 
     796        params => $q, 
     797        # ... lots of other stuff to set up the form ... 
     798    ); 
     799     
     800    $form->field( name => 'month' ); 
     801    $form->field( name => 'day' ); 
     802     
     803    unless ( $form->submitted && $form->validate ) { 
     804        print $form->render; 
     805    } else { 
     806        # do something with the entered data ... 
     807        # this is where your form processing code should go 
     808    } 
     809 
     810Like C<write_module>, you can optionally pass a true value as the second 
     811argument to have Perl::Tidy make the generated code look nicer. 
     812 
    698813=head2 dump 
    699814 
  • trunk/lib/Text/FormBuilder/grammar

    r29 r39  
    1111        %lists, 
    1212        %patterns, 
     13        %subs,         # validation subs 
    1314        @group,        # current group 
    1415        %groups,       # stored groups of fields 
     
    2425} 
    2526 
    26 form_spec: (list_def | description_def | group_def | line)(s) 
     27form_spec: (list_def | description_def | validate_def | group_def | line)(s) 
    2728    { 
    2829        # grab the last section, if there is any 
     
    4546            lists    => \%lists, 
    4647            patterns => \%patterns, 
     48            subs     => \%subs, 
    4749            groups   => \%groups, 
    4850            sections => \@sections, 
     
    7173    $description =~ s/^{\s*|\s*}$//g; 
    7274    } 
     75 
     76validate_def: '!validate' var_name <perl_codeblock> 
     77    { $subs{$item{var_name}} = $item[3] } 
    7378 
    7479group_def: '!group' { $context = 'group' } var_name '{' field_line(s) '}' { $context = 'line' } 
Note: See TracChangeset for help on using the changeset viewer.