Changeset 16 in text-formbuilder


Ignore:
Timestamp:
11/03/04 15:18:24 (20 years ago)
Author:
peter
Message:

catch, warn about, and skip unknown directives (lines beginning with !)
optionally use PerlTidy to clean up generated module code
updated version number and docs
write, write_module, and form automatically call build if necessary

Location:
trunk/lib/Text
Files:
2 edited

Legend:

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

    r15 r16  
    44use warnings; 
    55 
    6 our $VERSION = '0.03'; 
    7  
     6our $VERSION = '0.04'; 
     7 
     8use Carp; 
    89use Text::FormBuilder::Parser; 
    910use CGI::FormBuilder; 
     
    3435sub parse_text { 
    3536    my ($self, $src) = @_; 
     37     
    3638    # so it can be called as a class method 
    3739    $self = $self->new unless ref $self; 
     40     
    3841    $self->{form_spec} = $self->{parser}->form_spec($src); 
     42     
     43    # mark structures as not built (newly parsed text) 
     44    $self->{built} = 0; 
     45     
    3946    return $self; 
    4047} 
     
    4249sub build { 
    4350    my ($self, %options) = @_; 
    44      
     51 
     52    # save the build options so they can be used from write_module 
    4553    $self->{build_options} = { %options }; 
    4654     
     
    8795    } 
    8896 
     97    # TODO: configurable threshold for this 
    8998    foreach (@{ $self->{form_spec}{fields} }) { 
    9099        $$_{ulist} = 1 if defined $$_{options} and @{ $$_{options} } >= 3; 
     
    114123    $self->{form}->field(%{ $_ }) foreach @{ $self->{form_spec}{fields} }; 
    115124     
     125    # mark structures as built 
     126    $self->{built} = 1; 
     127     
    116128    return $self; 
    117129} 
     
    119131sub write { 
    120132    my ($self, $outfile) = @_; 
     133     
     134    # automatically call build if needed to 
     135    # allow the new->parse->write shortcut 
     136    $self->build unless $self->{built}; 
     137     
    121138    if ($outfile) { 
    122139        open FORM, "> $outfile"; 
     
    129146 
    130147sub write_module { 
    131     my ($self, $package) = @_; 
    132  
    133     use Data::Dumper; 
     148    my ($self, $package, $use_tidy) = @_; 
     149 
     150    croak 'Expecting a package name' unless $package; 
     151     
     152    # automatically call build if needed to 
     153    # allow the new->parse->write shortcut 
     154    $self->build unless $self->{built}; 
     155     
     156    # conditionally use Data::Dumper 
     157    eval 'use Data::Dumper;'; 
     158    die "Can't write module; need Data::Dumper. $@" if $@; 
     159     
    134160    # don't dump $VARn names 
    135161    $Data::Dumper::Terse = 1; 
    136162     
    137     my $title = $self->{form_spec}{title} || ''; 
    138     my $author = $self->{form_spec}{author} || ''; 
     163    my $title       = $self->{form_spec}{title} || ''; 
     164    my $author      = $self->{form_spec}{author} || ''; 
    139165    my $description = $self->{form_spec}{description} || ''; 
    140     my $headings = Data::Dumper->Dump([$self->{form_spec}{headings}],['headings']); 
    141     my $fields = Data::Dumper->Dump([ [ map { $$_{name} } @{ $self->{form_spec}{fields} } ] ],['fields']); 
    142      
    143     my $source = $self->{build_options}{form_only} ? $self->_form_template : $self->_template; 
    144      
    145     my $options = keys %{ $self->{build_options} } > 0 ? Data::Dumper->Dump([$self->{build_options}],['*options']) : ''; 
     166     
     167    my $headings    = Data::Dumper->Dump([$self->{form_spec}{headings}],['headings']); 
     168    my $fields      = Data::Dumper->Dump([ [ map { $$_{name} } @{ $self->{form_spec}{fields} } ] ],['fields']); 
     169     
     170    my %options = %{ $self->{build_options} }; 
     171    my $source = $options{form_only} ? $self->_form_template : $self->_template; 
     172     
     173    delete $options{fomr_only}; 
     174     
     175    my $form_options = keys %options > 0 ? Data::Dumper->Dump([$self->{build_options}],['*options']) : ''; 
    146176     
    147177    my $field_setup = join( 
     
    179209            }, 
    180210        }, 
    181         $options 
     211        $form_options 
    182212    ); 
    183213     
     
    1902201; 
    191221END 
     222     
    192223    my $outfile = (split(/::/, $package))[-1] . '.pm'; 
    193224     
    194     if ($outfile) { 
     225    if ($use_tidy) { 
     226        # clean up the generated code, if asked 
     227        eval 'use Perl::Tidy'; 
     228        die "Can't tidy the code: $@" if $@; 
     229        Perl::Tidy::perltidy(source => \$module, destination => $outfile); 
     230    } else { 
     231        # otherwise, just print as is 
    195232        open FORM, "> $outfile"; 
    196233        print FORM $module; 
    197234        close FORM; 
    198     } else { 
    199         print $module; 
    200     } 
    201 } 
    202  
    203 sub form { shift->{form} } 
     235    } 
     236} 
     237 
     238sub form { 
     239    my $self = shift; 
     240     
     241    # automatically call build if needed to 
     242    # allow the new->parse->write shortcut 
     243    $self->build unless $self->{built}; 
     244 
     245    return $self->{form}; 
     246} 
    204247 
    205248sub _form_template { 
     
    245288<hr /> 
    246289<div id="footer"> 
    247   <p id="creator">Made with <a href="http://formbuilder.org/">CGI::FormBuilder</a> version <% $CGI::FormBuilder::VERSION %>.</p> 
     290  <p id="creator">Made with <a href="http://formbuilder.org/">CGI::FormBuilder</a> version <% CGI::FormBuilder->VERSION %>.</p> 
    248291</div> 
    249292</body> 
     
    267310=head1 NAME 
    268311 
    269 Text::FormBuilder - Parser for a minilanguage describing web forms 
     312Text::FormBuilder - Parser for a minilanguage for generating web forms 
    270313 
    271314=head1 SYNOPSIS 
    272315 
     316    use Text::FormBuilder; 
     317     
    273318    my $parser = Text::FormBuilder->new; 
    274319    $parser->parse($src_file); 
    275320     
    276     # returns a new CGI::FormBuilder object with the fields 
    277     # from the input form spec 
     321    # returns a new CGI::FormBuilder object with 
     322    # the fields from the input form spec 
    278323    my $form = $parser->form; 
    279324 
     
    287332     
    288333    # or as a class method 
    289     my $parser = Txt::FormBuilder->parse($src_file); 
     334    my $parser = Text::FormBuilder->parse($src_file); 
    290335 
    291336=head2 parse_text 
     337 
     338    $parser->parse_text($src); 
     339 
     340Parse the given C<$src> text. Returns the parse object. 
    292341 
    293342=head2 build 
     
    310359defaults that this module uses. 
    311360 
     361The C<form>, C<write>, and C<write_module> methods will all call 
     362C<build> with no options for you if you do not do so explicitly. 
     363This allows you to say things like this: 
     364 
     365    my $form = Text::FormBuilder->new->parse('formspec.txt')->form; 
     366 
     367However, if you need to specify options to C<build>, you must call it 
     368explictly after C<parse>. 
     369 
    312370=head2 form 
    313371 
    314372    my $form = $parser->form; 
    315373 
    316 Returns the L<CGI::FormBuilder> object. 
     374Returns the L<CGI::FormBuilder> object. Remember that you can modify 
     375this object directly, in order to (for example) dynamically populate 
     376dropdown lists or change input types at runtime. 
    317377 
    318378=head2 write 
     
    327387=head2 write_module 
    328388 
    329     $parser->write_module($package); 
     389    $parser->write_module($package, $use_tidy); 
    330390 
    331391Takes a package name, and writes out a new module that can be used by your 
    332392CGI script to render the form. This way, you only need CGI::FormBuilder on 
    333393your server, and you don't have to parse the form spec each time you want  
    334 to display your form. 
     394to display your form. The generated module has one function (not exported) 
     395called C<get_form>, that takes a CGI object as its only argument, and returns 
     396a CGI::FormBuilder object. 
     397 
     398First, you parse the formspec and write the module, which you can do as a one-liner: 
     399 
     400    $ perl -MText::FormBuilder -e"Text::FormBuilder->parse('formspec.txt')->write_module('MyForm')" 
     401 
     402And then, in your CGI script, use the new module: 
    335403 
    336404    #!/usr/bin/perl -w 
    337405    use strict; 
    338406     
    339     # your CGI script 
    340      
    341407    use CGI; 
    342408    use MyForm; 
    343409     
    344410    my $q = CGI->new; 
    345     my $form = MyForm::form($q); 
     411    my $form = MyForm::get_form($q); 
    346412     
    347413    # do the standard CGI::FormBuilder stuff 
     
    352418        print $form->render; 
    353419    } 
    354      
     420 
     421If you pass a true value as the second argument to C<write_module>, the parser 
     422will run L<Perl::Tidy> on the generated code before writing the module file. 
    355423 
    356424=head2 dump 
    357425 
    358 Uses L<YAML> to print out a human-readable representaiton of the parsed 
     426Uses L<YAML> to print out a human-readable representation of the parsed 
    359427form spec. 
    360428 
     
    367435    !author ... 
    368436     
     437    !description { 
     438        ... 
     439    } 
     440     
    369441    !pattern name /regular expression/ 
     442     
    370443    !list name { 
    371444        option1[display string], 
     
    394467=item C<!author> 
    395468 
     469=item C<!description> 
     470 
    396471=item C<!head> 
    397472 
     
    417492=head1 TODO 
    418493 
    419 =head2 Langauge 
    420  
    421 Directive for a descriptive or explanatory paragraph about the form 
     494C<!include> directive to include external formspec files 
     495 
     496Field groups all on one line in the generated form 
     497 
     498Tests! 
    422499 
    423500=head1 SEE ALSO 
     
    425502L<CGI::FormBuilder> 
    426503 
     504=head1 AUTHOR 
     505 
     506Peter Eichman <peichman@cpan.org> 
     507 
     508=head1 COPYRIGHT AND LICENSE 
     509 
     510Copyright E<copy>2004 by Peter Eichman. 
     511 
     512This program is free software; you can redistribute it and/or 
     513modify it under the same terms as Perl itself. 
     514 
    427515=cut 
  • trunk/lib/Text/FormBuilder/grammar

    r14 r16  
    1414    } 
    1515 
    16 list_def: '!list' list_name (static_list | dynamic_list) 
    17     { $lists{$item{list_name}} = [ @options ]; @options = () } 
     16list_def: '!list' var_name (static_list | dynamic_list) 
     17    { $lists{$item{var_name}} = [ @options ]; @options = () } 
    1818 
    1919static_list: '{' option(s /,\s*/) /,?/ '}' 
     
    2929    } 
    3030 
    31 list_name: /[A-Z_]+/ 
    32  
    3331description_def: '!description' <perl_codeblock> 
    3432    { warn "[Text::FormBuilder] Description redefined at input text line $thisline\n" if defined $description; 
     
    3836    } 
    3937 
    40 line: <skip:'[ \t]*'> ( title | author | pattern_def | heading | field | comment | blank ) "\n" 
     38line: <skip:'[ \t]*'> ( title | author | pattern_def | heading | unknown_directive | field | comment | blank ) "\n" 
    4139 
    4240title: '!title' /.*/ 
     
    4745    { $author = $item[2] } 
    4846 
    49 pattern_def: '!pattern' pattern_name pattern 
    50     { $patterns{$item{pattern_name}} = $item{pattern} } 
     47pattern_def: '!pattern' var_name pattern 
     48    { $patterns{$item{var_name}} = $item{pattern} } 
    5149 
    52 pattern_name: /[A-Z_]+/ 
    5350pattern: /.*/ 
    5451 
     
    8885name: identifier 
    8986 
     87var_name: /[A-Z_]+/ 
     88 
    9089field_size: '[' ( row_col | size ) ']' 
    9190 
     
    123122 
    124123identifier: /\w+/ 
     124 
     125# skip unknown directives with a warning 
     126unknown_directive: /\!\S*/ /.*/ 
     127    { warn "[Text::Formbuilder] Skipping unknown directive '$item[1]' at input text line $thisline\n"; } 
Note: See TracChangeset for help on using the changeset viewer.