File Coverage

blib/lib/Rose/HTML/Form/Field/Numeric.pm
Criterion Covered Total %
statement 50 51 98.0
branch 26 30 86.6
condition 16 21 76.1
subroutine 9 9 100.0
pod 4 4 100.0
total 105 115 91.3


line stmt bran cond sub pod time code
1             package Rose::HTML::Form::Field::Numeric;
2              
3 7     7   104245 use strict;
  7         21  
  7         258  
4              
5 7     7   44 use Rose::HTML::Object::Errors qw(:number);
  7         30  
  7         80  
6              
7 7     7   52 use base 'Rose::HTML::Form::Field::Text';
  7         17  
  7         5189  
8              
9             our $VERSION = '0.624';
10              
11             # use Rose::Object::MakeMethods::Generic
12             # (
13             # scalar => [ qw(min max) ],
14             # );
15              
16             __PACKAGE__->default_html_attr_value(size => 6);
17              
18             __PACKAGE__->add_required_html_attrs({
19             type => 'number',
20             });
21              
22             sub positive
23             {
24 5     5 1 26 my($self) = shift;
25              
26 5 100 66     40 if(!@_ || $_[0])
    50          
27             {
28 3         22 $self->min(0);
29 3         19 $self->max(undef);
30             }
31             elsif(@_)
32             {
33 2         10 $self->min(undef);
34             }
35             }
36              
37             sub negative
38             {
39 4     4 1 12 my($self) = shift;
40              
41 4 100 66     34 if(!@_ || $_[0])
    50          
42             {
43 2         11 $self->max(0);
44 2         8 $self->min(undef);
45             }
46             elsif(@_)
47             {
48 2         11 $self->max(undef);
49             }
50             }
51              
52             sub internal_value
53             {
54 172     172 1 317 my($self) = shift;
55              
56 172         534 my $value = $self->SUPER::internal_value(@_);
57              
58 172 100       470 if(defined $value)
59             {
60 161         330 for($value)
61             {
62 161 100       577 s/-\s+/-/ || s/\+\s+//;
63             }
64             }
65              
66 172 100 100     1038 return (defined $value && $value =~ /\S/) ? $value : undef;
67             }
68              
69             # This is $RE{num}{dec} from Regexp::Common::number
70             my $Match = qr{^(?:(?i)(?:[+-]?)(?:(?=[0123456789]|[.])(?:[0123456789]*)(?:(?:[.])(?:[0123456789]{0,}))?)(?:(?:[E])(?:(?:[+-]?)(?:[0123456789]+))|))$};
71              
72             sub validate
73             {
74 51     51 1 1009 my($self) = shift;
75              
76 51         185 my $ok = $self->SUPER::validate(@_);
77 51 100       143 return $ok unless($ok);
78              
79 50         124 my $value = $self->internal_value;
80 50 100 66     215 return 1 unless(defined $value && length $value);
81              
82 49         165 my $min = $self->min;
83 49         186 my $max = $self->max;
84              
85 49 50   16   209 my $name = sub { $self->error_label || $self->name };
  16         60  
86              
87 49 100       446 unless($value =~ $Match)
88             {
89 5 50 33     25 if(defined $min && $min >= 0)
90             {
91 0         0 $self->add_error_id(NUM_INVALID_NUMBER_POSITIVE, { label => $name });
92             }
93             else
94             {
95 5         54 $self->add_error_id(NUM_INVALID_NUMBER, { label => $name });
96             }
97              
98 5         33 return 0;
99             }
100              
101 44 100 100     196 if(defined $min && $value < $min)
102             {
103 6 100       21 if($min == 0)
104             {
105 4         21 $self->add_error_id(NUM_NOT_POSITIVE_NUMBER, { label => $name });
106             }
107             else
108             {
109 2         12 $self->add_error_id(NUM_BELOW_MIN, { label => $name, value => $min });
110             }
111 6         36 return 0;
112             }
113              
114 38 100 100     144 if(defined $max && $value > $max)
115             {
116 4         25 $self->add_error_id(NUM_ABOVE_MAX, { label => $name, value => $max });
117 4         23 return 0;
118             }
119              
120 34         184 return 1;
121             }
122              
123             if(__PACKAGE__->localizer->auto_load_messages)
124             {
125             __PACKAGE__->localizer->load_all_messages;
126             }
127              
128 7     7   69 use utf8; # The __DATA__ section contains UTF-8 text
  7         16  
  7         56  
