File Coverage

blib/lib/Rose/HTML/Object/Messages.pm
Criterion Covered Total %
statement 238 240 99.1
branch 28 32 87.5
condition 9 15 60.0
subroutine 66 67 98.5
pod 8 10 80.0
total 349 364 95.8


line stmt bran cond sub pod time code
1              
2             use strict;
3 47     47   397582  
  47         118  
  47         1175  
4             use Carp;
5 47     47   197  
  47         77  
  47         2128  
6             use base 'Rose::HTML::Object::Exporter';
7 47     47   227  
  47         75  
  47         17971  
8             our $VERSION = '0.618';
9              
10             our $Debug = 0;
11              
12             use Rose::Class::MakeMethods::Generic
13             (
14             inheritable_scalar =>
15 47         203 [
16             '_message_names',
17             'message_id_to_name_map',
18             'message_name_to_id_map',
19             ],
20             );
21 47     47   476  
  47         102  
22             BEGIN
23             {
24             __PACKAGE__->_message_names([]);
25 47     47   11588 __PACKAGE__->message_id_to_name_map({});
26 47         491 __PACKAGE__->message_name_to_id_map({});
27 47         312 }
28              
29             {
30             my($class) = shift;
31              
32 139     139 0 274 my $list = $class->message_names;
33              
34 139         393 $class->export_tags
35             (
36             all => $list,
37             field => [ grep { /^FIELD_/ } @$list ],
38             form => [ grep { /^FORM_/ } @$list ],
39 6283         10913 date => [ grep { /^DATE_|_(?:YEAR|MONTH|DAY)$/ } @$list ],
40 6283         8971 time => [ grep { /^TIME_|_(?:HOUR|MINUTE|SECOND)$/ } @$list ],
41 6283         18319 email => [ grep { /^EMAIL_/ } @$list ],
42 6283         17410 phone => [ grep { /^PHONE_/ } @$list ],
43 6283         8731 number => [ grep { /^NUM_/ } @$list ],
44 6283         8367 set => [ grep { /^SET_/ } @$list ],
45 6283         8919 string => [ grep { /^STRING_/ } @$list ],
46 6283         8645 );
47 139         1383 }
  6283         8814  
48              
49             {
50             my($class) = shift;
51              
52             $class->use_private_messages;
53 332     332   66711 $class->init_export_tags;
54              
55 332         1082 if($Rose::HTML::Object::Exporter::Target_Class)
56 332         1174 {
57             $class->SUPER::import(@_);
58 332 100       17415 }
59             else
60 3         14 {
61             local $Rose::HTML::Object::Exporter::Target_Class = (caller)[0];
62             $class->SUPER::import(@_);
63             }
64 329         1034 }
65 329         1457  
66             our %Private;
67              
68             {
69             my($class) = shift;
70              
71             unless($Private{$class})
72             {
73 4221     4221 0 5711 $Private{$class} = 1;
74              
75 4221 100       9042 # Make private copies of inherited data structures
76             # (shallow copy is sufficient)
77 107         212 $class->message_names([ $class->message_names ]);
78             $class->message_id_to_name_map({ %{$class->message_id_to_name_map} });
79             $class->message_name_to_id_map({ %{$class->message_name_to_id_map} });
80             }
81 107         302 }
82 107         618  
  107         327  
83 107         1776  
  107         281  
