Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

import HTML-FormFu 0.01005 from CPAN

git-cpan-module:   HTML-FormFu
git-cpan-version:  0.01005
git-cpan-authorid: CFRANKS
git-cpan-file:     authors/id/C/CF/CFRANKS/HTML-FormFu-0.01005.tar.gz
  • Loading branch information...
commit 7ce29a1301a4b0dcf291c8284a3fe999af520315 1 parent 1d5bfdf
authored September 21, 2007 schwern committed December 11, 2009

Showing 38 changed files with 1,903 additions and 510 deletions. Show diff stats Hide diff stats

  1. 7  Changes
  2. 11  MANIFEST
  3. 3  META.yml
  4. 1  Makefile.PL
  5. 184  lib/HTML/FormFu.pm
  6. 203  lib/HTML/FormFu/Attribute.pm
  7. 56  lib/HTML/FormFu/Constraint.pm
  8. 3  lib/HTML/FormFu/Constraint/AllOrNone.pm
  9. 8  lib/HTML/FormFu/Constraint/AutoSet.pm
  10. 3  lib/HTML/FormFu/Constraint/CallbackOnce.pm
  11. 3  lib/HTML/FormFu/Constraint/DependOn.pm
  12. 3  lib/HTML/FormFu/Constraint/Equal.pm
  13. 8  lib/HTML/FormFu/Constraint/MinMaxFields.pm
  14. 35  lib/HTML/FormFu/Element.pm
  15. 35  lib/HTML/FormFu/Element/Block.pm
  16. 2  lib/HTML/FormFu/Element/Checkbox.pm
  17. 2  lib/HTML/FormFu/Element/Date.pm
  18. 34  lib/HTML/FormFu/Element/SimpleTable.pm
  19. 380  lib/HTML/FormFu/Element/_Field.pm
  20. 4  lib/HTML/FormFu/Exception.pm
  21. 2  lib/HTML/FormFu/Filter.pm
  22. 732  lib/HTML/FormFu/ObjectUtil.pm
  23. 69  lib/HTML/FormFu/OutputProcessor.pm
  24. 128  lib/HTML/FormFu/OutputProcessor/Indent.pm
  25. 2  lib/HTML/FormFu/Processor.pm
  26. 10  lib/HTML/FormFu/Render/base.pm
  27. 4  lib/HTML/FormFu/Upload.pm
  28. 35  t/constraints/autoset_group.t
  29. 114  t/constraints/constraint_when.t
  30. 45  t/elements/checkbox_force_default.t
  31. 46  t/elements/radio_force_default.t
  32. 33  t/elements/radiogroup_force_default.t
  33. 33  t/elements/select_force_default.t
  34. 30  t/elements/text_force_default.t
  35. 23  t/form/add_valid_unknown.t
  36. 7  t/form/auto_constraint_class.t
  37. 36  t/output_processors/indent.t
  38. 79  t/output_processors/indent_internals.t
7  Changes
... ...
@@ -1,3 +1,10 @@
  1
+0.01005 2007-09-21
  2
+
  3
+	- New Indent "output processor" to pretty-print output
  4
+	- New force_default() method on fields
  5
+	- New when() method for all Constraints
  6
+	- Behaviour change for MinMaxFields Constraint
  7
+
1 8
 0.01004 2007-09-12
2 9
 
3 10
 	- New html_formfu_deploy.pl helper program
11  MANIFEST
@@ -102,6 +102,8 @@ lib/HTML/FormFu/Inflator/DateTime.pm
102 102
 lib/HTML/FormFu/Literal.pm
103 103
 lib/HTML/FormFu/Localize.pm
104 104
 lib/HTML/FormFu/ObjectUtil.pm
  105
+lib/HTML/FormFu/OutputProcessor.pm
  106
+lib/HTML/FormFu/OutputProcessor/Indent.pm
105 107
 lib/HTML/FormFu/Preload.pm
106 108
 lib/HTML/FormFu/Processor.pm
107 109
 lib/HTML/FormFu/QueryType/Catalyst.pm
@@ -179,6 +181,7 @@ t/constraints/autoset_group.t
179 181
 t/constraints/bool.t
180 182
 t/constraints/callback.t
181 183
 t/constraints/callbackonce.t
  184
+t/constraints/constraint_when.t
182 185
 t/constraints/dependon.t
183 186
 t/constraints/email.t
184 187
 t/constraints/equal.t
@@ -208,6 +211,7 @@ t/elements/block.t
208 211
 t/elements/button.t
209 212
 t/elements/button_no_name.t
210 213
 t/elements/checkbox.t
  214
+t/elements/checkbox_force_default.t
211 215
 t/elements/checkbox_retain_default.t
212 216
 t/elements/content_button.t
213 217
 t/elements/date.t
@@ -227,14 +231,17 @@ t/elements/password.t
227 231
 t/elements/password_render_value.t
228 232
 t/elements/password_retain_default.t
229 233
 t/elements/radio.t
  234
+t/elements/radio_force_default.t
230 235
 t/elements/radio_retain_default.t
231 236
 t/elements/radiogroup.t
232 237
 t/elements/radiogroup_errors.t
  238
+t/elements/radiogroup_force_default.t
233 239
 t/elements/radiogroup_id.t
234 240
 t/elements/radiogroup_retain_default.t
235 241
 t/elements/radiogroup_subgroup.t
236 242
 t/elements/reset.t
237 243
 t/elements/select.t
  244
+t/elements/select_force_default.t
238 245
 t/elements/select_optgroup.t
239 246
 t/elements/select_retain_default.t
240 247
 t/elements/select_value_range.t
@@ -249,6 +256,7 @@ t/elements/submit.t
249 256
 t/elements/text.t
250 257
 t/elements/text_attributes.t
251 258
 t/elements/text_errors.t
  259