129              
130             1;
131              
132             __DATA__
133              
134             [% LOCALE en %]
135              
136             NUM_INVALID_NUMBER = "[label] must be a number."
137             NUM_INVALID_NUMBER_POSITIVE = "[label] must be a positive number."
138             NUM_NOT_POSITIVE_NUMBER = "[label] must be a positive number."
139             NUM_BELOW_MIN = "[label] must be greater than or equal to [value]."
140             NUM_ABOVE_MAX = "[label] must be less than or equal to [value]."
141              
142             [% LOCALE de %]
143              
144             NUM_INVALID_NUMBER = "[label] muß eine Zahl sein."
145             NUM_INVALID_NUMBER_POSITIVE = "[label] muß eine positive Zahl sein."
146             NUM_NOT_POSITIVE_NUMBER = "[label] muß eine positive Zahl sein."
147             NUM_BELOW_MIN = "[label] muß größer als oder gleich [value] sein."
148             NUM_ABOVE_MAX = "[label] muß kleiner oder gleich [value] sein."
149              
150             [% LOCALE fr %]
151              
152             NUM_INVALID_NUMBER = "[label] doit être un nombre."
153             NUM_INVALID_NUMBER_POSITIVE = "[label] doit être un nombre positif."
154             NUM_NOT_POSITIVE_NUMBER = "[label] doit être un nombre positif."
155             NUM_BELOW_MIN = "[label] doit être plus grand ou égal à [value]."
156             NUM_ABOVE_MAX = "[label] doit être plus petit ou égal à [value]."
157              
158             [% LOCALE bg %]
159              
160             NUM_INVALID_NUMBER = "Полето '[label]' трябва да бъде цяло число."
161             NUM_INVALID_NUMBER_POSITIVE = "Полето '[label]' трябва да бъде цяло положително число."
162             NUM_NOT_POSITIVE_NUMBER = "Полето '[label]' трябва да бъде цяло положително число."
163             NUM_BELOW_MIN = "Стойността в '[label]' трябва да бъде по-голяма от [value]."
164             NUM_ABOVE_MAX = "Стойността в '[label]' трябва да бъде по-малка или равна на [value]."
165              
166             __END__
167              
168             =head1 NAME
169              
170             Rose::HTML::Form::Field::Numeric - Text field that only accepts numeric values.
171              
172             =head1 SYNOPSIS
173              
174             $field =
175             Rose::HTML::Form::Field::Numeric->new(
176             label => 'Distance',
177             name => 'distance',
178             maxlength => 6);
179              
180             $field->input_value('abc');
181             $field->validate; # false
182              
183             $field->input_value(123);
184             $field->validate; # true
185              
186             # Set minimum and maximum values
187             $field->min(2);
188             $field->max(100);
189              
190             $field->input_value(123);
191             $field->validate; # false
192              
193             $field->input_value(1);
194             $field->validate; # false
195              
196             $field->input_value(5.5);
197             $field->validate; # true
198              
199             print $field->html;
200             ...
201              
202             =head1 DESCRIPTION
203              
204             L<Rose::HTML::Form::Field::Numeric> is a subclass of L<Rose::HTML::Form::Field::Text> that only accepts numeric values. It overrides the L<validate()|Rose::HTML::Form::Field/validate> method of its parent class, returning true if the L<internal_value()|Rose::HTML::Form::Field/internal_value> is a valid number, or setting an error message and returning false otherwise.
205              
206             Use the L<min|/min> and :<max|/max> attributes to control whether the range of valid values.
207              
208             =head1 OBJECT METHODS
209              
210             =over 4
211              
212             =item B<max [NUMERIC]>
213              
214             Get or set the maximum acceptable value. If the field's L<internal_value()|Rose::HTML::Form::Field/internal_value> is B<greater than> this value, then the L<validate()|Rose::HTML::Form::Field/validate> method will return false. If undefined, then no limit on the maximum value is enforced.
215              
216             =item B<min [NUMERIC]>
217              
218             Get or set the minimum acceptable value. If the field's L<internal_value()|Rose::HTML::Form::Field/internal_value> is B<less than> this value, then the L<validate()|Rose::HTML::Form::Field/validate> method will return false. If undefined, then no limit on the minimum value is enforced.
219              
220             =item B<negative [BOOL]>
221              
222             If BOOL is true or omitted, sets L<max|/max> to C<0>. If BOOL is false, sets L<max|/max> to undef.
223              
224             =item B<positive [BOOL]>
225              
226             If BOOL is true or omitted, sets L<min|/min> to C<0>. If BOOL is false, sets L<min|/min> to undef.
227              
228             =back
229              
230             =head1 AUTHOR
231              
232             John C. Siracusa (siracusa@gmail.com)
233              
234             =head1 LICENSE
235              
236             Copyright (c) 2010 by John C. Siracusa. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.