84             {
85             my($class) = shift;
86              
87 69     69 1 2497 $class->_message_names(@_) if(@_);
88 4     4 1 1377  
89             wantarray ? @{$class->_message_names} :
90             $class->_message_names;
91             }
92 593     593 1 3372  
93             {
94 593 100       1705 my($class, $symbol) = @_;
95             no strict 'refs';
96 593 100       2607 my $const = "${class}::$symbol";
  109         375  
97             return &$const if(defined &$const);
98             return undef;
99             }
100              
101             {
102 113     113 1 1557 my($class) = shift;
103 47     47   25890 my $map = $class->message_id_to_name_map;
  47         106  
  47         6847  
104 113         286  
105 113 100       1069 return wantarray ?
106 2         9 (sort { $a <=> $b } keys %$map) :
107             [ sort { $a <=> $b } keys %$map ];
108             }
109              
110             {
111 6     6 1 8857 no warnings 'uninitialized';
112 6         25 return $_[0]->message_id_to_name_map->{$_[1]};
113             }
114              
115 595         646 {
116 6 100       105 my($class, $name, $id) = @_;
  287         325  
117              
118             $class->use_private_messages;
119              
120             unless($class->imported($name))
121 47     47   328 {
  47         102  
  47         8392  
122 471     471 1 4630 if(exists $class->message_name_to_id_map->{$name} &&
123             $class->message_name_to_id_map->{$name} != $id)
124             {
125             croak "Could not add message '$name' - a message with that name already exists ",
126             '(', $class->message_name_to_id_map->{$name}, ')';
127 3780     3780 1 7156 }
128              
129 3780         7184 if(exists $class->message_id_to_name_map->{$id} &&
130             $class->message_id_to_name_map->{$id} ne $name)
131 3780 100       7717 {
132             croak "Could not add message '$name' - a message with the id $id already exists ",
133 3282 50 33     5975 '(', $class->message_id_to_name_map->{$id}, ')';
134             }
135             }
136              
137 0         0 MAKE_CONSTANT:
138             {
139             no strict 'refs';
140 3282 100 66     22499 my $const = "${class}::$name";
141             unless($class->can($name) || defined &$const)
142             {
143             *{"${class}::$name"} = sub() { $id };
144 2         32  
145             #my $error;
146             #
147             #TRY:
148             #{
149             # local $@;
150 47     47   359 # eval "package $class; use constant $name => $id;";
  47         85  
  47         7783  
  3778         22294  
151 3778         6094 # $error = $@;
152 3778 100 66     12179 #}
153             #
154 19     0   172 #croak "Could not create constant '$name' in $class - $error" if($error);
  19         108  
  0         0  
155             }
156             }
157              
158             unless(exists $class->message_name_to_id_map->{$name})
159             {
160             push(@{$class->_message_names}, $name);
161             }
162              
163             $class->message_id_to_name_map->{$id} = $name;
164             $class->message_name_to_id_map->{$name} = $id;
165              
166             return;
167             }
168              
169 3778 100       6848 {
170             my($class) = shift;
171 3280         18377  
  3280         5672  
172             $class->use_private_messages;
173              
174 3778         23797 no strict 'refs';
175 3778         23373  
176             if(@_)
177 3778         23978 {
178             foreach my $name (@_)
179             {
180             $class->add_message($name, "${class}::$name"->());
181             }
182 109     109 1 3775 }
183             else
184 109         587 {
185             foreach my $name (keys %{"${class}::"})
186 47     47   453 {
  47         127  
  47         12231  
187             my $fq_name = "${class}::$name";
188 109 100       1728  
189             next unless(defined *{$fq_name}{'CODE'} && $name =~ /^[A-Z0-9_]+$/);
190 2         4  
191             my $code = $class->can($name);
192 4         23  
193             # Skip it if it's not a constant
194             next unless(defined prototype($code) && !length(prototype($code)));
195              
196             # Should not need this check?
197 107         166 next if($name =~ /^(BEGIN|DESTROY|AUTOLOAD|TIE.*)$/);
  107         1385  
198              
199 6111         10127 $Debug && warn "$class ADD $name = ", $code->(), "\n";
200             $class->add_message($name, $code->());
201 6111 100 100     6614 }
  6111         43515  
202             }
203 3755         11585 }
204              
205             #
206 3755 50 33     12522 # Messages
207             #
208              
209 3755 50       9567 use constant CUSTOM_MESSAGE => -1;
210              
211 3755 50       5686 # Fields and labels
212 3755         6846 use constant FIELD_LABEL => 1;
213             use constant FIELD_DESCRIPTION => 2;
214             use constant FIELD_REQUIRED_GENERIC => 4;
215             use constant FIELD_REQUIRED_LABELLED => 5;
216             use constant FIELD_REQUIRED_SUBFIELD => 6;
217             use constant FIELD_REQUIRED_SUBFIELDS => 7;
218             use constant FIELD_PARTIAL_VALUE => 8;
219             use constant FIELD_INVALID_GENERIC => 10;
220             use constant FIELD_INVALID_LABELLED => 11;
221 47     47   320  
  47         199  
  47         3067  