+t/elements/text_force_default.t
252 260
 t/elements/text_retain_default.t
253 261
 t/elements/textarea.t
254 262
 t/escaping.t
@@ -279,6 +287,7 @@ t/force_errors/integer.t
279 287
 t/force_errors/minmaxfields.t
280 288
 t/form/add_render_class_args.t
281 289
 t/form/add_valid.t
  290
+t/form/add_valid_unknown.t
282 291
 t/form/attributes.t
283 292
 t/form/auto_constraint_class.t
284 293
 t/form/auto_error_class.t
@@ -347,6 +356,8 @@ t/load_config_file_multiple2.yml
347 356
 t/multiple_radiogroup_fields.t
348 357
 t/multiple_select_fields.t
349 358
 t/multiple_text_fields.t
  359
+t/output_processors/indent.t
  360
+t/output_processors/indent_internals.t
350 361
 t/utils/append_xml_attribute.t
351 362
 t/utils/has_xml_attribute.t
352 363
 t/utils/remove_xml_attribute.t
3  META.yml
@@ -28,6 +28,7 @@ requires:
28 28
   File::Copy: 0
29 29
   File::Spec: 0
30 30
   HTML::Scrubber: 0
  31
+  HTML::TokeParser::Simple: 0
31 32
   List::MoreUtils: 0
32 33
   Locale::Maketext::Simple: 0
33 34
   Module::Pluggable: 0
@@ -40,4 +41,4 @@ requires:
40 41
   YAML::Syck: 0
41 42
   perl: 5.8.1
42 43
 tests: t/*.t t/*/*.t
43  
-version: 0.01004
  44
+version: 0.01005
1  Makefile.PL
@@ -22,6 +22,7 @@ requires 'Email::Valid';
22 22
 requires 'File::Copy';
23 23
 requires 'File::Spec';
24 24
 requires 'HTML::Scrubber';
  25
+requires 'HTML::TokeParser::Simple';
25 26
 requires 'List::MoreUtils';
26 27
 requires 'Locale::Maketext::Simple';
27 28
 requires 'Module::Pluggable';
184  lib/HTML/FormFu.pm
@@ -2,8 +2,7 @@ package HTML::FormFu;
2 2
 use strict;
3 3
 
4 4
 use HTML::FormFu::Attribute qw/
5  
-    mk_attrs mk_attr_accessors mk_add_methods mk_single_methods
6  
-    mk_require_methods mk_get_methods mk_get_one_methods 
  5
+    mk_attrs mk_attr_accessors
7 6
     mk_inherited_accessors mk_output_accessors
8 7
     mk_inherited_merging_accessors mk_accessors /;
9 8
 use HTML::FormFu::Constraint;
@@ -13,12 +12,12 @@ use HTML::FormFu::Filter;
13 12
 use HTML::FormFu::Inflator;
14 13
 use HTML::FormFu::Localize;
15 14
 use HTML::FormFu::ObjectUtil qw/
16  
-    _single_element _require_constraint
17  
-    get_elements get_element get_all_elements get_all_element
18  
-    get_fields get_field get_errors get_error clear_errors
  15
+    :FORM_AND_BLOCK
  16
+    :FORM_AND_ELEMENT
19 17
     populate load_config_file insert_before insert_after form
20 18
     _render_class clone stash constraints_from_dbic parent /;
21  
-use HTML::FormFu::Util qw/ require_class _get_elements xml_escape /;
  19
+use HTML::FormFu::Util qw/ require_class _get_elements xml_escape
  20
+    _parse_args /;
22 21
 use List::MoreUtils qw/ uniq /;
23 22
 use Scalar::Util qw/ blessed refaddr weaken /;
24 23
 use Storable qw/ dclone /;
@@ -41,7 +40,7 @@ __PACKAGE__->mk_accessors(
41 40
         element_defaults query_type languages force_error_message
42 41
         localize_class submitted query input _auto_fieldset
43 42
         _elements _processed_params _valid_names
44  
-        render_class_suffix /
  43
+        render_class_suffix _output_processors /
45 44
 );
46 45
 
47 46
 __PACKAGE__->mk_output_accessors(qw/ form_error_message /);
@@ -56,43 +55,19 @@ __PACKAGE__->mk_inherited_accessors(
56 55
 );
57 56
 
58 57
 __PACKAGE__->mk_inherited_merging_accessors(
59  
-    qw/ render_class_args config_callback / );
60  
-
61  
-__PACKAGE__->mk_add_methods(
62  
-    qw/
63  
-        element deflator filter constraint inflator validator transformer /
64  
-);
65  
-
66  
-__PACKAGE__->mk_single_methods(
67  
-    qw/
68  
-        deflator filter constraint inflator validator transformer /
69  
-);
70  
-
71  
-__PACKAGE__->mk_require_methods(
72  
-    qw/
73  
-        deflator filter inflator validator transformer /
74  
-);
75  
-
76  
-__PACKAGE__->mk_get_methods(
77  
-    qw/
78  
-        deflator filter constraint inflator validator transformer /
79  
-);
80  
-
81  
-__PACKAGE__->mk_get_one_methods(
82  
-    qw/
83  
-        deflator filter constraint inflator validator tranformer /
84  
-);
85  
-
86  
-*elements     = \&element;
87  
-*constraints  = \&constraint;
88  
-*filters      = \&filter;
89  
-*deflators    = \&deflator;
90  
-*inflators    = \&inflator;
91  
-*validators   = \&validator;
92  
-*transformers = \&transformer;
93  
-*loc          = \&localize;
94  
-
95  
-our $VERSION = '0.01004';
  58
+    qw/ render_class_args config_callback /);
  59
+
  60
+*elements          = \&element;
  61
+*constraints       = \&constraint;
  62
