File Coverage

blib/lib/Validator/Custom.pm
Criterion Covered Total %
statement 292 300 97.3
branch 170 182 93.4
condition 27 36 75.0
subroutine 26 27 96.3
pod 8 12 66.6
total 523 557 93.9


line stmt bran cond sub pod time code
1             package Validator::Custom;
2 5     5   55949 use Object::Simple -base;
  5         3513  
  5         27  
3 5     5   331 use 5.008001;
  5         12  
4             our $VERSION = '1.0201';
5              
6 5     5   23 use Carp 'croak';
  5         9  
  5         240  
7 5     5   1738 use Validator::Custom::Validation;
  5         11  
  5         37  
8 5     5   1695 use Validator::Custom::FilterFunction;
  5         16  
  5         105  
9 5     5   1520 use Validator::Custom::CheckFunction;
  5         7  
  5         110  
10              
11             # Version 0 modules
12 5     5   1577 use Validator::Custom::Constraints;
  5         9  
  5         33  
13 5     5   1817 use Validator::Custom::Constraint;
  5         7  
  5         130  
14 5     5   1702 use Validator::Custom::Result;
  5         10  
  5         33  
15 5     5   1438 use Validator::Custom::Rule;
  5         8  
  5         28  
16              
17 18     18 1 1885 sub validation { Validator::Custom::Validation->new }
18              
19             sub new {
20 136     136 1 51512 my $self = shift->SUPER::new(@_);
21            
22             # Add checks
23 136         771 $self->add_check(
24             ascii_graphic => \&Validator::Custom::CheckFunction::ascii_graphic,
25             number => \&Validator::Custom::CheckFunction::number,
26             int => \&Validator::Custom::CheckFunction::int,
27             in => \&Validator::Custom::CheckFunction::in
28             );
29            
30             # Add filters
31 136         254 $self->add_filter(
32             remove_blank => \&Validator::Custom::FilterFunction::remove_blank,
33             trim => \&Validator::Custom::FilterFunction::trim,
34             );
35            
36             # Version 0 constraints
37             $self->register_constraint(
38 2     2   4 any => sub { 1 },
39             ascii => \&Validator::Custom::Constraint::ascii,
40             between => \&Validator::Custom::Constraint::between,
41             blank => \&Validator::Custom::Constraint::blank,
42             date_to_timepiece => \&Validator::Custom::Constraint::date_to_timepiece,
43             datetime_to_timepiece => \&Validator::Custom::Constraint::datetime_to_timepiece,
44             decimal => \&Validator::Custom::Constraint::decimal,
45 3     3   8 defined => sub { defined $_[0] },
46 136         1182 duplication => \&Validator::Custom::Constraint::duplication,
47             equal_to => \&Validator::Custom::Constraint::equal_to,
48             greater_than => \&Validator::Custom::Constraint::greater_than,
49             http_url => \&Validator::Custom::Constraint::http_url,
50             int => \&Validator::Custom::Constraint::int,
51             in_array => \&Validator::Custom::Constraint::in_array,
52             length => \&Validator::Custom::Constraint::length,
53             less_than => \&Validator::Custom::Constraint::less_than,
54             merge => \&Validator::Custom::Constraint::merge,
55             not_defined => \&Validator::Custom::Constraint::not_defined,
56             not_space => \&Validator::Custom::Constraint::not_space,
57             not_blank => \&Validator::Custom::Constraint::not_blank,
58             uint => \&Validator::Custom::Constraint::uint,
59             regex => \&Validator::Custom::Constraint::regex,
60             selected_at_least => \&Validator::Custom::Constraint::selected_at_least,
61             shift => \&Validator::Custom::Constraint::shift_array,
62             space => \&Validator::Custom::Constraint::space,
63             string => \&Validator::Custom::Constraint::string,
64             to_array => \&Validator::Custom::Constraint::to_array,
65             to_array_remove_blank => \&Validator::Custom::Constraint::to_array_remove_blank,
66             trim => \&Validator::Custom::Constraint::trim,
67             trim_collapse => \&Validator::Custom::Constraint::trim_collapse,
68             trim_lead => \&Validator::Custom::Constraint::trim_lead,
69             trim_trail => \&Validator::Custom::Constraint::trim_trail,
70             trim_uni => \&Validator::Custom::Constraint::trim_uni,
71             trim_uni_collapse => \&Validator::Custom::Constraint::trim_uni_collapse,
72             trim_uni_lead => \&Validator::Custom::Constraint::trim_uni_lead,
73             trim_uni_trail => \&Validator::Custom::Constraint::trim_uni_trail
74             );
75            
76 136         379 return $self;
77             }
78              
79             sub check_each {
80 8     8 1 399 my ($self, $values, $name, $arg) = @_;
81            
82 8 100       15 if (@_ < 3) {
83 2         144 croak "values and the name of a checking function must be passed";
84             }
85            
86 6   50     10 my $checks = $self->{checks} || {};
87            
88             croak "Can't call \"$name\" checking function"
89 6 100       79 unless $checks->{$name};
90            
91 5 100       77 croak "values must be array reference"
92             unless ref $values eq 'ARRAY';
93            
94 4         3 my $is_invalid;
95 4         5 for my $value (@$values) {
96 7         10 my $is_valid = $checks->{$name}->($self, $value, $arg);
97 7 100       28 unless ($is_valid) {
98 2         3 $is_invalid = 1;
99 2         2 last;
100             }
101             }
102            
103 4 100       6 return $is_invalid ? 0 : 1;
104             }
105              
106             sub filter_each {
107 6     6 1 386 my ($self, $values, $name, $arg) = @_;
108            
109 6 100       11 if (@_ < 3) {
110 2         144 croak "values and the name of a filtering function must be passed";
111             }
112            
113 4   50     8 my $filters = $self->{filters} || {};
114            
115             croak "Can't call \"$name\" filtering function"
116 4 100       76 unless $filters->{$name};
117            
118 3 100       90 croak "values must be array reference"
119             unless ref $values eq 'ARRAY';
120            
121 2         2 my $new_values = [];
122 2         4 for my $value (@$values) {
123 4         7 my $new_value = $filters->{$name}->($self, $value, $arg);
124 4         14 push @$new_values, $new_value;
125             }
126            
127 2         3 return $new_values;
128             }
129              
130             sub check {
131 44     44 1 570 my ($self, $value, $name, $arg) = @_;
132              
133 44 100       64 if (@_ < 3) {
134 2         212 croak "value and the name of a checking function must be passed";
135             }
136            
137 42   50     60 my $checks = $self->{checks} || {};
138            
139             croak "Can't call \"$name\" checking function"
140 42 100       116 unless $checks->{$name};
141            
142 41         66 return $checks->{$name}->($self, $value, $arg);
143             }
144              
145             sub filter {
146 10     10 1 386 my ($self, $value, $name, $arg) = @_;
147            
148 10 100       18 if (@_ < 3) {
149 2         140 croak "value and the name of a filtering function must be passed";
150             }
151            
152 8   50     14 my $filters = $self->{filters} || {};
153            
154             croak "Can't call \"$name\" filtering function"
155 8 100       82 unless $filters->{$name};
156            
157 7         14 return $filters->{$name}->($self, $value, $arg);
158             }
159              
160             sub add_check {
161 138     138 1 151 my $self = shift;
162            
163             # Merge
164 138 50       490 my $checks = ref $_[0] eq 'HASH' ? $_[0] : {@_};
165 138 100       119 $self->{checks} = ({%{$self->{checks} || {}}, %$checks});
  138         896  
166            
167 138         263 return $self;
168             }
169              
170             sub add_filter {
171 138     138 1 122 my $self = shift;
172            
173             # Merge
174 138 50       307 my $filters = ref $_[0] eq 'HASH' ? $_[0] : {@_};
175 138 100       90 $self->{filters} = ({%{$self->{filters} || {}}, %$filters});
  138         565  
176            
177 138         185 return $self;
178             }
179              
180             # Version 0 method
181             our %VALID_OPTIONS = map {$_ => 1} qw/message default copy require optional/;
182             sub _parse_constraint {
183 452     452   1641 my ($self, $c) = @_;
184              
185             # Constraint information
186 452         375 my $cinfo = {};
187              
188             # Arrange constraint information
189 452         398 my $constraint = $c->{constraint};
190 452         501 $cinfo->{message} = $c->{message};
191 452         388 $cinfo->{original_constraint} = $c->{constraint};
192            
193             # Code reference
194 452 100       541 if (ref $constraint eq 'CODE') {
195 19         25 $cinfo->{funcs} = [$constraint];
196             }
197             # Simple constraint name
198             else {
199 433         307 my $constraints;
200 433 100       430 if (ref $constraint eq 'ARRAY') {
201 6         6 $constraints = $constraint;
202             }
203             else {
204 427 100       590 if ($constraint =~ /\|\|/) {
205 13         30 $constraints = [split(/\|\|/, $constraint)];
206             }
207             else {
208 414         538 $constraints = [$constraint];
209             }
210             }
211            
212             # Constraint functions
213 433         309 my @cfuncs;
214             my @cargs;
215 433         427 for my $cname (@$constraints) {
216             # Arrange constraint
217 457 100       681 if (ref $cname eq 'HASH') {
218 108         180 my $first_key = (keys %$cname)[0];
219 108         142 push @cargs, $cname->{$first_key};
220 108         101 $cname = $first_key;
221             }
222              
223             # Target is array elements
224 457 100       638 $cinfo->{each} = 1 if $cname =~ s/^@//;
225 457 50       767 croak qq{"\@" must be one at the top of constrinat name}
226             if index($cname, '@') > -1;
227            
228            
229             # Trim space
230 457         542 $cname =~ s/^\s+//;
231 457         486 $cname =~ s/\s+$//;
232            
233             # Negative
234 457 100       537 my $negative = $cname =~ s/^!// ? 1 : 0;
235 457 50       614 croak qq{"!" must be one at the top of constraint name}
236             if index($cname, '!') > -1;
237            
238             # Trim space
239 457         402 $cname =~ s/^\s+//;
240 457         398 $cname =~ s/\s+$//;
241            
242             # Constraint function
243 457 100       824 croak "Constraint name '$cname' must be [A-Za-z0-9_]"
244             if $cname =~ /\W/;
245 456   100     7535 my $cfunc = $self->constraints->{$cname} || '';
246 456 100       2455 croak qq{"$cname" is not registered}
247             unless ref $cfunc eq 'CODE';
248            
249             # Negativate
250             my $f = $negative ? sub {
251 9     9   18 my $ret = $cfunc->(@_);
252 9 100       21 if (ref $ret eq 'ARRAY') {
253 2         3 $ret->[0] = ! $ret->[0];
254 2         4 return $ret;
255             }
256 7         14 else { return !$ret }
257 455 100       536 } : $cfunc;
258            
259             # Add
260 455         808 push @cfuncs, $f;
261             }
262 431         485 $cinfo->{funcs} = \@cfuncs;
263 431         638 $cinfo->{args} = \@cargs;
264             }
265            
266 450         1086 return $cinfo;
267             }
268              
269             has shared_rule => sub { [] };
270             __PACKAGE__->attr('constraints' => sub { {} });
271              
272             # Version 0 method
273 173     173 0 1381 sub create_rule { Validator::Custom::Rule->new(validator => shift) }
274              
275             # Version 0 method
276             sub register_constraint {
277 165     165 0 1187 my $self = shift;
278            
279             # Merge
280 165 100       1807 my $constraints = ref $_[0] eq 'HASH' ? $_[0] : {@_};
281 165         137 $self->constraints({%{$self->constraints}, %$constraints});
  165         3183  
282            
283 165         1360 return $self;
284             }
285              
286             # Version 0 method
287             sub _parse_random_string_rule {
288 1     1   5 my $self = shift;
289            
290             # Rule
291 1 50       8 my $rule = ref $_[0] eq 'HASH' ? $_[0] : {@_};
292            
293             # Result
294 1         2 my $result = {};
295            
296             # Parse string rule
297 1         3 for my $name (keys %$rule) {
298             # Pettern
299 5         6 my $pattern = $rule->{$name};
300 5 100       8 $pattern = '' unless $pattern;
301            
302             # State
303 5         4 my $state = 'character';
304              
305             # Count
306 5         4 my $count = '';
307            
308             # Chacacter sets
309 5         4 my $csets = [];
310 5         5 my $cset = [];
311            
312             # Parse pattern
313 5         3 my $c;
314 5   66     20 while (defined ($c = substr($pattern, 0, 1, '')) && length $c) {
315             # Character class
316 42 100       53 if ($state eq 'character_class') {
    100          
317 9 100       9 if ($c eq ']') {
318 3         4 $state = 'character';
319 3         3 push @$csets, $cset;
320 3         7 $cset = [];
321 3         8 $state = 'character';
322             }
323 6         17 else { push @$cset, $c }
324             }
325            
326             # Count
327             elsif ($state eq 'count') {
328 13 100       12 if ($c eq '}') {
329 6 50       15 $count = 1 if $count < 1;
330 6         9 for (my $i = 0; $i < $count - 1; $i++) {
331 14 50       10 push @$csets, [@{$csets->[-1] || ['']}];
  14         37  
332             }
333 6         3 $count = '';
334 6         18 $state = 'character';
335             }
336 7         17 else { $count .= $c }
337             }
338            
339             # Character
340             else {
341 20 100       26 if ($c eq '[') { $state = 'character_class' }
  3 100       10  
342 6         16 elsif ($c eq '{') { $state = 'count' }
343 11         34 else { push @$csets, [$c] }
344             }
345             }
346            
347             # Add Charcter sets
348 5         11 $result->{$name} = $csets;
349             }
350            
351 1         2 return $result;
352             }
353              
354             # Version 0 method
355             sub validate {
356 177     177 0 14442 my ($self, $input, $rule) = @_;
357            
358             # Class
359 177         204 my $class = ref $self;
360            
361             # Validation rule
362 177   100     389 $rule ||= $self->rule;
363            
364             # Data filter
365 177         3022 my $filter = $self->data_filter;
366 177 100       715 $input = $filter->($input) if $filter;
367            
368             # Check data
369 177 100       479 croak "First argument must be hash ref"
370             unless ref $input eq 'HASH';
371            
372             # Check rule
373 176 100       263 unless (ref $rule eq 'Validator::Custom::Rule') {
374 159 100       346 croak "Invalid rule structure" unless ref $rule eq 'ARRAY';
375             }
376            
377             # Result
378 175         399 my $result = Validator::Custom::Result->new;
379 175         827 $result->{_error_infos} = {};
380            
381             # Save raw data
382 175         2743 $result->raw_data($input);
383            
384             # Error is stock?
385 175         2960 my $error_stock = $self->error_stock;
386            
387             # Valid keys
388 175         984 my $valid_keys = {};
389            
390             # Error position
391 175         153 my $pos = 0;
392            
393             # Found missing parameters
394 175         140 my $found_missing_params = {};
395            
396             # Shared rule
397 175         2538 my $shared_rule = $self->shared_rule;
398            
399 175 100       554 if (ref $rule eq 'Validator::Custom::Rule') {
400 17         213 $self->rule_obj($rule);
401             }
402             else {
403 158         238 my $rule_obj = $self->create_rule;
404 158         1025 $rule_obj->parse($rule, $shared_rule);
405 156         2286 $self->rule_obj($rule_obj);
406             }
407 173         3168 my $rule_obj = $self->rule_obj;
408              
409 173 50 33     735 if ($rule_obj->{version} && $rule_obj->{version} == 1) {
410 0         0 croak "Can't call validate method(Validator::Custom). Use \$rule->validate(\$input) instead";
411             }
412            
413             # Process each key
414             OUTER_LOOP:
415 173         179 for (my $i = 0; $i < @{$rule_obj->rule}; $i++) {
  564         8178  
416            
417 407         6736 my $r = $rule_obj->rule->[$i];
418            
419             # Increment position
420 407         1291 $pos++;
421            
422             # Key, options, and constraints
423 407         353 my $key = $r->{key};
424 407         289 my $opts = $r->{option};
425 407   100     596 my $cinfos = $r->{constraints} || [];
426            
427             # Check constraints
428 407 100       870 croak "Invalid rule structure"
429             unless ref $cinfos eq 'ARRAY';
430              
431             # Arrange key
432 405         269 my $result_key = $key;
433 405 100       731 if (ref $key eq 'HASH') {
    50          
434 49         112 my $first_key = (keys %$key)[0];
435 49         52 $result_key = $first_key;
436 49         61 $key = $key->{$first_key};
437             }
438             elsif (defined $r->{name}) {
439 0         0 $result_key = $r->{name};
440             }
441            
442             # Real keys
443 405         294 my $keys;
444            
445 405 100       555 if (ref $key eq 'ARRAY') { $keys = $key }
  49 100       41  
446             elsif (ref $key eq 'Regexp') {
447 2         2 $keys = [];
448 2         5 for my $k (keys %$input) {
449 5 100       16 push @$keys, $k if $k =~ /$key/;
450             }
451             }
452 354         419 else { $keys = [$key] }
453            
454             # Check option
455 405 100       573 if (exists $opts->{optional}) {
456 1 50       5 if ($opts->{optional}) {
457 1         3 $opts->{require} = 0;
458             }
459 1         9 delete $opts->{optional};
460             }
461 405         656 for my $oname (keys %$opts) {
462             croak qq{Option "$oname" of "$result_key" is invalid name}
463 25 50       46 unless $VALID_OPTIONS{$oname};
464             }
465            
466             # Default
467 405 100       568 if (exists $opts->{default}) {
468 8         9 $r->{default} = $opts->{default};
469             }
470            
471             # Is data copy?
472 405         324 my $copy = 1;
473 405 100       518 $copy = $opts->{copy} if exists $opts->{copy};
474            
475             # Check missing parameters
476 405 100       456 my $require = exists $opts->{require} ? $opts->{require} : 1;
477 405         243 my $found_missing_param;
478 405         5916 my $missing_params = $result->missing_params;
479 405         1066 for my $key (@$keys) {
480 551 100       983 unless (exists $input->{$key}) {
481 16 100 100     56 if ($require && !exists $r->{default}) {
482             push @$missing_params, $key
483 10 100       23 unless $found_missing_params->{$key};
484 10         14 $found_missing_params->{$key}++;
485             }
486 16         17 $found_missing_param = 1;
487             }
488             }
489 405 100       526 if ($found_missing_param) {
490             $result->data->{$result_key} = ref $r->{default} eq 'CODE'
491             ? $r->{default}->($self) : $r->{default}
492 15 100 100     52 if exists $r->{default} && $copy;
    100          
493 15 100 100     68 next if $r->{default} || !$require;
494             }
495            
496             # Already valid
497 399 100       546 next if $valid_keys->{$result_key};
498            
499             # Validation
500             my $value = @$keys > 1
501 196         260 ? [map { $input->{$_} } @$keys]
502 396 100       702 : $input->{$keys->[0]};
503            
504 396         381 for my $cinfo (@$cinfos) {
505            
506             # Constraint information
507 427         391 my $args = $cinfo->{args};
508 427         334 my $message = $cinfo->{message};
509            
510             # Constraint function
511 427         333 my $cfuncs = $cinfo->{funcs};
512            
513             # Is valid?
514 427         281 my $is_valid;
515            
516             # Data is array
517 427 100       492 if($cinfo->{each}) {
518            
519             # To array
520 21 100       34 $value = [$value] unless ref $value eq 'ARRAY';
521            
522             # Validation loop
523 21         36 for (my $k = 0; $k < @$value; $k++) {
524 37         30 my $input = $value->[$k];
525            
526             # Validation
527 37         54 for (my $j = 0; $j < @$cfuncs; $j++) {
528 43         26 my $cfunc = $cfuncs->[$j];
529 43         34 my $arg = $args->[$j];
530            
531             # Validate
532 43         25 my $cresult;
533             {
534 43         26 local $_ = Validator::Custom::Constraints->new(
  43         561  
535             constraints => $self->constraints
536             );
537 43         307 $cresult= $cfunc->($input, $arg, $self);
538             }
539            
540             # Constrint result
541 43         127 my $v;
542 43 100       65 if (ref $cresult eq 'ARRAY') {
    100          
543 18         19 ($is_valid, $v) = @$cresult;
544 18         16 $value->[$k] = $v;
545             }
546             elsif (ref $cresult eq 'HASH') {
547 4         4 $is_valid = $cresult->{result};
548 4 100       7 $message = $cresult->{message} unless $is_valid;
549 4 100       8 $value->[$k] = $cresult->{output} if exists $cresult->{output};
550             }
551 21         17 else { $is_valid = $cresult }
552            
553 43 100       73 last if $is_valid;
554             }
555            
556             # Validation error
557 37 100       74 last unless $is_valid;
558             }
559             }
560            
561             # Data is scalar
562             else {
563             # Validation
564 406         714 for (my $k = 0; $k < @$cfuncs; $k++) {
565 418         320 my $cfunc = $cfuncs->[$k];
566 418         300 my $arg = $args->[$k];
567            
568 418         253 my $cresult;
569             {
570 418         289 local $_ = Validator::Custom::Constraints->new(
  418         6038  
571             constraints => $self->constraints
572             );
573 418         3784 $cresult = $cfunc->($value, $arg, $self);
574             }
575            
576 407 100       1016 if (ref $cresult eq 'ARRAY') {
    100          
577 95         74 my $v;
578 95         122 ($is_valid, $v) = @$cresult;
579 95 100       196 $value = $v if $is_valid;
580             }
581             elsif (ref $cresult eq 'HASH') {
582 2         3 $is_valid = $cresult->{result};
583 2 100       5 $message = $cresult->{message} unless $is_valid;
584 2 100 66     8 $value = $cresult->{output} if exists $cresult->{output} && $is_valid;
585             }
586 310         256 else { $is_valid = $cresult }
587            
588 407 100       855 last if $is_valid;
589             }
590             }
591            
592             # Add error if it is invalid
593 416 100       637 unless ($is_valid) {
594 197 100       277 if (exists $r->{default}) {
595             # Set default value
596             $result->data->{$result_key} = ref $r->{default} eq 'CODE'
597             ? $r->{default}->($self)
598             : $r->{default}
599 6 100 66     101 if exists $r->{default} && $copy;
    100          
600 6         14 $valid_keys->{$result_key} = 1
601             }
602             else {
603             # Resist error info
604 191 100       326 $message = $opts->{message} unless defined $message;
605             $result->{_error_infos}->{$result_key} = {
606             message => $message,
607             position => $pos,
608             reason => $cinfo->{original_constraint},
609             original_key => $key
610 191 100       666 } unless exists $result->{_error_infos}->{$result_key};
611            
612             # No Error stock
613 191 100       284 unless ($error_stock) {
614             # Check rest constraint
615 5         6 my $found;
616 5         8 for (my $k = $i + 1; $k < @{$rule_obj->rule}; $k++) {
  13         212  
617 8         144 my $r_next = $rule_obj->rule->[$k];
618 8         26 my $key_next = $r_next->{key};
619 8 50       12 $key_next = (keys %$key)[0] if ref $key eq 'HASH';
620 8 100       16 $found = 1 if $key_next eq $result_key;
621             }
622 5 100       28 last OUTER_LOOP unless $found;
623             }
624             }
625 194         450 next OUTER_LOOP;
626             }
627             }
628            
629             # Result data
630 188 100       2815 $result->data->{$result_key} = $value if $copy;
631            
632             # Key is valid
633 188         436 $valid_keys->{$result_key} = 1;
634            
635             # Remove invalid key
636 188         333 delete $result->{_error_infos}->{$key};
637             }
638            
639 160         1073 return $result;
640             }
641              
642             # Version 0 attributes
643             has 'data_filter';
644             has 'rule';
645             has 'rule_obj';
646             has error_stock => 1;
647              
648             # Version 0 method
649             sub js_fill_form_button {
650 0     0 0   my ($self, $rule) = @_;
651            
652 0           my $r = $self->_parse_random_string_rule($rule);
653            
654 0           require JSON;
655 0           my $r_json = JSON->new->encode($r);
656            
657 0           my $javascript = << "EOS";
658             (function () {
659              
660             var rule = $r_json;
661              
662             var create_random_value = function (rule, name) {
663             var patterns = rule[name];
664             if (patterns === undefined) {
665             return "";
666             }
667            
668             var value = "";
669             for (var i = 0; i < patterns.length; i++) {
670             var pattern = patterns[i];
671             var num = Math.floor(Math.random() * pattern.length);
672             value = value + pattern[num];
673             }
674            
675             return value;
676             };
677            
678             var addEvent = (function(){
679             if(document.addEventListener) {
680             return function(node,type,handler){
681             node.addEventListener(type,handler,false);
682             };
683             } else if (document.attachEvent) {
684             return function(node,type,handler){
685             node.attachEvent('on' + type, function(evt){
686             handler.call(node, evt);
687             });
688             };
689             }
690             })();
691            
692             var button = document.createElement("input");
693             button.setAttribute("type","button");
694             button.value = "Fill Form";
695             document.body.insertBefore(button, document.body.firstChild)
696              
697             addEvent(
698             button,
699             "click",
700             function () {
701            
702             var input_elems = document.getElementsByTagName('input');
703             var radio_names = {};
704             var checkbox_names = {};
705             for (var i = 0; i < input_elems.length; i++) {
706             var e = input_elems[i];
707              
708             var name = e.getAttribute("name");
709             var type = e.getAttribute("type");
710             if (type === "text" || type === "hidden" || type === "password") {
711             var value = create_random_value(rule, name);
712             e.value = value;
713             }
714             else if (type === "checkbox") {
715             e.checked = Math.floor(Math.random() * 2) ? true : false;
716             }
717             else if (type === "radio") {
718             radio_names[name] = 1;
719             }
720             }
721            
722             for (name in radio_names) {
723             var elems = document.getElementsByName(name);
724             var num = Math.floor(Math.random() * elems.length);
725             elems[num].checked = true;
726             }
727            
728             var textarea_elems = document.getElementsByTagName("textarea");
729             for (var i = 0; i < textarea_elems.length; i++) {
730             var e = textarea_elems[i];
731            
732             var name = e.getAttribute("name");
733             var value = create_random_value(rule, name);
734            
735             var text = document.createTextNode(value);
736            
737             if (e.firstChild) {
738             e.removeChild(e.firstChild);
739             }
740            
741             e.appendChild(text);
742             }
743            
744             var select_elems = document.getElementsByTagName("select");
745             for (var i = 0; i < select_elems.length; i++) {
746             var e = select_elems[i];
747             var options = e.options;
748             if (e.multiple) {
749             for (var k = 0; k < options.length; k++) {
750             options[k].selected = Math.floor(Math.random() * 2) ? true : false;
751             }
752             }
753             else {
754             var num = Math.floor(Math.random() * options.length);
755             e.selectedIndex = num;
756             }
757             }
758             }
759             );
760             })();
761             EOS
762              
763 0           return $javascript;
764             }
765              
766             1;
767              
768             =encoding UTF-8
769              
770             =head1 NAME
771              
772             Validator::Custom - HTML form validation. Simple and good flexibility
773              
774             =head1 DESCRIPTION
775              
776             L is a validator for HTML form.
777              
778             =over 4
779              
780             =item *
781              
782             1. B C, C, C, C. You can also add your checking function.
783              
784             =item *
785              
786             2. B C, C. You can also add your filtering function.
787              
788             =item *
789              
790             3. B Save each validation result and check if all data is valid.
791              
792             =back
793              
794             =head1 SYNOPSIS
795              
796             use Validator::Custom;
797             my $vc = Validator::Custom->new;
798            
799             # Input data
800             my $id = 1;
801             my $name = 'Ken Suzuki';
802             my $price = ' 19.23 ';
803             my $favorite = ['001', '002'];
804            
805             # Create validation object
806             my $validation = $vc->validation;
807            
808             # Check if id is integer
809             if (!$vc->check($id, 'int')) {
810             # Add failed message
811             $validation->add_failed(id => 'id must be integer');
812             }
813            
814             # Check if name has length
815             if (!(length $name)) {
816             $validation->add_failed(name => 'name must have length');
817             }
818             # Check if name's length is less than 30
819             elsif (!(length $name < 30)) {
820             $validation->add_failed(name => 'name is too long');
821             }
822            
823             # Filter price to remove left-rigth space
824             $price = $vc->filter($price, 'trim');
825              
826             # Check price is number and the digits of the decimal part is two or less than two
827             if (!$vc->check($price, 'number', {decimal_part_max => 2})) {
828             # Set default value if validation fail
829             $price = 20.25;
830             }
831            
832             # Filter each value of favorite using "trim" filtering function
833             $favorite = $vc->filter_each($favorite, 'trim');
834            
835             # Check if favorite has at least one values
836             if (@$favorite == 0) {
837             $validation->add_failed(favorite => 'favorite must be selected more than one');
838             }
839             # Check if favorite is one of the specified values
840             elsif (!($vc->check_each($favorite, 'in', ['001', '002', '003']))) {
841             $validation->add_failed(favorite => 'favorite is invalid');
842             }
843            
844             # Check if validation result is valid
845             if ($validation->is_valid) {
846             # ...
847             }
848             else {
849            
850             # Check what parameter fail
851             unless ($validation->is_valid('name')) {
852             # ...
853             }
854            
855             # Get all failed parameter names
856             my $failed = $validation->failed;
857              
858             # Get a failed parameter message
859             my $name_message = $validation->message('name');
860            
861             # Get all failed parameter messages
862             my $messages = $validation->messages;
863            
864             # Get all failed parameter names and the messages as hash reference
865             my $messages_h = $validation->messages_to_hash;
866             }
867            
868             =head1 1. Basic usage
869              
870             =head2 1. Create a new Validator::Custom object
871              
872             At first, create L object using C method.
873              
874             use Validator::Custom;
875             my $vc = Validator::Custom->new;
876              
877             =head2 2. Prepare input data for validation
878              
879             Next, prepare input data.
880              
881             my $id = 1;
882             my $name = 'Ken Suzuki';
883             my $price = ' 19.23 ';
884             my $favorite = ['001', '002'];
885              
886             =head2 3. Create a new validation object
887              
888             Next, create a new validation object using C method.
889              
890             my $validation = $vc->validation;
891              
892             This is L object
893             to store failed parameter names and the messages.
894              
895             =head2 4. Validate input data
896              
897             # Check if id is integer
898             if (!$vc->check($id, 'int')) {
899             # Add failed message
900             $validation->add_failed(id => 'id must be integer');
901             }
902              
903             You can use C checking function to check the value is integer.
904             C checking function is default one.
905             Any checking function is available through C method.
906              
907             When the check doesn't succeed, you can add the failed parameter name and the message
908             using C method of L class.
909            
910             # Filter price to remove left-rigth space
911             $price = $vc->filter($price, 'trim');
912              
913             You can use C filtering function to trim left-rigth spaces.
914            
915             # Filter each value of favorite using "trim" filtering function
916             $favorite = $vc->filter_each($favorite, 'trim');
917              
918             You can use C method to filter each value of favorite.
919            
920             # Check if favorite has at least one values
921             if (@$favorite == 0) {
922             $validation->add_failed(favorite => 'favorite must be selected more than one');
923             }
924             # Check if favorite is one of the specified values
925             elsif (!($vc->check_each($favorite, 'in', ['001', '002', '003']))) {
926             $validation->add_failed(favorite => 'favorite is invalid');
927             }
928              
929             You can use C method to check each value of favorite.
930              
931             If you see default checks and filter,
932             see L and L.
933              
934             =head1 2. Manipulate validation object
935              
936             If you check all input data is valid, use C method.
937            
938             # Check if validation result is valid
939             if ($validation->is_valid) {
940             # Success
941             }
942             else {
943             # Failed
944             }
945              
946             If you can check a input data is valid, use C method with parameter name.
947            
948             # Check what parameter fail
949             unless ($validation->is_valid('name')) {
950             # ...
951             }
952              
953             You can get all failed parameter names using C method.
954              
955             # Get all failed parameter names
956             my $failed = $validation->failed;
957              
958             You can get a failed parameter message using C method.
959              
960             # Get a failed parameter message
961             my $name_message = $validation->message('name');
962              
963             You can get all failed parameter messages using C method.
964              
965             # Get all failed parameter messages
966             my $messages = $validation->messages;
967              
968             You can get all failed names and the messages as hash reference using C method.
969              
970             # Get all failed parameter names and the messages as hash reference
971             my $messages_h = $validation->messages_to_hash;
972              
973             See also L.
974              
975             =head1 3. Advanced tequnique
976              
977             =head2 1. Add checking function
978              
979             You can add your own checking function using C method if you need.
980              
981             $vc->add_check(
982             telephone => sub {
983             my ($vc, $value, $arg) = @_;
984            
985             my $is_valid;
986             if ($value =~ /^[\d-]+$/) {
987             $is_valid = 1;
988             }
989             return $is_valid;
990             }
991             );
992              
993             Checking function receives three arguments,
994             First argument is L object,
995             Second argument is the value for checking,
996             Third argument is the argument of checking function.
997              
998             Your Checking function must return true or false value.
999              
1000             =head2 2. Add filtering function
1001              
1002             You can add your filtering function by C method if you need.
1003              
1004             $vc->add_filter(
1005             to_upper_case => sub {
1006             my ($vc, $value, $arg) = @_;
1007            
1008             my $new_$value = uc $value;
1009            
1010             return $new_value;
1011             }
1012             );
1013              
1014             Filtering function receives three arguments,
1015             First argument is L object,
1016             Second argument is the value for filtering.
1017             Third argument is the argument of filtering function.
1018              
1019             Your filtering function must return the result of filtering.
1020              
1021             =head1 Checking functions
1022              
1023             L have the following default checking functions.
1024             You can call any checking function by C method.
1025              
1026             =head2 int
1027              
1028             Check if the value is integer value.
1029              
1030             my $value = 19;
1031             my $is_valid = $vc->check($value, 'int');
1032              
1033             Example of valid values:
1034              
1035             "-10"
1036             "234"
1037              
1038             Example of invalid values:
1039              
1040             "10.11"
1041             "abc"
1042              
1043             If you also need to check the range of value, you can write the following way.
1044              
1045             my $is_valid = $vc->check($value, 'int') && $value > 0;
1046              
1047             =head2 number
1048              
1049             Check if the value is number.
1050             Number means integer or decimal.
1051            
1052             my $is_valid = $vc->check($value, 'number');
1053              
1054             Example of valid values:
1055              
1056             '1'
1057             '123'
1058             '123.456'
1059             '-1'
1060             '-100'
1061             '-100.789'
1062              
1063             Example of invalid values:
1064              
1065             'a';
1066             '1.a';
1067             'a.1';
1068              
1069             You can also specify decimal part max digits using C option.
1070              
1071             my $is_valid = $vc->check($value, 'number', {decimal_part_max => 3});
1072              
1073             Example of valid values:
1074              
1075             '123'
1076             '123.456'
1077             '-100.789'
1078              
1079             Example of invalid values:
1080              
1081             '123.4567'
1082             '-100.7891'
1083              
1084             =head2 ascii_graphic
1085              
1086             Check if the value is Ascii graphic characters(hex 21-7e).
1087             Generally, C function is used to
1088             check the characters of a password.
1089            
1090             my $is_valid = $vc->check($value, 'ascii');
1091              
1092             Example of valid values:
1093              
1094             "Ken!@-"
1095              
1096             Example of invalid values:
1097            
1098             "aa aa"
1099             "\taaa"
1100              
1101             =head2 in
1102              
1103             Check if the value is one of the given values.
1104            
1105             my $value = '001';
1106             my $is_valid = $vc->check($value, 'in', ['001', '002', '003']);
1107              
1108             Example of valid values:
1109              
1110             '001'
1111             '002'
1112             '003'
1113              
1114             Example of invalid values:
1115              
1116             '004'
1117             '005'
1118              
1119             =head1 Filtering functions
1120              
1121             L have the following default filtering functions.
1122             You can call any filtering function using C method.
1123              
1124             =head2 trim
1125              
1126             Trim leading and trailing white space.
1127             Note that trim function remove unicode space character, not only C<[ \t\n\r\f]>.
1128              
1129             my $new_value = $vc->filter($value, 'trim');
1130              
1131             Filtering example:
1132              
1133             Input : '  Ken '
1134             Output: 'Ken'
1135              
1136             =head2 remove_blank
1137              
1138             Remove blank character and undefined value from array reference.
1139              
1140             my $new_values = $vc->filter($values, 'remove_blank');
1141              
1142             Filtering example:
1143              
1144             Input : [1, 2, '', undef, 4]
1145             Output: [1, 2, 4]
1146              
1147             =head1 Methods
1148              
1149             L inherits all methods from L
1150             and implements the following new ones.
1151              
1152             =head2 new
1153              
1154             Create a new L object.
1155              
1156             my $vc = Validator::Custom->new;
1157              
1158             =head2 add_check
1159              
1160             Add a checking function.
1161              
1162             $vc->add_check(int => sub { ... });
1163              
1164             Example:
1165            
1166             $vc->add_check(
1167             int => sub {
1168             my ($vc, $value, $arg) = @_;
1169            
1170             my $is_valid = $value =~ /^\-?[\d]+$/;
1171            
1172             return $is_valid;
1173             }
1174             );
1175              
1176             Checking function receives three arguments,
1177             First argument is L object,
1178             Second argument is the value for checking,
1179             Third argument is the argument of checking function.
1180              
1181             Your Checking function must return true or false value.
1182              
1183             =head2 add_filter
1184              
1185             Add a filtering function.
1186              
1187             $vc->add_filter(trim => sub { ... });
1188              
1189             Example:
1190              
1191             $vc->add_filter(
1192             trim => sub {
1193             my ($vc, $value, $arg) = @_;
1194            
1195             $value =~ s/^\s+//;
1196             $value =~ s/\s+$//;
1197            
1198             return $value;
1199             }
1200             );
1201              
1202             =head2 check
1203              
1204             Execute a checking function.
1205              
1206             my $is_valid = $vc->check($value, 'int');
1207             my $is_valid = $vc->check($value, 'int', $arg);
1208              
1209             First argument is the value for checking.
1210             Second argument is the name of the checking funcion.
1211             Third argument is the argument of the checking function.
1212              
1213             =head2 check_each
1214              
1215             Execute a checking function to all elements of array reference.
1216             If more than one element is invalid, C method return false.
1217              
1218             my $is_valid = $vc->check_each($values, 'int');
1219             my $is_valid = $vc->check_each($values, 'int', $arg);
1220              
1221             First argument is the values for checking, which must be array reference.
1222             Second argument is the name of the checking funcion.
1223             Third argument is the argument of the checking function.
1224              
1225             =head2 filter
1226              
1227             Execute a filtering function.
1228              
1229             my $new_value = $vc->filter($value, 'trim');
1230             my $new_value = $vc->filter($value, 'trim', $arg);
1231              
1232             First argument is the value for filtering.
1233             Second argument is the name of the filtering funcion.
1234             Third argument is the argument of the filtering function.
1235              
1236             =head2 filter_each
1237              
1238             Execute a filtering function to all elements of array reference.
1239              
1240             my $new_values = $vc->filter_each($values, 'trim');
1241             my $new_values = $vc->filter_each($values, 'trim', $arg);
1242              
1243             First argument is the values for filtering, which must be array reference.
1244             Second argument is the name of the filtering funcion.
1245             Third argument is the argument of the filtering function.
1246              
1247             =head1 EXAMPLES
1248              
1249             Show you some examples to do some validation.
1250              
1251             Password checking:
1252            
1253             my $password = 'abc';
1254             my $password2 = 'abc';
1255            
1256             my $validation = $vc->validation;
1257            
1258             if (!length $password) {
1259             $validation->add_failed(password => 'password must have length');
1260             }
1261             elsif (!$vc->check($password, 'ascii')) {
1262             $validation->add_failed(password => 'password contains invalid characters');
1263             }
1264             elsif ($password ne $password2) {
1265             $validation->add_failed(password => "two passwords don't match");
1266             }
1267            
1268             if ($validation->is_valid) {
1269             # ...
1270             }
1271             else {
1272             # ...
1273             }
1274              
1275             Check box, selected at least 1, one of the given values:
1276              
1277             my $favorite = ['001', '002'];
1278              
1279             my $validation = $vc->validation;
1280            
1281             if (@$favorite == 0) {
1282             $validation->add_failed(favorite => 'favorite must be selected at least 1');
1283             }
1284             elsif (!$vc->check($favorite, 'in', ['001', '002', '003'])) {
1285             $validation->add_failed(favorite => 'favorite have invalid value');
1286             }
1287            
1288             if ($validtion->is_valid) {
1289             # ...
1290             }
1291             else {
1292             # ...
1293             }
1294              
1295             Convert date string to L object.
1296              
1297             my $date = '2014/05/16';
1298            
1299             my $validation = $vc->validation;
1300            
1301             my $date_tp;
1302             if (!length $date) {
1303             $validation->add_failed(date => 'date must have length');
1304             }
1305             else {
1306             eval { $date_tp = Time::Piece->strptime($date, '%Y/%m/%d') };
1307             if (!$date_tp) {
1308             $validation->add_failed(date => 'date value is invalid');
1309             }
1310             }
1311              
1312             Convert datetime string to L object.
1313              
1314             my $datetime = '2014/05/16 12:30:40';
1315            
1316             my $validation = $vc->validation;
1317            
1318             my $datetime_tp;
1319             if (!length $datetime) {
1320             $validation->add_failed(datetime => 'datetime must have length');
1321             }
1322             else {
1323             eval { $datetime_tp = Time::Piece->strptime($datetime, '%Y/%m/%d %H:%M:%S') };
1324             if (!$datetime_tp) {
1325             $validation->add_failed(datetime => 'datetime value is invalid');
1326             }
1327             }
1328              
1329             =head1 FAQ
1330              
1331             =head2 I use Validator::Custom 0.xx yet. I want to see documentation of Version 0.xx.
1332              
1333             See L.
1334             This is complete document for L version 0.xx.
1335              
1336             =head2 What point I take care of in Version 1.xx.
1337              
1338             =over 4
1339              
1340             =item *
1341              
1342             C constraint function is renamed to C checking function.
1343              
1344             =item *
1345              
1346             C filtering function becomes triming unicode space characters, not only C<[ \t\n\r\f]>.
1347              
1348             =item *
1349              
1350             C constraint is renamed to C checking function and simplified.
1351              
1352             =item *
1353              
1354             C checking function doesn't exist.
1355             About alternative way, see the topic "Convert date string to Time::Piece object" in "EXAMPLES".
1356              
1357             =item *
1358              
1359             C checking function doesn't exists.
1360             About alternative way, see the topic "Convert datetime string to Time::Piece object" in "EXAMPLES".
1361              
1362             =back
1363              
1364             =head2 How to create the corresponding checking functions in Version 0.xx constraint functions.
1365              
1366             I show some examples.
1367              
1368             space
1369              
1370             $vc->add_check(space => sub {
1371             my ($vc, $value, $arg) = @_;
1372             return defined $value && $value =~ '^[ \t\n\r\f]*$' ? 1 : 0;
1373             });
1374              
1375             http_url
1376              
1377             $vc->add_check(http_url => sub {
1378             my ($vc, $value, $arg) = @_;
1379             return defined $value && $value =~ /^s?https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#]+$/ ? 1 : 0;
1380             });
1381              
1382             decimal
1383              
1384             $vc->add_check(decimal => sub {
1385             my ($vc, $value, $arg) = @_;
1386              
1387             return undef unless defined $value;
1388            
1389             my $digits_tmp = $arg;
1390            
1391             # Digit
1392             my $digits;
1393             if (defined $digits_tmp) {
1394             if (ref $digits_tmp eq 'ARRAY') {
1395             $digits = $digits_tmp;
1396             }
1397             else {
1398             $digits = [$digits_tmp, undef];
1399             }
1400             }
1401             else {
1402             $digits = [undef, undef];
1403             }
1404            
1405             # Regex
1406             my $re;
1407             if (defined $digits->[0] && defined $digits->[1]) {
1408             $re = qr/^[0-9]{1,$digits->[0]}(\.[0-9]{0,$digits->[1]})?$/;
1409             }
1410             elsif (defined $digits->[0]) {
1411             $re = qr/^[0-9]{1,$digits->[0]}(\.[0-9]*)?$/;
1412             }
1413             elsif (defined $digits->[1]) {
1414             $re = qr/^[0-9]+(\.[0-9]{0,$digits->[1]})?$/;
1415             }
1416             else {
1417             $re = qr/^[0-9]+(\.[0-9]*)?$/;
1418             }
1419            
1420             # Check value
1421             if ($value =~ /$re/) {
1422             return 1;
1423             }
1424             else {
1425             return 0;
1426             }
1427             }
1428              
1429             =head2 How to create the corresponding filtering functions in Version 0.xx constraint functions.
1430              
1431             I show some examples.
1432              
1433             trim_collapse
1434              
1435             $vc->add_filter(trim_collapse => sub {
1436             my ($vc, $value, $arg) = @_;
1437            
1438             return undef unless defined $value;
1439            
1440             $value =~ s/[ \t\n\r\f]+/ /g;
1441             $value =~ s/^[ \t\n\r\f]*(.*?)[ \t\n\r\f]*$/$1/ms;
1442              
1443             return $value;
1444             });
1445              
1446             trim_lead
1447              
1448             $vc->add_filter(trim_lead => sub {
1449             my ($vc, $value, $arg) = @_;
1450            
1451             return undef unless defined $value;
1452              
1453             $value =~ s/^[ \t\n\r\f]+(.*)$/$1/ms;
1454              
1455             return $value;
1456             });
1457              
1458             trim_trail
1459              
1460             $vc->add_filter(trim_trail => sub {
1461             my ($vc, $value, $arg) = @_;
1462            
1463             return undef unless defined $value;
1464              
1465             $value =~ s/^(.*?)[ \t\n\r\f]+$/$1/ms;
1466              
1467             return $value;
1468             });
1469              
1470             trim_uni
1471              
1472             $vc->add_filter(trim_uni => sub {
1473             my ($vc, $value, $arg) = @_;
1474            
1475             return undef unless defined $value;
1476              
1477             $value =~ s/^\s*(.*?)\s*$/$1/ms;
1478              
1479             return $value;
1480             });
1481              
1482             trim_uni_collapse
1483              
1484             $vc->add_filter(trim_uni_collapse => sub {
1485             my ($vc, $value, $arg) = @_;
1486              
1487             return undef unless defined $value;
1488            
1489             $value =~ s/\s+/ /g;
1490             $value =~ s/^\s*(.*?)\s*$/$1/ms;
1491              
1492             return $value;
1493             });
1494              
1495             trim_uni_lead
1496              
1497             $vc->add_filter(trim_uni_lead => sub {
1498             my ($vc, $value, $arg) = @_;
1499            
1500             return undef unless defined $value;
1501            
1502             $value =~ s/^\s+(.*)$/$1/ms;
1503            
1504             return $value;
1505             });
1506              
1507             trim_uni_trail
1508              
1509             $vc->add_filter(trim_uni_trail => sub {
1510             my ($vc, $value, $arg) = @_;
1511            
1512             return undef unless defined $value;
1513              
1514             $value =~ s/^(.*?)\s+$/$1/ms;
1515              
1516             return $value;
1517             });
1518              
1519             =head1 AUTHOR
1520              
1521             Yuki Kimoto, C<< >>
1522              
1523             L
1524              
1525             =head1 COPYRIGHT & LICENCE
1526              
1527             Copyright 2009-2017 Yuki Kimoto, all rights reserved.
1528              
1529             This program is free software; you can redistribute it and/or modify it
1530             under the same terms as Perl itself.
1531              
1532             =cut