222             use constant FIELD_LABEL_YEAR => 10_000;
223             use constant FIELD_LABEL_MONTH => 10_001;
224 47     47   272 use constant FIELD_LABEL_DAY => 10_002;
  47         89  
  47         2602  
225 47     47   295 use constant FIELD_LABEL_HOUR => 10_003;
  47         124  
  47         2196  
226 47     47   262 use constant FIELD_LABEL_MINUTE => 10_004;
  47         162  
  47         2360  
227 47     47   244 use constant FIELD_LABEL_SECOND => 10_005;
  47         89  
  47         2272  
228 47     47   289  
  47         83  
  47         2176  
229 47     47   258 use constant FIELD_ERROR_LABEL_YEAR => 11_000;
  47         76  
  47         2431  
230 47     47   281 use constant FIELD_ERROR_LABEL_MONTH => 11_001;
  47         139  
  47         1963  
231 47     47   252 use constant FIELD_ERROR_LABEL_DAY => 11_002;
  47         109  
  47         2018  
232 47     47   254 use constant FIELD_ERROR_LABEL_HOUR => 11_003;
  47         87  
  47         2054  
233             use constant FIELD_ERROR_LABEL_MINUTE => 11_004;
234 47     47   250 use constant FIELD_ERROR_LABEL_SECOND => 11_005;
  47         77  
  47         2088  
235 47     47   310  
  47         76  
  47         2137  
236 47     47   276 use constant FIELD_ERROR_LABEL_MINIMUM_DATE => 11_006;
  47         230  
  47         2189  
237 47     47   238 use constant FIELD_ERROR_LABEL_MAXIMUM_DATE => 11_007;
  47         297  
  47         1958  
238 47     47   247  
  47         101  
  47         2039  
239 47     47   272 # Forms
  47         123  
  47         1906  
240             use constant FORM_HAS_ERRORS => 100;
241 47     47   298  
  47         122  
  47         1994  
242 47     47   248 # Numerical messages
  47         87  
  47         1975  
243 47     47   241 use constant NUM_INVALID_INTEGER => 1300;
  47         95  
  47         2016  
244 47     47   253 use constant NUM_INVALID_INTEGER_POSITIVE => 1301;
  47         105  
  47         2105  
245 47     47   254 use constant NUM_NOT_POSITIVE_INTEGER => 1302;
  47         134  
  47         2033  
246 47     47   239 use constant NUM_BELOW_MIN => 1303;
  47         92  
  47         2047  
247             use constant NUM_ABOVE_MAX => 1304;
248 47     47   310 use constant NUM_INVALID_NUMBER => 1305;
  47         83  
  47         2143  
249 47     47   253 use constant NUM_INVALID_NUMBER_POSITIVE => 1306;
  47         78  
  47         2078  
250             use constant NUM_NOT_POSITIVE_NUMBER => 1307;
251              
252 47     47   244 # String messages
  47         77  
  47         2047  
253             use constant STRING_OVERFLOW => 1400;
254              
255 47     47   253 # Date messages
  47         91  
  47         1905  
256 47     47   233 use constant DATE_INVALID => 1500;
  47         108  
  47         1919  
257 47     47   236 use constant DATE_MIN_GREATER_THAN_MAX => 1501;
  47         106  
  47         2159  
258 47     47   251  
  47         75  
  47         2078  
259 47     47   233 # Time messages
  47         243  
  47         2037  
260 47     47   244 use constant TIME_INVALID => 1550;
  47         83  
  47         2044  
261 47     47   249 use constant TIME_INVALID_HOUR => 1551;
  47         107  
  47         1975  
262 47     47   244 use constant TIME_INVALID_MINUTE => 1552;
  47         274  
  47         2356  
263             use constant TIME_INVALID_SECONDS => 1553;
264             use constant TIME_INVALID_AMPM => 1554;
265 47     47   285  
  47         106  
  47         2029  
266             # Email messages
267             use constant EMAIL_INVALID => 1600;
268 47     47   314  
  47         186  
  47         1911  
269 47     47   240 # Phone messages
  47         108  
  47         2175  
270             use constant PHONE_INVALID => 1650;
271              
272 47     47   248 # Set messages
  47         78  
  47         2129  
273 47     47   243 use constant SET_INVALID_QUOTED_STRING => 1700;
  47         146  
  47         1843  