+*filters           = \&filter;
  63
+*deflators         = \&deflator;
  64
+*inflators         = \&inflator;
  65
+*validators        = \&validator;
  66
+*transformers      = \&transformer;
  67
+*output_processors = \&output_processor;
  68
+*loc               = \&localize;
  69
+
  70
+our $VERSION = '0.01005';
96 71
 $VERSION = eval $VERSION;
97 72
 
98 73
 Class::C3::initialize();
@@ -108,6 +83,7 @@ sub new {
108 83
 
109 84
     my %defaults = (
110 85
         _elements           => [],
  86
+        _output_processors  => [],
111 87
         _valid_names        => [],
112 88
         _processed_params   => {},
113 89
         input               => {},
@@ -275,7 +251,7 @@ sub _build_params {
275 251
 
276 252
     for my $name (@names) {
277 253
         next if !exists $input->{$name};
278  
-        
  254
+
279 255
         my $input = exists $input->{$name} ? $input->{$name} : undef;
280 256
 
281 257
         if ( ref $input eq 'ARRAY' ) {
@@ -331,8 +307,8 @@ sub _filter_input {
331 307
 
332 308
     for my $name ( keys %$params ) {
333 309
         next if !exists $self->input->{$name};
334  
-        
335  
-        for my $filter ( @{ $self->get_filters({ name => $name }) } ) {
  310
+
  311
+        for my $filter ( @{ $self->get_filters( { name => $name } ) } ) {
336 312
             $filter->process( $self, $params );
337 313
         }
338 314
     }
@@ -344,11 +320,11 @@ sub _constrain_input {
344 320
     my ($self) = @_;
345 321
 
346 322
     my $params = $self->_processed_params;
347  
-    
  323
+
348 324
     for my $constraint ( @{ $self->get_constraints } ) {
349  
-        
  325
+
350 326
         my @errors = eval { $constraint->process($params); };
351  
-        
  327
+
352 328
         if ( blessed $@ && $@->isa('HTML::FormFu::Exception::Constraint') ) {
353 329
             push @errors, $@;
354 330
         }
@@ -374,12 +350,12 @@ sub _inflate_input {
374 350
 
375 351
     for my $name ( keys %$params ) {
376 352
         next if !exists $self->input->{$name};
377  
-        
  353
+
378 354
         next if $self->has_errors($name);
379 355
 
380 356
         my $value = $params->{$name};
381 357
 
382  
-        for my $inflator ( @{ $self->get_inflators({ name => $name }) } ) {
  358
+        for my $inflator ( @{ $self->get_inflators( { name => $name } ) } ) {
383 359
             my @errors;
384 360
 
385 361
             ( $value, @errors ) = eval { $inflator->process($value); };
@@ -411,10 +387,10 @@ sub _validate_input {
411 387
 
412 388
     for my $name ( keys %$params ) {
413 389
         next if !exists $self->input->{$name};
414  
-        
415  
-        for my $validator ( @{ $self->get_validators({ name => $name }) } ) {
  390
+
  391
+        for my $validator ( @{ $self->get_validators( { name => $name } ) } ) {
416 392
             next if $self->has_errors( $validator->field->name );
417  
-    
  393
+
418 394
             my @errors = eval { $validator->process($params); };
419 395
             if ( blessed $@ && $@->isa('HTML::FormFu::Exception::Validator') ) {
420 396
                 push @errors, $@;
@@ -422,11 +398,11 @@ sub _validate_input {
422 398
             elsif ($@) {
423 399
                 push @errors, HTML::FormFu::Exception::Validator->new;
424 400
             }
425  
-    
  401
+
426 402
             for my $error (@errors) {
427 403
                 $error->parent( $validator->parent ) if !$error->parent;
428 404
                 $error->validator($validator)        if !$error->validator;
429  
-    
  405
+
430 406
                 $error->parent->add_error($error);
431 407
             }
432 408
         }
@@ -442,11 +418,11 @@ sub _transform_input {
442 418
 
443 419
     for my $name ( keys %$params ) {
444 420
         next if !exists $self->input->{$name};
445  
-        
  421
+
446 422
         my $value = $params->{$name};
447 423
 
448 424
         for my $transformer (
449  
-            @{ $self->get_transformers({ name => $name }) } )
  425
+            @{ $self->get_transformers( { name => $name } ) } )
450 426
         {
451 427
             next if $self->has_errors( $transformer->field->name );
452 428
 
@@ -649,6 +625,96 @@ sub hidden_fields {
649 625
         map { $_->render } @{ $self->get_fields( { type => 'Hidden' } ) };
650 626
 }
651 627
 
  628
+sub output_processor {
  629
+    my ( $self, $arg ) = @_;
  630
+    my @return;
  631
+
  632
+    if ( ref $arg eq 'ARRAY' ) {
  633
+        push @return, map { $self->_single_output_processor($_) } @$arg;
  634
+    }
  635
+    else {
  636
+        push @return, $self->_single_output_processor($arg);
  637
+    }
  638
+
  639
+    return @return == 1 ? $return[0] : @return;
  640
+};
  641
+
  642
+sub _single_output_processor {
  643
+    my ( $self, $arg ) = @_;
  644
+    my @items;
  645
+
  646
+    if ( ref $arg eq 'HASH' ) {
  647
+        push @items, $arg;
  648
+    }
  649
+    elsif ( !ref $arg ) {
  650
+        push @items, { type => $arg };
  651
+    }
  652
+    else {
  653
+        croak 'invalid args';
  654
+    }
  655
+
  656
+    my @return;
  657
+
  658
+    for my $item (@items) {
  659
+        my $type = delete $item->{type};
  660
+
  661
+        my $new = $self->_require_output_processor( $type, $item );
  662
+
  663
+        push @{ $self->_output_processors }, $new;
  664
+        push @return, $new;
  665
+    }
  666
+
  667
+    return @return;
  668
+}
  669
+
  670
+sub _require_output_processor {
  671
+    my ( $self, $type, $opt ) = @_;
  672
+
  673
+    croak 'required arguments: $self, $type, \%options' if @_ != 3;
  674
+
  675
+    eval { my %x = %$opt };
  676
+    croak "options argument must be hash-ref" if $@;
  677
+
  678
+    my $class = $type;
  679
+    if ( not $class =~ s/^\+// ) {
  680
+        $class = "HTML::FormFu::OutputProcessor::$class";
  681
+    }
  682
+
  683
+    $type =~ s/^\+//;
  684
+
  685
+    require_class($class);
  686
+
  687
+    my $object = $class->new( {
  688
+        type   => $type,
  689
+        parent => $self,
  690
+        } );
  691
+
  692
+    $object->populate( $opt );
  693
+
  694
+    return $object;
  695
+};
  696
+
  697
+sub get_output_processors {
  698
+    my $self = shift;
  699
+    my %args = _parse_args(@_);
  700
+
  701
+    my @x = @{ $self->_output_processors };
  702
+
  703
+    if ( exists $args{type} ) {
  704
+        @x = grep { $_->type eq $args{type} } @x;
  705
+    }
  706
+
  707
+    return \@x;
  708
+}
  709
+
  710
+sub get_output_processor {
  711
+    my $self = shift;
  712
+
  713
+    my $x = $self->get_output_processors(@_);
  714
+
  715
+    return @$x ? $x->[0] : ();
  716
+}
  717
+
652 718
 1;
653 719
 
654 720
 __END__
203  lib/HTML/FormFu/Attribute.pm
@@ -3,24 +3,20 @@ package HTML::FormFu::Attribute;
3 3
 use strict;
4 4
 use Exporter qw/ import /;
5 5
 use HTML::FormFu::Util qw/
6  
-    append_xml_attribute remove_xml_attribute literal require_class
  6
+    append_xml_attribute remove_xml_attribute literal
7 7
     _parse_args /;
8  
-use List::MoreUtils qw/ uniq /;
9  
-use Scalar::Util qw/ weaken /;
10  
-use Carp qw/ croak /;
11 8
 
12 9
 our @EXPORT_OK = qw/ mk_attrs mk_attr_accessors mk_attr_modifiers
13  
-    mk_add_methods mk_single_methods mk_require_methods mk_get_methods
14  
-    mk_get_one_methods mk_inherited_accessors mk_output_accessors 
  10
+    mk_inherited_accessors mk_output_accessors
15 11
     mk_inherited_merging_accessors mk_accessors /;
16 12
 
17 13
 sub mk_accessors {
18 14
     my $class = shift;
19 15
 
20 16
     for my $name (@_) {
21  
-        my$sub = sub {
  17
+        my $sub = sub {
22 18
             my $self = shift;
23  
-    
  19
+
24 20
             if ( @_ == 1 ) {
25 21
                 $self->{$name} = $_[0];
26 22
                 return $self;
@@ -33,9 +29,9 @@ sub mk_accessors {
33 29
                 return $self->{$name};
34 30
             }
35 31
         };
36  
-        
  32
+
37 33
         no strict 'refs';
38  
-        *{"$class\::$name"} = $sub
  34
+        *{"$class\::$name"} = $sub;
39 35
     }
40 36
 }
41 37
 
@@ -207,193 +203,6 @@ sub mk_del_attrs {
207 203
     return;
208 204
 }
209 205
 
210  
-sub mk_add_methods {
211  
-    my ( $self, @names ) = @_;
212  
-
213  
-    my $class = ref $self || $self;
214  
-
215  
-    for my $name (@names) {
216  
-        my $sub = sub {
217  
-            my ( $self, $arg ) = @_;
218  
-            my @return;
219  
-            my $sub_name = "_single_$name";
220  
-
221  
-            if ( ref $arg eq 'ARRAY' ) {
222  
-                push @return, map { $self->$sub_name($_) } @$arg;
223  
-            }
224  
-            else {
225  
-                push @return, $self->$sub_name($arg);
226  
-            }
227  
-
228  
-            return @return == 1 ? $return[0] : @return;
229  
-        };
230  
-
231  
-        no strict 'refs';
232  
-
233  
-        *{"$class\::$name"} = $sub;
234  
-    }
235  
-
236  
-    return;
237  
-}
238  
-
239  
-sub mk_single_methods {
240  
-    my ( $self, @names ) = @_;
241  
-
242  
-    my $class = ref $self || $self;
243  
-
244  
-    for my $name (@names) {
245  
-        my $sub = sub {
246  
-            my ( $self, $arg ) = @_;
247  
-            my @items;
248  
-
249  
-            if ( ref $arg eq 'HASH' ) {
250  
-                push @items, $arg;
251  
-            }
252  
-            elsif ( !ref $arg ) {
253  
-                push @items, { type => $arg };
254  
-            }
255  
-            else {
256  
-                croak 'invalid args';
257  
-            }
258  
-
259  
-            my @return;
260  
-
261  
-            for my $item (@items) {
262  
-                my @names = map { ref $_ ? @$_ : $_ }
263  
-                    grep {defined}
264  
-                    ( delete $item->{name}, delete $item->{names} );
265  
-
266  
-                @names = uniq map { $_->name }
267  
-                    grep { defined $_->name } @{ $self->get_fields }
268  
-                    if !@names;
269  
-
270  
-                croak "no field names to add $name to" if !@names;
271  
-
272  
-                my $type = delete $item->{type};
273  
-
274  
-                for my $x (@names) {
275  
-                    my $require_sub  = "_require_$name";
276  
-                    my $array_method = "_${name}s";
277  
-
278  
-                    for my $field ( @{ $self->get_fields( { name => $x } ) } ) {
279  
-                        my $new = $field->$require_sub( $type, $item );
280  
-                        push @{ $field->$array_method }, $new;
281  
-                        push @return, $new;
282  
-                    }
283  
-                }
284  
-            }
285  
-
286  
-            return @return;
287  
-        };
288  
-
289  
-        no strict 'refs';
290  
-
291  
-        *{"$class\::_single_$name"} = $sub;
292  
-    }
293  
-
294  
-    return;
295  
-}
296  
-
297  
-sub mk_require_methods {
298  
-    my ( $self, @names ) = @_;
299  
-
300  
-    my $class = ref $self || $self;
301  
-
302  
-    for my $name (@names) {
303  
-        my $sub = sub {
304  
-            my ( $self, $type, $opt ) = @_;
305  
-
306  
-            croak 'required arguments: $self, $type, \%options' if @_ != 3;
307  
-
308  
-            eval { my %x = %$opt };
309  
-            croak "options argument must be hash-ref" if $@;
310  
-
311  
-            my $class = $type;
312  
-            if ( not $class =~ s/^\+// ) {
313  
-                $class = "HTML::FormFu::" . ucfirst($name) . "::$class";
314  
-            }
315  
-
316  
-            $type =~ s/^\+//;
317  
-
318  
-            require_class($class);
319  
-
320  
-            my $object = $class->new( {
321  
-                    type   => $type,
322  
-                    parent => $self,
323  
-                } );
324  
-
325  
-            # inlined ObjectUtil::populate(), otherwise circular dependency
326  
-            eval {
327  
-                map { $object->$_( $opt->{$_} ) } keys %$opt;
328  
-            };
329  
-            croak $@ if $@;
330  
-
331  
-            return $object;
332  
-        };
333  
-
334  
-        no strict 'refs';
335  
-
336  
-        *{"$class\::_require_$name"} = $sub;
337  
-    }
338  
-
339  
-    return;
340  
-}
341  
-
342  
-sub mk_get_methods {
343  
-    my ( $self, @names ) = @_;
344  
-
345  
-    my $class = ref $self || $self;
346  
-
347  
-    for my $name (@names) {
348  
-        my $sub = sub {
349  
-            my $self       = shift;
350  
-            my %args       = _parse_args(@_);
351  
-            my $get_method = "get_${name}s";
352  
-
353  
-            my @x = map { @{ $_->$get_method(@_) } } @{ $self->_elements };
354  
-
355  
-            if ( exists $args{name} ) {
356  
-                @x = grep { $_->name eq $args{name} } @x;
357  
-            }
358  
-
359  
-            if ( exists $args{type} ) {
360  
-                @x = grep { $_->type eq $args{type} } @x;
361  
-            }
362  
-
363  
-            return \@x;
364  
-        };
365  
-
366  
-        no strict 'refs';
367  
-
368  
-        *{"$class\::get_${name}s"} = $sub;
369  
-    }
370  
-
371  
-    return;
372  
-}
373  
-
374  
-sub mk_get_one_methods {
375  
-    my ( $self, @names ) = @_;
376  
-
377  
-    my $class = ref $self || $self;
378  
-
379  
-    for my $name (@names) {
380  
-        my $sub = sub {
381  
-            my $self       = shift;
382  
-            my $get_method = "get_${name}s";
383  
-
384  
-            my $x = $self->$get_method(@_);
385  
-
386  
-            return @$x ? $x->[0] : ();
387  
-        };
388  
-
389  
-        no strict 'refs';
390  
-
391  
-        *{"$class\::get_$name"} = $sub;
392  
-    }
393  
-
394  
-    return;
395  
-}
396  
-
397 206
 sub mk_inherited_accessors {
398 207
     my ( $self, @names ) = @_;
399 208
 
56  lib/HTML/FormFu/Constraint.pm
@@ -8,7 +8,7 @@ use HTML::FormFu::Exception::Constraint;
8 8
 use Scalar::Util qw/ blessed /;
9 9
 use Carp qw/ croak /;
10 10
 
11  
-__PACKAGE__->mk_accessors(qw/ not force_errors /);
  11
+__PACKAGE__->mk_accessors(qw/ not force_errors when /);
12 12
 
13 13
 sub process {
14 14
     my ( $self, $params ) = @_;
@@ -17,6 +17,9 @@ sub process {
17 17
     my $value = $params->{$name};
18 18
     my @errors;
19 19
 
  20
+    # check when condition
  21
+    return unless $self->_process_when( $params );
  22
+
20 23
     if ( ref $value ) {
21 24
         eval { my @x = @$value };
22 25
         croak $@ if $@;
@@ -95,6 +98,43 @@ sub mk_error {
95 98
     return $err;
96 99
 }
97 100
 
  101
+sub _process_when {
  102
+    my ( $self, $params ) = @_;
  103
+    # returns 1 if when condition is fullfilled or not defined
  104
+    # returns 0 if when condition is defined and not fullfilled
  105
+
  106
+    # get when condition
  107
+    my $when = $self->when;
  108
+    return 1 if !defined $when;
  109
+
  110
+    # check type of 'when'
  111
+    croak "Parameter 'when' is not a hash ref" if ref $when ne 'HASH';
  112
+
  113
+    # field must be defined
  114
+    my $when_field = $when->{field};
  115
+    croak "Parameter 'field' is not defined" if !defined $when_field;
  116
+
  117
+    # nothing to constrain if field doesn't exist
  118
+    my $when_field_value = $params->{$when_field};
  119
+    return 0 if !defined $when_field_value;
  120
+
  121
+    # a compare value must be defined
  122
+    my @values;
  123
+    my $compare_value = $when->{value};
  124
+    push @values, $compare_value if defined $compare_value;
  125
+    my $compare_values = $when->{values};
  126
+    push @values, @$compare_values if ref $compare_values eq 'ARRAY';
  127
+    croak "Parameter 'value' or 'values' are not defined" unless @values;
  128
+
  129
+    # determine if condition is fullfilled
  130
+    my $fullfilled = grep { $when_field_value eq $_ } @values;
  131
+
  132
+    # invert when condition if asked for
  133
+    $fullfilled = $when->{not} ? !$fullfilled : $fullfilled;
  134
+
  135
+    return $fullfilled;
  136
+}
  137
+
98 138
 1;
99 139
 
100 140
 __END__
@@ -112,6 +152,9 @@ HTML::FormFu::Constraint - Constrain User Input
112 152
         constraints:
113 153
           - type: Length
114 154
             min: 8
  155
+            when:
  156
+              field: bar
  157
+              values: [ 1, 3, 5 ]
115 158
       - type: Text
116 159
         name: bar
117 160
         constraints: 
@@ -195,6 +238,17 @@ to.
195 238
 
196 239
 Shorthand for C<< $constraint->parent->name >>
197 240
 
  241
+=head2 when
  242
+
  243
+Defines a condition for the constraint. Only when the condition is fullfilled
  244
+the constraint will be applied.
  245
+
  246
+This method expects a hashref with the following keys:
  247
+  field: name of form field that shall be compared
  248
+  value: expected value in the form field 'field'
  249
+  values: Array of multiple values, one must match to fullfill the condition
  250
+  not: inverse the when condition - value(s) must not match
  251
+
198 252
 =head1 CORE CONSTRAINTS
199 253
 
200 254
 =over
3  lib/HTML/FormFu/Constraint/AllOrNone.pm
@@ -6,6 +6,9 @@ use base 'HTML::FormFu::Constraint::_others';
6 6
 sub process {
7 7
     my ( $self, $params ) = @_;
8 8
 
  9
+    # check when condition
  10
+    return unless $self->_process_when( $params );
  11
+
9 12
     my $others = $self->others;
10 13
     return if !defined $others;
11 14
 
8  lib/HTML/FormFu/Constraint/AutoSet.pm
@@ -8,7 +8,7 @@ sub process {
8 8
     my $self = shift;
9 9
 
10 10
     my @set = map { _parse_value($_) } @{ $self->parent->_options };
11  
-    
  11
+
12 12
     $self->set( \@set );
13 13
 
14 14
     return $self->next::method(@_);
@@ -16,9 +16,9 @@ sub process {
16 16
 
17 17
 sub _parse_value {
18 18
     my ($item) = @_;
19  
-    
20  
-    if ( exists $item->{group} ){
21  
-        return map { _parse_value($_) } @{ $item->{group} }
  19
+
  20
+    if ( exists $item->{group} ) {
  21
+        return map { _parse_value($_) } @{ $item->{group} };
22 22
     }
23 23
     else {
24 24
         return $item->{value};
3  lib/HTML/FormFu/Constraint/CallbackOnce.pm
@@ -8,6 +8,9 @@ __PACKAGE__->mk_accessors(qw/ callback /);
8 8
 sub process {
9 9
     my ( $self, $params ) = @_;
10 10
 
  11
+    # check when condition
  12
+    return unless $self->_process_when( $params );
  13
+
11 14
     my $name = $self->name;
12 15
 
13 16
     my $value = $params->{$name};
3  lib/HTML/FormFu/Constraint/DependOn.pm
@@ -6,6 +6,9 @@ use base 'HTML::FormFu::Constraint::_others';
6 6
 sub process {
7 7
     my ( $self, $params ) = @_;
8 8
 
  9
+    # check when condition
  10
+    return unless $self->_process_when( $params );
  11
+
9 12
     my $others = $self->others;
10 13
     return if !defined $others;
11 14
 
3  lib/HTML/FormFu/Constraint/Equal.pm
@@ -6,6 +6,9 @@ use base 'HTML::FormFu::Constraint::_others';
6 6
 sub process {
7 7
     my ( $self, $params ) = @_;
8 8
 
  9
+    # check when condition
  10
+    return unless $self->_process_when( $params );
  11
+
9 12
     my $others = $self->others;
10 13
     return if !defined $others;
11 14
 
8  lib/HTML/FormFu/Constraint/MinMaxFields.pm
@@ -21,6 +21,9 @@ sub process {
21 21
     my ( $self, $params ) = @_;
22 22
     my $count = 0;
23 23
 
  24
+    # check when condition
  25
+    return unless $self->_process_when( $params );
  26
+
24 27
     # others are needed
25 28
     my $others = $self->others;
26 29
     return if !defined $others;
@@ -29,7 +32,7 @@ sub process {
29 32
     my $min = $self->minimum;
30 33
     $min = 1 if !defined $min;
31 34
     my $max = $self->maximum;
32  
-    $max = 1 if !defined $max;
  35
+    $max = 1 + scalar @$others if !defined $max;
33 36
 
34 37
     # get field names to check
35 38
     my @names = ( $self->name );
@@ -107,6 +110,9 @@ The maximum number of named fields which must be filled in.
107 110
 
108 111
 L</max> is an alias for L</maximum>.
109 112
 
  113
+The default for max is the number of all affected fields, in other words one
  114
+more than the number of elements given to others.
  115
+
110 116
 =head2 attach_errors_to_base
111 117
 
112 118
 Default Value: 1
35  lib/HTML/FormFu/Element.pm
@@ -3,11 +3,12 @@ package HTML::FormFu::Element;
3 3
 use strict;
4 4
 use Class::C3;
5 5
 
6  
-use HTML::FormFu::Attribute qw/ mk_attrs mk_attr_accessors 
7  
-    mk_output_accessors mk_inherited_accessors mk_accessors 
  6
+use HTML::FormFu::Attribute qw/ mk_attrs mk_attr_accessors
  7
+    mk_output_accessors mk_inherited_accessors mk_accessors
8 8
     mk_inherited_merging_accessors /;
9  
-use HTML::FormFu::ObjectUtil qw/ load_config_file _render_class
10  
-    populate form stash parent /;
  9
+use HTML::FormFu::ObjectUtil qw/ 
  10
+    :FORM_AND_ELEMENT
  11
+    load_config_file _render_class populate form stash parent /;
11 12
 use HTML::FormFu::Util qw/ require_class xml_escape /;
12 13
 use Scalar::Util qw/ refaddr /;
13 14
 use Storable qw( dclone );
@@ -48,7 +49,7 @@ sub new {
48 49
 
49 50
     $self->attributes( {} );
50 51
     $self->stash(      {} );
51  
-    
  52
+
52 53
     if ( exists $attrs{parent} ) {
53 54
         $self->parent( delete $attrs{parent} );
54 55
     }
@@ -74,28 +75,16 @@ sub get_field { }
74 75
 
75 76
 sub get_deflators { [] }
76 77
 
77  
-sub get_deflator { }
78  
-
79 78
 sub get_filters { [] }
80 79
 
81  
-sub get_filter { }
82  
-
83 80
 sub get_constraints { [] }
84 81
 
85  
-sub get_constraint { }
86  
-
87 82
 sub get_inflators { [] }
88 83
 
89  
-sub get_inflator { }
90  
-
91 84
 sub get_validators { [] }
92 85
 
93  
-sub get_validator { }
94  
-
95 86
 sub get_transformers { [] }
96 87
 
97  
-sub get_transformer { }
98  
-
99 88
 sub get_errors { [] }
100 89
 
101 90
 sub clear_errors { }
@@ -106,6 +95,18 @@ sub prepare_id { }
106 95
 
107 96
 sub prepare_attrs { }
108 97
 
  98
+sub get_output_processors {
  99
+    my $self = shift;
  100
+
  101
+    return $self->form->get_output_processors(@_);
  102
+}
  103
+
  104
+sub get_output_processor {
  105
+    my $self = shift;
  106
+
  107
+    return $self->form->get_output_processor(@_);
  108
+}
  109
+
109 110
 sub clone {
110 111
     my ($self) = @_;
111 112
 
35  lib/HTML/FormFu/Element/Block.pm
@@ -4,14 +4,10 @@ use strict;
4 4
 use base 'HTML::FormFu::Element';
5 5
 use Class::C3;
6 6
 
7  
-use HTML::FormFu::Attribute qw/
8  
-    mk_add_methods mk_single_methods mk_require_methods mk_get_methods
9  
-    mk_get_one_methods mk_output_accessors /;
  7
+use HTML::FormFu::Attribute qw/ mk_output_accessors /;
10 8
 use HTML::FormFu::ObjectUtil qw/
11  
-    _single_element _require_constraint
12  
-    get_fields get_field get_errors get_error clear_errors
13  
-    get_elements get_element get_all_elements get_all_element insert_before
14  
-    insert_after /;
  9
+    :FORM_AND_BLOCK
  10
+    insert_before insert_after /;
15 11
 use HTML::FormFu::Util qw/ _get_elements xml_escape /;
16 12
 use Storable qw( dclone );
17 13
 use Carp qw/croak/;
@@ -26,31 +22,6 @@ __PACKAGE__->mk_inherited_accessors(
26 22
         auto_transformer_class render_processed_value force_errors /
27 23
 );
28 24
 
29  
-__PACKAGE__->mk_add_methods(
30  
-    qw/
31  
-        element deflator filter constraint inflator valiBdator transformer /
32  
-);
33  
-
34  
-__PACKAGE__->mk_single_methods(
35  
-    qw/
36  
-        deflator constraint filter inflator validator transformer /
37  
-);
38  
-
39  
-__PACKAGE__->mk_require_methods(
40  
-    qw/
41  
-        deflator filter inflator validator transformer /
42  
-);
43  
-
44  
-__PACKAGE__->mk_get_methods(
45  
-    qw/
46  
-        deflator filter constraint inflator validator transformer /
47  
-);
48  
-
49  
-__PACKAGE__->mk_get_one_methods(
50  
-    qw/
51  
-        deflator filter constraint inflator validator transformer /
52  
-);
53  
-
54 25
 *elements     = \&element;
55 26
 *constraints  = \&constraint;
56 27
 *deflators    = \&deflator;
2  lib/HTML/FormFu/Element/Checkbox.pm
@@ -23,7 +23,7 @@ sub new {
23 23
 }
24 24
 
25 25
 sub process_value {
26  
-    my ( $self, $render ) = @_;
  26
+    my ( $self, $input ) = @_;
27 27
 
28 28
     return $self->value;
29 29
 }
2  lib/HTML/FormFu/Element/Date.pm
@@ -4,7 +4,7 @@ use strict;
4 4
 use base 'HTML::FormFu::Element::_Field', 'HTML::FormFu::Element::Multi';
5 5
 use Class::C3;
6 6
 
7  
-use HTML::FormFu::Attribute qw/ mk_attrs mk_require_methods /;
  7
+use HTML::FormFu::Attribute qw/ mk_attrs /;
8 8
 use HTML::FormFu::Util qw/ _get_elements _parse_args /;
9 9
 use DateTime;
10 10
 use DateTime::Format::Builder;
34  lib/HTML/FormFu/Element/SimpleTable.pm
@@ -7,7 +7,7 @@ use Class::C3;
7 7
 use HTML::FormFu::Util qw/ append_xml_attribute /;
8 8
 use Carp qw/ croak /;
9 9
 
10  
-__PACKAGE__->mk_accessors(qw/ headers odd_class even_class /);
  10
+__PACKAGE__->mk_accessors(qw/ odd_class even_class /);
11 11
 
12 12
 sub new {
13 13
     my $self = shift->next::method(@_);
@@ -17,16 +17,13 @@ sub new {
17 17
     return $self;
18 18
 }
19 19
 
20  
-sub _add_headers {
21  
-    my ($self) = @_;
22  
-
23  
-    my $headers = $self->headers;
24  
-
25  
-    return if !$headers || !@$headers;
  20
+sub headers {
  21
+    my ( $self, $headers ) = @_;
26 22
 
27 23
     eval { my @foo = @$headers; };
28 24
     croak "headers must be passed as an array-ref" if $@;
29 25
 
  26
+    # save any elements already added
30 27
     my @original_rows = @{ $self->_elements };
31 28
     $self->_elements( [] );
32 29
 
@@ -43,7 +40,7 @@ sub _add_headers {
43 40
         push @{ $self->_elements }, @original_rows;
44 41
     }
45 42
 
46  
-    return;
  43
+    return $self;
47 44
 }
48 45
 
49 46
 sub rows {
@@ -75,14 +72,18 @@ sub rows {
75 72
 sub render {
76 73
     my $self = shift;
77 74
 
78  
-    my $copy = $self->clone;
  75
+    my $odd  = $self->odd_class;
  76
+    my $even = $self->even_class;
  77
+    my $i    = 1;
79 78
 
80  
-    my @elements = @{ $copy->_elements };
81  
-    my $odd      = $self->odd_class;
82  
-    my $even     = $self->even_class;
  79
+    for my $row ( @{ $self->get_elements } ) {
  80
+        my $first_cell = $row->get_element;
83 81
 
84  
-    for my $i ( 1 .. scalar @elements ) {
85  
-        my $row = $elements[ $i - 1 ];
  82
+        if ( $i == 1 && $first_cell->tag eq 'th' ) {
  83
+
  84
+            # skip the header row
  85
+            next;
  86
+        }
86 87
 
87 88
         if ( $i % 2 ) {
88 89
             $row->attributes( { class => $odd } )
@@ -92,11 +93,10 @@ sub render {
92 93
             $row->attributes( { class => $even } )
93 94
                 if defined $even;
94 95
         }
  96
+        $i++;
95 97
     }
96 98
 
97  
-    $copy->_add_headers;
98  
-
99  
-    my $render = $copy->next::method(@_);
  99
+    my $render = $self->next::method(@_);
100 100
 
101 101
     append_xml_attribute( $render->attributes, 'class', lc $self->type );
102 102
 
380  lib/HTML/FormFu/Element/_Field.pm
@@ -4,8 +4,7 @@ use strict;
4 4
 use base 'HTML::FormFu::Element';
5 5
 use Class::C3;
6 6
 
7  
-use HTML::FormFu::Attribute qw/
8  
-    mk_attrs mk_require_methods mk_get_one_methods /;
  7
+use HTML::FormFu::Attribute qw/ mk_attrs /;
9 8
 use HTML::FormFu::ObjectUtil qw/
10 9
     get_error _require_constraint /;
11 10
 use HTML::FormFu::Util qw/
@@ -30,7 +29,8 @@ __PACKAGE__->mk_accessors(
30 29
     qw/
31 30
         _constraints _filters _inflators _deflators _validators _transformers
32 31
         _errors container_tag
33  
-        field_filename label_filename retain_default javascript /
  32
+        field_filename label_filename retain_default force_default
  33
+        javascript /
34 34
 );
35 35
 
36 36
 __PACKAGE__->mk_output_accessors(qw/ comment label value /);
@@ -41,92 +41,6 @@ __PACKAGE__->mk_inherited_accessors(
41 41
         auto_transformer_class render_processed_value force_errors /
42 42
 );
43 43
 
44  
-__PACKAGE__->mk_require_methods(
45  
-    qw/
46  
-        deflator filter inflator validator transformer /
47  
-);
48  
-
49  
-__PACKAGE__->mk_get_one_methods(
50  
-    qw/
51  
-        deflator filter constraint inflator validator transformer /
52  
-);
53  
-
54  
-# build _single_X methods
55  
-
56  
-for my $method (
57  
-    qw/
58  
-    deflator filter constraint inflator validator transformer /
59  
-    )
60  
-{
61  
-    no strict 'refs';
62  
-
63  
-    my $sub = sub {
64  
-        my ( $self, $arg ) = @_;
65  
-        my @items;
66  
-
67  
-        if ( ref $arg eq 'HASH' ) {
68  
-            push @items, $arg;
69  
-        }
70  
-        elsif ( !ref $arg ) {
71  
-            push @items, { type => $arg };
72  
-        }
73  
-        else {
74  
-            croak 'invalid args';
75  
-        }
76  
-
77  
-        my @return;
78  
-
79  
-        for my $item (@items) {
80  
-            my $type           = delete $item->{type};
81  
-            my $require_method = "_require_$method";
82  
-            my $array_method   = "_${method}s";
83  
-
84  
-            my $new = $self->$require_method( $type, $item );
85  
-
86  
-            push @{ $self->$array_method }, $new;
87  
-            push @return, $new;
88  
-        }
89  
-
90  
-        return @return;
91  
-    };
92  
-
93  
-    my $name = __PACKAGE__ . "::_single_$method";
94  
-
95  
-    *{$name} = $sub;
96  
-}
97  
-
98  
-# build get_Xs methods
99  
-
100  
-for my $method (
101  
-    qw/
102  
-    deflator filter constraint inflator validator transformer /
103  
-    )
104  
-{
105  
-    no strict 'refs';
106  
-