File Coverage

blib/lib/Validator/Custom.pm
Criterion Covered Total %
statement 293 301 97.3
branch 172 184 93.4
condition 27 36 75.0
subroutine 26 27 96.3
pod 8 12 66.6
total 526 560 93.9


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