274 47     47   256 use constant SET_PARSE_ERROR => 1701;
  47         104  
  47         2092  
275 47     47   256  
  47         100  
  47         1954  
276 47     47   412 BEGIN { __PACKAGE__->add_messages }
  47         119  
  47         2138  
277              
278             1;
279 47     47   265  
  47         88  
  47         2065  
280              
281             =head1 NAME
282 47     47   252  
  47         92  
  47         1850  
283             Rose::HTML::Object::Messages - Message ids and named constants for use with HTML objects.
284              
285 47     47   397 =head1 SYNOPSIS
  47         111  
  47         1999  
286 47     47   241  
  47         86  
  47         2206  
287             package My::HTML::Object::Messages;
288 47     47   193  
289             use strict;
290              
291             # Import the standard set of message ids
292             use Rose::HTML::Object::Messages qw(:all);
293             use base qw(Rose::HTML::Object::Messages);
294              
295             ##
296             ## Define your new message ids below
297             ##
298              
299             # Message ids from 0 to 29,999 are reserved for built-in messages.
300             # Negative message ids are reserved for internal use. Please use
301             # message ids 30,000 or higher for your messages. Suggested message
302             # id ranges and naming conventions for various message types are
303             # shown below.
304              
305             # Field labels
306              
307             use constant FIELD_LABEL_LOGIN_NAME => 100_000;
308             use constant FIELD_LABEL_PASSWORD => 100_001;
309             ...
310              
311             # Field error messages
312              
313             use constant FIELD_ERROR_PASSWORD_TOO_SHORT => 101_000;
314             use constant FIELD_ERROR_USERNAME_INVALID => 101_001;
315             ...
316              
317             # Generic messages
318              
319             use constant LOGIN_NO_SUCH_USER => 200_000;
320             use constant LOGIN_USER_EXISTS_ERROR => 200_001;
321             ...
322              
323             # This line must be below all the "use constant ..." declarations
324             BEGIN { __PACKAGE__->add_messages }
325              
326             1;
327              
328             =head1 DESCRIPTION
329              
330             L<Rose::HTML::Object::Messages> stores message ids and names. The message ids are defined as Perl L<constants|constant> with integer values. The constants themselves as well as the mapping between the symbolic constant names and their values are stored as class data.
331              
332             If you merely want to import one of the standard message id constants, you may use this module as-is (see the L<EXPORTS|/EXPORTS> section for details). If you want to define your own messages, you must subclass this module exactly as shown in the synopsis. The order of the statements is important!
333              
334             When adding your own messages, you are free to choose any integer message id values, subject to the following constraints:
335              
336             =over 4
337              
338             =item * Message ids from 0 to 29,999 are reserved for built-in messages.
339              
340             =item * Negative message ids are reserved for internal use.
341              
342             =back
343              
344             Please use ids 30,000 or higher for your messages. Constant names may contain only the characters C<[A-Z0-9_]> and must be unique among all message constant names.
345              
346             =head1 EXPORTS
347              
348             L<Rose::HTML::Object::Messages> does not export any symbols by default.
349              
350             The 'all' tag:
351              
352             use Rose::HTML::Object::Messages qw(:all);
353              
354             will cause all message name constant to be imported.
355              
356             The following tags will cause all messages whose names match the regular expression to the right of the tag name to be imported.
357              
358             TAG NAME REGEX
359             ----- -----------------
360             field ^FIELD_
361             form ^FORM_
362             date ^DATE_|_(?:YEAR|MONTH|DAY)$
363             time ^TIME_|_(?:HOUR|MINUTE|SECOND)$
364             email ^EMAIL_
365             phone ^PHONE_
366             number ^NUM_
367             set ^SET_
368             string ^STRING_
369              
370             For example, this will import all the message constants whose names begin with "FIELD_"
371              
372             use Rose::HTML::Object::Messages qw(:field);
373              
374             Finally, you can import individual message constant names as well:
375              
376             use Rose::HTML::Object::Messages qw(FIELD_LABEL_YEAR TIME_INVALID);
377              
378             A complete listing of the default set of message constant names appears in the next section.
379              
380             =head1 BUILT-IN MESSAGES
381              
382             The list of built-in messages constant names appears below. You should not rely on the actual numeric values of these constants. Import and refer to them only by their symbolic names.
383              
384             FIELD_LABEL
385             FIELD_DESCRIPTION
386             FIELD_REQUIRED_GENERIC
387             FIELD_REQUIRED_LABELLED
388             FIELD_REQUIRED_SUBFIELD
389             FIELD_REQUIRED_SUBFIELDS
390             FIELD_PARTIAL_VALUE
391             FIELD_INVALID_GENERIC
392             FIELD_INVALID_LABELLED
393              
394             FIELD_LABEL_YEAR
395             FIELD_LABEL_MONTH
396             FIELD_LABEL_DAY
397             FIELD_LABEL_HOUR
398             FIELD_LABEL_MINUTE
399             FIELD_LABEL_SECOND
400              
401             FIELD_ERROR_LABEL_YEAR
402             FIELD_ERROR_LABEL_MONTH
403             FIELD_ERROR_LABEL_DAY
404             FIELD_ERROR_LABEL_HOUR
405             FIELD_ERROR_LABEL_MINUTE
406             FIELD_ERROR_LABEL_SECOND
407              
408             FIELD_ERROR_LABEL_MINIMUM_DATE
409             FIELD_ERROR_LABEL_MAXIMUM_DATE
410              
411             FORM_HAS_ERRORS
412              
413             NUM_INVALID_INTEGER
414             NUM_INVALID_INTEGER_POSITIVE
415             NUM_NOT_POSITIVE_INTEGER
416             NUM_BELOW_MIN
417             NUM_ABOVE_MAX
418             NUM_INVALID_NUMBER
419             NUM_INVALID_NUMBER_POSITIVE
420             NUM_NOT_POSITIVE_NUMBER
421              
422             STRING_OVERFLOW
423              
424             DATE_INVALID
425             DATE_MIN_GREATER_THAN_MAX
426              
427             TIME_INVALID
428             TIME_INVALID_HOUR
429             TIME_INVALID_MINUTE
430             TIME_INVALID_SECONDS
431             TIME_INVALID_AMPM
432              
433             EMAIL_INVALID
434              
435             PHONE_INVALID
436              
437             SET_INVALID_QUOTED_STRING
438             SET_PARSE_ERROR
439              
440             =head1 CLASS METHODS
441              
442             =over 4
443              
444             =item B<add_message NAME, ID>
445              
446             Add a new message constant with NAME and an integer ID value. Message ids from 0 to 29,999 are reserved for built-in messages. Negative message ids are reserved for internal use. Please use message ids 30,000 or higher for your messages. Constant names may contain only the characters C<[A-Z0-9_]> and must be unique among all message names.
447              
448             =item B<add_messages [NAME1, NAME2, ...]>
449              
450             If called with no arguments, this method L<adds|/add_message> all message L<constants|constant> defined in the calling class. Example:
451              
452             __PACKAGE__->add_messages;
453              
454             If called with a list of constant names, add each named constant to the list of messages. These L<constants|constant> must already exist in the calling class. Example:
455              
456             use constant MY_MESSAGE1 => 123456;
457             use constant MY_MESSAGE2 => 123457;
458             ...
459             __PACKAGE__->add_messages('MY_MESSAGE1', 'MY_MESSAGE2');
460              
461             =item B<get_message_id NAME>
462              
463             Returns the integer message id corresponding to the symbolic constant NAME, or undef if no such name exists.
464              
465             =item B<get_message_name ID>
466              
467             Returns the symbolic message constant name corresponding to the integer message ID, or undef if no such message ID exists.
468              
469             =item B<message_id_exists ID>
470              
471             Return true if the integer message ID exists, false otherwise.
472              
473             =item B<message_name_exists NAME>
474              
475             Return true if the symbolic message constant NAME exists, false otherwise.
476              
477             =item B<message_ids>
478              
479             Returns a list (in list context) or reference to an array (in scalar context) of integer message ids.
480              
481             =item B<message_names>
482              
483             Returns a list (in list context) or reference to an array (in scalar context) of message names.
484              
485             =back
486              
487             =head1 AUTHOR
488              
489             John C. Siracusa (siracusa@gmail.com)
490              
491             =head1 LICENSE
492              
493             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.