File Coverage

blib/lib/Rose/HTML/Objects.pm
Criterion Covered Total %
statement 694 707 98.1
branch 64 84 76.1
condition 12 17 70.5
subroutine 191 201 95.0
pod 1 4 25.0
total 962 1013 94.9


line stmt bran cond sub pod time code
1              
2             use strict;
3 1     1   830  
  1         2  
  1         25  
4             use Carp;
5 1     1   5 use File::Spec();
  1         8  
  1         53  
6 1     1   5 use File::Path();
  1         1  
  1         21  
7 1     1   5 use File::Basename();
  1         1  
  1         11  
8 1     1   4  
  1         1  
  1         1054  
9             our $VERSION = '0.624';
10              
11             our $Debug = 0;
12              
13             {
14             my($class) = shift;
15              
16 3     3 1 1271 my %args = @_;
17              
18 3         14 my($packages, $perl) =
19             Rose::HTML::Objects->private_library_perl(@_);
20 3         12  
21             my $debug = exists $args{'debug'} ? $args{'debug'} : $Debug;
22              
23 3 50       19 if($args{'in_memory'})
24             {
25 3 100       11 foreach my $pkg (@$packages)
26             {
27 2         9 my $code = $perl->{$pkg};
28             $debug > 2 && warn $code, "\n";
29 149         333  
30 149 50       278 my $error;
31              
32 149         170 TRY:
33             {
34             local $@;
35             eval $code;
36 149         187 $error = $@;
  149         212  
37 1     1   6 }
  1     1   1  
  1     1   23  
  1     1   4  
  1     1   2  
  1     1   372  
  1     1   6  
  1     1   1  
  1     1   22  
  1     1   5  
  1     1   2  
  1     1   93  
  1     1   6  
  1     1   2  
  1     1   22  
  1     1   5  
  1     1   10  
  1     1   8  
  1     1   6  
  1     1   2  
  1     1   81  
  1     1   8  
  1     1   6  
  1     1   2  
  1     1   35  
  1     1   6  
  1     1   2  
  1     1   4  
  1     1   5  
  1     1   2  
  1     1   80  
  1     1   8  
  1     1   6  
  1     1   2  
  1     1   22  
  1     1   5  
  1     1   1  
  1     1   104  
  1     1   9  
  1     1   2  
  1     1   35  
  1     1   6  
  1     1   1  
  1     1   143  
  1     1   13  
  1     1   3  
  1     1   48  
  1     1   5  
  1     1   2  
  1     1   183  
  1     1   6  
  1     1   1  
  1     1   36  
  1     1   5  
  1     1   3  
  1     1   24  
  1     1   6  
  1     1   2  
  1     1   24  
  1     1   5  
  1     1   2  
  1     1   26  
  1     1   5  
  1     1   2  
  1     1   25  
  1     1   5  
  1     1   2  
  1     1   24  
  1     1   5  
  1     1   2  
  1     1   23  
  1     1   5  
  1     1   2  
  1     1   22  
  1     1   5  
  1     1   2  
  1     1   31  
  1     1   5  
  1     1   2  
  1     1   24  
  1     1   5  
  1     1   2  
  1     1   33  
  1     1   13  
  1     1   3  
  1     1   28  
  1     1   6  
  1     1   2  
  1     1   45  
  1     1   6  
  1     1   2  
  1     1   23  
  1     1   6  
  1     1   2  
  1     1   27  
  1     1   5  
  1     1   2  
  1     1   33  
  1     1   31  
  1     1   2  
  1     1   34  
  1     1   5  
  1     1   2  
  1     1   28  
  1     1   5  
  1     1   2  
  1     1   31  
  1     1   5  
  1     1   2  
  1     1   23  
  1     1   5  
  1     1   2  
  1     1   30  
  1     1   6  
  1     1   2  
  1     1   23  
  1     1   6  
  1     1   2  
  1     1   22  
  1     1   5  
  1     1   2  
  1     1   22  
  1     1   5  
  1     1   2  
  1     1   31  
  1     1   5  
  1     1   3  
  1     1   23  
  1     1   7  
  1     1   2  
  1     1   33  
  1     1   5  
  1     1   2  
  1     1   24  
  1     1   6  
  1     1   2  
  1     1   32  
  1     1   6  
  1     1   2  
  1     1   23  
  1     1   6  
  1     1   2  
  1     1   23  
  1     1   6  
  1     1   2  
  1     1   22  
  1     1   6  
  1     1   2  
  1     1   23  
  1     1   6  
  1     1   2  
  1     1   23  
  1     1   6  
  1     1   2  
  1     1   26  
  1     1   5  
  1     1   2  
  1     1   32  
  1     1   5  
  1     1   2  
  1     1   22  
  1     1   5  
  1     1   2  
  1     1   23  
  1     1   5  
  1     1   2  
  1     1   22  
  1     1   5  
  1     1   2  
  1     1   24  
  1     0   5  
  1     0   1  
  1     0   31  
  1     1   5  
  1     0   3  
  1     0   22  
  1     1   5  
  1     1   2  
  1     0   31  
  1     0   5  
  1     0   2  
  1     0   36  
  1     1   5  
  1     1   2  
  1     0   39  
  1         8  
  1         2  
  1         27  
  1         6  
  1         2  
  1         24  
  1         6  
  1         2  
  1         24  
  1         5  
  1         2  
  1         31  
  1         5  
  1         2  
  1         22  
  1         6  
  1         2  
  1         22  
  1         5  
  1         2  
  1         31  
  1         5  
  1         3  
  1         21  
  1         6  
  1         2  
  1         24  
  1         6  
  1         2  
  1         22  
  1         6  
  1         2  
  1         23  
  1         6  
  1         2  
  1         26  
  1         5  
  1         2  
  1         32  
  1         5  
  1         2  
  1         33  
  1         5  
  1         2  
  1         32  
  1         5  
  1         2  
  1         25  
  1         6  
  1         2  
  1         33  
  1         5  
  1         2  
  1         24  
  1         6  
  1         2  
  1         32  
  1         5  
  1         2  
  1         23  
  1         5  
  1         1  
  1         32  
  1         5  
  1         2  
  1         25  
  1         11  
  1         3  
  1         35  
  1         5  
  1         2  
  1         533  
  1         11  
  1         6  
  1         29  
  1         10  
  1         3  
  1         102  
  1         6  
  1         2  
  1         31  
  1         11  
  1         2  
  1         12  
  1         5  
  1         9  
  1         116  
  1         15  
  1         6  
  1         1  
  1         122  
  1         8  
  1         7  
  1         12  
  1         5  
  1         3  
  1         106  
  1         8  
  1         6  
  1         5  
  1         33  
  1         6  
  1         3  
  1         108  
  1         10  
  1         3  
  1         35  
  1         6  
  1         6  
  1         127  
  1         13  
  1         4  
  1         173  
  1         6  
  1         7  
  1         40  
  1         5  
  1         3  
  1         25  
  1         5  
  1         2  
  1         36  
  1         10  
  1         3  
  1         27  
  1         5  
  1         2  
  1         30  
  1         5  
  1         2  
  1         25  
  1         6  
  1         2  
  1         24  
  1         5  
  1         2  
  1         30  
  1         6  
  1         6  
  1         33  
  1         5  
  1         3  
  1         38  
  1         5  
  1         3  
  1         24  
  1         5  
  1         2  
  1         34  
  1         5  
  1         2  
  1         26  
  1         11  
  1         3  
  1         33  
  1         6  
  1         2  
  1         24  
  1         5  
  1         2  
  1         37  
  1         5  
  1         2  
  1         23  
  1         5  
  1         6  
  1         26  
  1         9  
  1         3  
  1         25  
  1         6  
  1         3  
  1         33  
  1         5  
  1         6  
  1         27  
  1         6  
  1         2  
  1         23  
  1         6  
  1         3  
  1         37  
  1         6  
  1         3  
  1         22  
  1         10  
  1         3  
  1         24  
  1         9  
  1         3  
  1         37  
  1         5  
  1         2  
  1         24  
  1         5  
  1         2  
  1         23  
  1         5  
  1         2  
  1         24  
  1         10  
  1         3  
  1         31  
  1         5  
  1         2  
  1         31  
  1         5  
  1         1  
  1         30  
  1         6  
  1         6  
  1         48  
  1         7  
  1         2  
  1         22  
  1         6  
  1         2  
  1         23  
  1         6  
  1         3  
  1         31  
  1         7  
  1         2  
  1         33  
  1         5  
  1         2  
  1         22  
  1         6  
  1         2  
  1         22  
  1         6  
  1         2  
  1         22  
  1         5  
  1         2  
  1         23  
  1         6  
  1         1  
  1         32  
  1         7  
  1         1  
  1         23  
  1         5  
  1         2  
  1         29  
  1         6  
  1         3  
  1         23  
  1         5  
  1         2  
  1         24  
  1         6  
  1         2  
  1         43  
  1         5  
  1         2  
  1         21  
  1         5  
  1         2  
  1         31  
  1         7  
  1         2  
  1         33  
  1         5  
  1         1  
  1         30  
  1         6  
  1         6  
  1         26  
  1         6  
  1         2  
  1         38  
  1         9  
  1         4  
  1         24  
  1         5  
  1         3  
  1         42  
  1         5  
  1         2  
  1         30  
  1         6  
  1         2  
  1         31  
  1         6  
  1         2  
  1         23  
  1         5  
  1         2  
  1         32  
  1         5  
  1         2  
  1         24  
  1         679  
  1         3  
  1         30  
  1         6  
  1         290  
  1         32  
  1         5  
  1         2  
  1         22  
  1         5  
  1         2  
  1         23  
  1         4  
  1         3  
  1         22  
  1         5  
  1         2  
  1         22  
  1         5  
  1         3  
  1         22  
  1         5  
  1         2  
  1         23  
  149         9142  
  0         0  
  0         0  
  0         0  
  1         7  
  0         0  
  0         0  
  1         4  
  1         5  
  1         35  
  0         0  
  0         0  
  0         0  
  0         0  
  1         24  
  1         31  
  0         0  
38 149         352  
39             die "Could not eval $pkg - $error" if($error);
40             }
41 149 50       428 }
42             else
43             {
44             my $dir = $args{'modules_dir'} or croak "Missing modules_dir parameter";
45             mkdir($dir) unless(-d $dir);
46 1 50       5 croak "Could not create modules_dir '$dir' - $!" unless(-d $dir);
47 1 50       20  
48 1 50       14 foreach my $pkg (@$packages)
49             {
50 1         4 my @file_parts = split('::', $pkg);
51             $file_parts[-1] .= '.pm';
52 75         325 my $file = File::Spec->catfile($dir, @file_parts);
53 75         156  
54 75         833 my $file_dir = File::Basename::dirname($file);
55              
56 75         2409 File::Path::mkpath($file_dir); # spews errors to STDERR
57             croak "Could not make directory '$file_dir'" unless(-d $file_dir);
58 75         3431  
59 75 50       875 if(-e $file && !$args{'overwrite'})
60             {
61 75 50 66     1200 $debug && warn "Refusing to overwrite '$file'";
62             next;
63 0 0       0 }
64 0         0  
65             open(my $fh, '>', $file) or croak "Could not create '$file' - $!";
66             print $fh $perl->{$pkg};
67 75 50       11280 close($fh) or croak "Could not write '$file' - $!";
68 75         514  
69 75 50       3321 $debug > 2 && warn $perl->{$pkg}, "\n";
70             }
71 75 50       528 }
72              
73             return wantarray ? @$packages : $packages;
74             }
75 3 100       108  
76             {
77             my($class, %args) = @_;
78              
79             my $rename = $args{'rename'};
80 3     3 0 11 my $prefix = $args{'prefix'};
81             my $trim_prefix = $args{'trim_prefix'} || 'Rose::';
82 3         7 my $in_memory = $args{'in_memory'} || 0;
83 3         7  
84 3   50     19 my $prefix_regex = qr(^$trim_prefix);
85 3   100     11  
86             $rename ||= sub
87 3         26 {
88             my($name) = shift;
89             $name =~ s/$prefix_regex/$prefix/;
90             return $name;
91 295     295   347 };
92 295         1354  
93 295         593 my $save_rename = $rename;
94 3   100     19  
95             $rename = sub
96 3         5 {
97             my $name = shift;
98             local $_ = $name;
99             my $new_name = $save_rename->($name);
100 443     443   568  
101 443         544 if($_ ne $name && (!$new_name || $new_name == 1))
102 443         595 {
103             return $_;
104 443 50 33     1515 }
      66        
105              
106 148         285 return $new_name;
107             };
108              
109 295         419 my $class_filter = $args{'class_filter'};
110 3         11  
111             my(%perl, %isa, @packages);
112 3         16  
113             require Rose::HTML::Object;
114 3         5  
115             my $base_object_type = Rose::HTML::Object->object_type_classes;
116 3         624 my %base_type_object = reverse %$base_object_type;
117              
118 3         14 my %object_type;
119 3         564  
120             my $max_type_len = 0;
121 3         11  
122             while(my($type, $base_class) = each(%$base_object_type))
123 3         5 {
124             $object_type{$type} = $rename->($base_class);
125 3         16 $max_type_len = length($type) if(length($type) > $max_type_len);
126             }
127 201         279  
128 201 100       489 my $object_map_perl =<<"EOF";
129             __PACKAGE__->object_type_classes
130             (
131 3         19 EOF
132              
133             foreach my $type (sort keys %object_type)
134             {
135             my $class = $object_type{$type};
136 3         84 $object_map_perl .= sprintf(" %-*s => '$class',\n", $max_type_len + 2, qq('$type'));
137             }
138 201         379  
139 201         409 $object_map_perl .=<<"EOF";
140             );
141             EOF
142 3         21  
143             my $object_package = $rename->('Rose::HTML::Object');
144             my $message_package = $rename->('Rose::HTML::Object::Message::Localized');
145             my $messages_package = $rename->('Rose::HTML::Object::Messages');
146 3         8 my $error_package = $rename->('Rose::HTML::Object::Error');
147 3         7 my $errors_package = $rename->('Rose::HTML::Object::Errors');
148 3         11 my $localizer_package = $rename->('Rose::HTML::Object::Message::Localizer');
149 3         6 my $custom_package = $rename->('Rose::HTML::Object::Custom');
150 3         10  
151 3         26 my $load_message_and_errors_perl = '';
152 3         6  
153             unless($in_memory)
154 3         4 {
155             $load_message_and_errors_perl=<<"EOF";
156 3 100       10 use $error_package;
157             use $errors_package();
158 1         5 use $message_package;
159             use $messages_package();
160             EOF
161             }
162              
163             my $std_messages=<<"EOF";
164             # Import the standard set of message ids
165             use Rose::HTML::Object::Messages qw(:all);
166 3         6 EOF
167              
168             my $std_errors=<<"EOF";
169             # Import the standard set of error ids
170             use Rose::HTML::Object::Errors qw(:all);
171 3         4 EOF
172              
173             my %code =
174             (
175             $message_package =><<"EOF",
176             sub generic_object_class { '$object_package' }
177             EOF
178              
179             $messages_package =>
180             {
181             filter => sub
182             {
183             s/^(use base.+)/$std_messages$1/m;
184             },
185              
186 3     3   26 code =><<"EOF",
187             ##
188             ## Define your new message ids below
189             ##
190              
191             # Message ids from 0 to 29,999 are reserved for built-in messages. Negative
192             # message ids are reserved for internal use. Please use message ids 30,000
193             # or higher for your messages. Suggested message id ranges and naming
194             # conventions for various message types are shown below.
195              
196             # Field labels
197              
198             #use constant FIELD_LABEL_LOGIN_NAME => 100_000;
199             #use constant FIELD_LABEL_PASSWORD => 100_001;
200             #...
201              
202             # Field error messages
203              
204             #use constant FIELD_ERROR_PASSWORD_TOO_SHORT => 101_000;
205             #use constant FIELD_ERROR_USERNAME_INVALID => 101_001;
206             #...
207              
208             # Generic messages
209              
210             #use constant LOGIN_NO_SUCH_USER => 200_000;
211             #use constant LOGIN_USER_EXISTS_ERROR => 200_001;
212             #...
213              
214             ### %CODE% ###
215              
216             # This line must be below all the "use constant ..." declarations
217             BEGIN { __PACKAGE__->add_messages }
218             EOF
219             },
220              
221             $error_package =><<"EOF",
222             sub generic_object_class { '$object_package' }
223             EOF
224              
225             $errors_package =>
226             {
227             filter => sub
228             {
229             s/^(use base.+)/$std_errors$1/m;
230             },
231              
232 3     3   37 code =><<"EOF",
233             ##
234             ## Define your new error ids below
235 3         46 ##
236              
237             # Error ids from 0 to 29,999 are reserved for built-in errors. Negative
238             # error ids are reserved for internal use. Please use error ids 30,000
239             # or higher for your errors. Suggested error id ranges and naming
240             # conventions for various error types are shown below.
241              
242             # Field errors
243              
244             #use constant FIELD_ERROR_PASSWORD_TOO_SHORT => 101_000;
245             #use constant FIELD_ERROR_USERNAME_INVALID => 101_001;
246             #...
247              
248             # Generic errors
249              
250             #use constant LOGIN_NO_SUCH_USER => 200_000;
251             #use constant LOGIN_USER_EXISTS_ERROR => 200_001;
252             #...
253              
254             ### %CODE% ###
255              
256             # This line must be below all the "use constant ..." declarations
257             BEGIN { __PACKAGE__->add_errors }
258             EOF
259             },
260              
261             $localizer_package =><<"EOF",
262             $load_message_and_errors_perl
263             sub init_message_class { '$message_package' }
264             sub init_messages_class { '$messages_package' }
265             sub init_error_class { '$error_package' }
266             sub init_errors_class { '$errors_package' }
267             EOF
268              
269             $custom_package =><<"EOF",
270             @{[ $in_memory ? "Rose::HTML::Object->import(':customize');" : "use Rose::HTML::Object qw(:customize);" ]}
271             @{[ $in_memory ? '' : "\nuse $localizer_package;\n" ]}
272             __PACKAGE__->default_localizer($localizer_package->new);
273 3 100       14  
274 3 100       53 $object_map_perl
275             EOF
276              
277             $object_package =><<"EOF",
278             sub generic_object_class { '$object_package' }
279             EOF
280             );
281              
282             #
283             # Rose::HTML::Object
284             #
285              
286             require Rose::HTML::Object;
287              
288             foreach my $base_class (qw(Rose::HTML::Object))
289 3         24 {
290             my $package = $rename->($base_class);
291 3         7  
292             push(@packages, $package);
293 3         8  
294             if($args{'in_memory'})
295 3         8 {
296             # Prevent "Base class package "..." is empty" errors from base.pm
297 3 100       10 no strict 'refs';
298             ${"${custom_package}::VERSION"} = $Rose::HTML::Object::VERSION;
299              
300 1     1   7 # XXX" Don't need to do this
  1         1  
  1         608  
301 2         4 #(my $path = $custom_package) =~ s{::}{/}g;
  2         20  
302             #$INC{"$path.pm"} = 123;
303             }
304              
305             $isa{$package} = [ $custom_package, $base_class ];
306              
307             $perl{$package} = $class->subclass_perl(package => $package,
308 3         9 isa => $isa{$package},
309             in_memory => 0,
310             default_code => \%code,
311             code => $args{'code'},
312             code_filter => $args{'code_filter'});
313             }
314              
315 3         22 #
316             # Rose::HTML::Object::Errors
317             # Rose::HTML::Object::Messages
318             # Rose::HTML::Object::Message::Localizer
319             #
320              
321             require Rose::HTML::Object::Errors;
322             require Rose::HTML::Object::Messages;
323             require Rose::HTML::Object::Message::Localizer;
324 3         14  
325 3         16 foreach my $base_class (qw(Rose::HTML::Object::Error
326 3         11 Rose::HTML::Object::Errors
327             Rose::HTML::Object::Messages
328 3         8 Rose::HTML::Object::Message::Localized
329             Rose::HTML::Object::Message::Localizer))
330             {
331             my $package = $rename->($base_class);
332              
333             push(@packages, $package);
334 15         28  
335             $isa{$package} = $base_class;
336 15         25  
337             $perl{$package} = $class->subclass_perl(package => $package,
338 15         25 isa => $isa{$package},
339             in_memory => 0,
340             default_code => \%code,
341             code => $args{'code'},
342             code_filter => $args{'code_filter'});
343             }
344              
345 15         52 #
346             # Rose::HTML::Object::Customized
347             #
348              
349             $perl{$custom_package} =
350             $class->subclass_perl(package => $custom_package,
351             in_memory => $in_memory,
352             default_code => \%code,
353             code => $args{'code'},
354             code_filter => $args{'code_filter'});
355              
356             push(@packages, $custom_package);
357 3         14  
358             #
359 3         10 # All other classes
360             #
361              
362             foreach my $base_class (sort values %$base_object_type, 'Rose::HTML::Form::Field')
363             {
364             if($class_filter)
365 3         77 {
366             local $_ = $base_class;
367 204 100       333 next unless($class_filter->($base_class));
368             }
369 68         102  
370 68 100       105 if($in_memory)
371             {
372             my $error;
373 203 100       614  
374             TRY:
375 135         141 {
376             local $@;
377             eval "require $base_class";
378             $error = $@;
379 135         158 }
  135         144  
380 135         6113  
381 135         461 croak "Could not load '$base_class' - $error" if($error);
382             }
383              
384 135 50       292 my $package = $rename->($base_class);
385              
386             push(@packages, $package);
387 203         395  
388             unless($isa{$package})
389 203         323 {
390             $isa{$package} =
391 203 100       407 [
392             $custom_package,
393             $base_type_object{$package} ? $rename->($base_class) : $base_class,
394             ];
395             }
396 125 50       404  
397             $perl{$package} = $class->subclass_perl(package => $package,
398             isa => $isa{$package},
399             in_memory => $in_memory,
400             code => $args{'code'},
401             code_filter => $args{'code_filter'});
402             }
403              
404 203         670 return wantarray ? (\@packages, \%perl) : \%perl;
405             }
406              
407 3 50       363 {
408             my($class, %args) = @_;
409              
410             my $isa = $args{'isa'} or Carp::confess "Missing 'isa' parameter";
411             $isa = [ $isa ] unless(ref $isa eq 'ARRAY');
412 221     221 0 548  
413             if($args{'in_memory'})
414 221 50       375 {
415 221 100       435 return 'our @ISA = qw(' . join(' ', @$isa) . ");";
416             }
417 221 100       344 else
418             {
419 135         654 return 'use base qw(' . join(' ', @$isa) . ");";
420             }
421             }
422              
423 86         328 our $Perl;
424              
425             {
426             my($class, %args) = @_;
427              
428             my $package = $args{'package'} or Carp::confess "Missing 'package' parameter";
429             my $isa = $args{'isa'};
430             $isa = [ $isa ] unless(ref $isa eq 'ARRAY');
431 224     224 0 813  
432             my $filter = $args{'code_filter'};
433 224 50       427  
434 224         300 my($code, @code, @default_code);
435 224 100       421  
436             foreach my $param (qw(default_code code))
437 224         274 {
438             my $arg = $args{$param} || '';
439 224         279  
440             if(ref $arg eq 'HASH')
441 224         319 {
442             $arg = $arg->{$package};
443 448   100     953 }
444              
445 448 100       677 no warnings 'uninitialized';
446             if(ref $arg eq 'HASH')
447 170         235 {
448             if(my $existing_filter = $filter)
449             {
450 1     1   7 my $new_filter = $arg->{'filter'};
  1         1  
  1         398  
451 448 100       641 $filter = sub
452             {
453 7 100       15 $existing_filter->(@_);
454             $new_filter->(@_);
455 3         5 };
456             }
457             else
458 3     3   9 {
459 3         14 $filter = $arg->{'filter'};
460 3         10 }
461              
462             $arg = $arg->{'code'};
463             }
464 4         7  
465             if(ref $arg eq 'CODE')
466             {
467 7         14 $code = $arg->($package, $isa);
468             }
469             else
470 448 50       620 {
471             $code = $arg;
472 0         0 }
473              
474             if($code)
475             {
476 448         519 for($code)
477             {
478             s/^\n*/\n/;
479 448 100       546 s/\n*\z/\n/;
480             }
481 27         39 }
482             else
483 27         110 {
484 27         1503 $code = '';
485             }
486              
487             if($code)
488             {
489 421         459 if($param eq 'code')
490             {
491             push(@code, $code);
492 448 100       745 }
493             else
494 27 100       44 {
495             push(@default_code, $code);
496 6         13 }
497             }
498             }
499              
500 21         80 foreach my $default_code (@default_code)
501             {
502             if($default_code =~ /\n### %CODE% ###\n/)
503             {
504             $default_code =~ s/\n### %CODE% ###\n/join('', @code)/me;
505 224         319 undef @code; # Attempt to reclaim memory
506             undef $code; # Attempt to reclaim memory
507 21 100       61 }
508             }
509 6         23  
  6         28  
510 6         11 local $Perl;
511 6         11  
512             $Perl=<<"EOF";
513             package $package;
514              
515 224         266 use strict;
516             @{[ $args{'isa'} ? "\n" . $class->isa_perl(%args) . "\n" : '' ]}@{[ join('', @default_code, @code) ]}
517 224         353 1;
518             EOF
519              
520             if($filter)
521 224 100       642 {
  224         613  
522             local *_ = *Perl;
523             $filter->(\$Perl);
524             }
525 224 100       616  
526             return $Perl;
527 78         141 }
528 78         167  
529             1;
530              
531 224         912  
532             =head1 NAME
533              
534             Rose::HTML::Objects - Object-oriented interfaces for HTML.
535              
536             =head1 SYNOPSIS
537              
538             #
539             # HTML form/field abstraction
540             #
541              
542             use Rose::HTML::Form;
543              
544             $form = Rose::HTML::Form->new(action => '/foo',
545             method => 'post');
546              
547             $form->add_fields
548             (
549             name => { type => 'text', size => 20, required => 1 },
550             height => { type => 'text', size => 5, maxlength => 5 },
551             bday => { type => 'datetime' },
552             );
553              
554             $form->params(name => 'John', height => '6ft', bday => '01/24/1984');
555              
556             $form->init_fields();
557              
558             $bday = $form->field('bday')->internal_value; # DateTime object
559              
560             print $bday->strftime('%A'); # Tuesday
561              
562             print $form->field('bday')->html;
563              
564             #
565             # Generic HTML objects
566             #
567              
568             $obj = Rose::HTML::Object->new('p');
569              
570             $obj->push_child('hello'); # text node
571             $obj->add_child(' '); # text node
572              
573             # Add two children: HTML object with text node child
574             $obj->add_children(
575             Rose::HTML::Object->new(element => 'b',
576             children => [ 'world' ]));
577              
578             # Serialize to HTML
579             print $obj->html; # prints: <p>hello <b>world</b></p>
580              
581             =head1 DESCRIPTION
582              
583             L<Rose::HTML::Objects> is a framework for creating a reusable set of HTML widgets as mutable Perl objects that can be serialized to HTML or XHTML for display purposes.
584              
585             The L<Rose::HTML::Object> class may be used directly to represent a generic tag with an explicitly set L<element|Rose::HTML::Object/element> name and arbitrary L<attributes|Rose::HTML::Object/html_attr>. There are also methods for L<parentE<sol>child manipulation|Rose::HTML::Object/HIERARCHY>.
586              
587             Though such generic usage is possible, this family of modules is primarily intended as a framework for creating a resuable set of L<form|Rose::HTML::Form> and L<field|Rose::HTML::Form::Field> widgets. On the Perl side, these objects are treated as abstract entities that can be fed input and will produce output in the form that is most convenient for the programmer (e.g., pass a L<DateTime> object to a date picker field to initialize it, and get a L<DateTime> object back from the field when asking for its value).
588              
589             Fields may be simple (one standard HTML form field per Perl field object) or L<compound|Rose::HTML::Form::Field::Compound> (a field object that serializes to an arbitrary number of HTML tags, but can be addressed as a single logical field internally). Likewise, forms themselves can be L<nested|Rose::HTML::Form/"NESTED FORMS">.
590              
591             Each L<field|Rose::HTML::Form::Field> has its own customizable validation, input filter, output filter, internal value (a plain value or a Perl object, whichever is most convenient), output value (the value shown when the field is redisplayed), label, associated error, and any other metadata deemed necessary. Each field can also be serialized to the L<equivalent|Rose::HTML::Form::Field/html_hidden_fields> set of (X)HTML "hidden" fields.
592              
593             L<Forms|Rose::HTML::Form> are expected to be initialized with and return an object or list of objects that the form represents. For example, a registration form could be initialized with and return a C<UserAccount> object.
594              
595             All labels, errors, and messages used in the bundled form and field widgets are localized in several languages, and you may add your own localized messages and errors using the provided L<localization framework|/LOCALIZATION>.
596              
597             Users are encouraged to L<create their own libraries|/"PRIVATE LIBRARIES"> of reusable form and field widgets for use on their site. The expectation is that the same kind of field appears in multiple places in any large web application (e.g., username fields, password fields, address forms, etc.) Each field encapsulates a set of values (e.g., options in a pop-up menu), labels, validation constraints, filters, and error messages. Similarly, each form encapsulates a set of fields along with any inter-field validation, error messages, and init-with/object-from methods. Nesting forms and fields preserves this delegation of responsibility, with each higher level having access to its children to perform inter-form/field tasks.
598              
599             =head1 PRIVATE LIBRARIES
600              
601             The classes that make up the L<Rose::HTML::Objects> distribution can be used as-is to build forms, fields, and other HTML objects. The provided classes may also be subclassed to change their behavior. When subclassing, however, the interconnected nature of these classes may present some surprises. For example, consider the case of subclassing the L<Rose::HTML::Form::Field::Option> class that represents a single option in a L<select box|Rose::HTML::Form::Field::SelectBox> or L<pop-up menu|Rose::HTML::Form::Field::PopUpMenu>.
602              
603             package My::HTML::Form::Field::Option;
604              
605             use base 'Rose::HTML::Form::Field::Option';
606              
607             sub bark
608             {
609             print "woof!\n";
610             }
611              
612             Now all your options can bark like a dog.
613              
614             $option = My::HTML::Form::Field::Option->new;
615             $option->bark; # woof!
616              
617             This seems great until you make your first select box or pop-up menu, pull out an option object, and ask it to bark.
618              
619             $color =
620             Rose::HTML::Form::Field::PopUpMenu->new(
621             name => 'color',
622             options => [ 'red', 'green', 'blue' ]);
623              
624             $option = $color->option('red');
625              
626             $option->bark; # BOOM: fatal error, no such method!
627              
628             What you'll get is an error message like this: "Can't locate object method 'bark' via package 'Rose::HTML::Form::Field::Option' - ..." That's because C<$option> is a plain old L<Rose::HTML::Form::Field::Option> object and not one of your new C<My::HTML::Form::Field::Option> objects that can C<bark()>.
629              
630             This is an example of the aforementioned interconnected nature of HTML objects: L<pop-up menus|Rose::HTML::Form::Field::PopUpMenu> and L<select boxes|Rose::HTML::Form::Field::SelectBox> contain L<options|Rose::HTML::Form::Field::Option>; L<radio button groups|Rose::HTML::Form::Field::RadioButtonGroup> contain L<radio buttons|Rose::HTML::Form::Field::RadioButton>; L<checkbox groups|Rose::HTML::Form::Field::CheckboxGroup> contain L<checkboxes|Rose::HTML::Form::Field::Checkbox>; L<forms|Rose::HTML::Form> contain all of the above; and so on. What to do?
631              
632             Well, one solution is to convince all the C<Rose::HTML::*> classes that might contain option objects to use your new C<My::HTML::Form::Field::Option> subclass instead of the standard L<Rose::HTML::Form::Field::Option> class. But globally altering the behavior of the standard C<Rose::HTML::*> classes is an extremely bad idea. To understand why, imagine that you did so and then tried to incorporate some other code that also uses C<Rose::HTML::*> classes. That other code certainly doesn't expect the changes you've made. It expects the documented behavior for all the classes it's using, and rightfully so.
633              
634             That's the problem with making class-wide alterations: every piece of code using those classes will see your changes. It's "anti-social behavior" in the context of code sharing and reuse.
635              
636             The solution is to subclass not just the single class whose behavior is to be altered, but rather to create an entirely separate namespace for a full hierarchy of classes within which you can make your changes in isolation. This is called a "private library," and the L<Rose::HTML::Objects> class contains methods for creating one, either dynamically in memory, or on disk in the form of actial C<*.pm> Perl module files.
637              
638             Let's try the example above again, but this time using a private library. We will use the the L<make_private_library|/make_private_library> class method to do this. The reference documentation for this method appears below, but you should get a good idea of its functionality by reading the usage examples here.
639              
640             First, let's create an in-memory private library to contain our changes. The L<make_private_library|/make_private_library> method accepts a hash of class name/code pairs containing customizations to be incorporated into one or more of the classes in the newly created private library. Let's use the C<My::> prefix for our private library. Here's a hash containing just our custom code:
641              
642             %code =
643             (
644             'My::HTML::Form::Field::Option' => <<'EOF',
645             sub bark
646             {
647             print "woof!\n";
648             }
649             EOF
650             );
651              
652             Note that the code is provided as a string, not a code reference. Be sure to use the appropriate quoting mechanism (a single-quoted "here document" in this case) to protect your code from unintended variable interpolation.
653              
654             Next, we'll create the private library in memory:
655              
656             Rose::HTML::Objects->make_private_library(in_memory => 1,
657             prefix => 'My::',
658             code => \%code);
659              
660             Now we have a full hierarchy of C<My::>-prefixed classes, one for each public C<Rose::> class in the L<Rose::HTML::Objects> distribution. Let's try the problematic code from earlier, this time using one of our new classes.
661              
662             $color =
663             My::HTML::Form::Field::PopUpMenu->new(
664             name => 'color',
665             options => [ 'red', 'green', 'blue' ]);
666              
667             $option = $color->option('red');
668              
669             $option->bark; # woof!
670              
671             Success! Of course, this dynamic in-memory class creation is relatively heavyweight. It necessarily has to have all the classes in memory. Creating a private library on disk allows you to load only the classes you need. It also provides an easier means of making your customizations persistent. Editing the actual C<*.pm> files on disk means that your changes can be tracked on a per-file basis by your version control system, and so on. We can still use the C<%code> hash from the in-memory example to "seed" the classes; the L<make_private_library|/make_private_library> method will insert our custom code into the initial C<*.pm> files it generates.
672              
673             To create a private library on disk, we need to provide a path to the directory where the generated files will be placed. The appropriate directory hierarchy will be created below it (e.g., the path to the C<My::HTML::Form> Perl module file will be C<My/HTML/Form.pm>, starting beneath the specified C<modules_dir>). Let's do it:
674              
675             Rose::HTML::Objects->make_private_library(
676             modules_dir => '/home/john/lib',
677             prefix => 'My::',
678             code => \%code);
679              
680             To actually use the generated modules, we must, well, C<use> (or C<require>) them. We must also make sure the specified C<modules_dir> is in our L<@INC|perlvar/@INC> path. Example:
681              
682             use lib '/home/john/lib';
683              
684             use My::HTML::Form::Field::PopUpMenu;
685              
686             $color =
687             My::HTML::Form::Field::PopUpMenu->new(
688             name => 'color',
689             options => [ 'red', 'green', 'blue' ]);
690              
691             $option = $color->option('red');
692              
693             $option->bark; # woof!
694              
695             And it works. Note that if the call to L<make_private_library|/make_private_library> that creates the Perl module files on disk was in the same file as the code above, the C<My::HTML::Form::Field::PopUpMenu> class would have to be C<require>d rather than C<use>d. (All C<use> statements are evaluated at compile time, but the C<My::HTML::Form::Field::PopUpMenu> class is not created until the L<make_private_library|/make_private_library> call is executed, which happens at runtime in this example.)
696              
697             One final example. Suppose you want to add or override a method in I<all> HTML object classes within your private library. To facilitate this, the L<make_private_library|/make_private_library> method will create a mix-in class which will be placed at the front of the inheritence chain (i.e., the first item in the C<@ISA> array) of all generated subclasses. Given a prefix of C<My::> as in the example above, this custom class will be called C<My::HTML::Object::Custom>. It comes pre-populated with an initial set of private-library-wide information such as the L<object_type_class mapping|Rose::HTML::Object/object_type_classes> and the L<default_localizer|Rose::HTML::Object/default_localizer> (all of which will be populated with your C<My::*> subclasses, naturally). Simply add your own methods to this module:
698              
699             package My::HTML::Object::Custom;
700             ...
701             sub chirp
702             {
703             print "tweet!\n";
704             }
705              
706             Now the C<chirp()> method will appear in all other HTML object classes in your private library.
707              
708             # It's everwhere!
709             My::HTML::Link->can('chirp'); # true
710             My::HTML::Form::Field::Date->can('chirp'); # true
711             My::HTML::Form::Field::CheckboxGroup->can('chirp'); # true
712             ...
713              
714             I hope this demonstrates the motivation for and utility of private libraries. Please see the L<make_private_library|/make_private_library> documentation for a more information on this method.
715              
716             =head1 LOCALIZATION
717              
718             There are several components of L<Rose::HTML::Object>'s localization system: the L<message|Rose::HTML::Object::Message::Localized> and L<error|Rose::HTML::Object::Error> objects, the classes that L<manage|Rose::HTML::Object::Messages> L<them|Rose::HTML::Object::Errors>, and of course the L<localizer|Rose::HTML::Object::Message::Localizer> itself. Using a L<private library|/"PRIVATE LIBRARIES">, you get your own private subclasses of all of these. This is extremely important for several reasons, and you should definitely read the L<PRIVATE LIBRARIES|/"PRIVATE LIBRARIES"> section above before continuing.
719              
720             The most important actor in the localization process is, predictably, the L<localizer|Rose::HTML::Object::Message::Localizer>, and the most important aspect of the localizer is the way in which it's accessed.
721              
722             The general approach is that each object that is or contains something that needs to be localized has a C<localizer()> method through which it accesses its L<localizer|Rose::HTML::Object::Message::Localizer> object. These methods check for a local localizer object attribute, and if one is not found, the method looks "up the chain" until it finds one. The chain may include parent objects or class hierarchies. Eventually, the assumption is that a localizer will be found and returned.
723              
724             In the most granular case, this allows each localized object to have its own individual localizer. In the more common (and default) case, there is a single localizer object camped out at some higher point in the chain of lookups, and this localizer serves all objects.
725              
726             The default localizer class, L<Rose::HTML::Object::Message::Localizer>, reads localized message text from the C<__DATA__> sections of the Perl module files that make up the L<Rose::HTML::Objects> distribution. This is done mostly because it's the most convenient way to include the "built-in" localized message text in this CPAN module distribution. (See the L<Rose::HTML::Object::Message::Localizer> documentation for more information.) Localized message text is stored in memory within the localizer object itself.
727              
728             You can change both the source and storage of localized message text by creating your own localizer subclass. The key, of course, is to ensure that your localizer subclass is used instead the default localizer class by all objects. Thankfully, the creation of a L<private library|/"PRIVATE LIBRARIES"> takes care of that, both creating a localizer subclass and ensuring that it is accessible everywhere.
729              
730             Here's a simple example of a customized localizer that overrides just one method, L<get_localized_message_text|Rose::HTML::Object::Message::Localizer/get_localized_message_text>, to add three stars C<***> around the built-in message text.
731              
732             sub get_localized_message_text
733             {
734             my($self) = shift;
735              
736             # Get message text using the default mechanism
737             my $text = $self->SUPER::get_localized_message_text(@_);
738              
739             # Bail out early if no text is defined
740             return $text unless(defined $text);
741              
742             # Surround the text with stars and return it
743             return "*** $text ***";
744             }
745              
746             This is a silly example, obviously, but it does demonstrate how easy it is to alter the default behavior. A more useful example might be to look elsewhere for a message first, then fall back to the default mechanism. This requires actually unpacking the method arguments (as opposed to simply passing them on to the superclass call in the example above), but is otherwise not much more complex:
747              
748             sub get_localized_message_text
749             {
750             my($self) = shift;
751              
752             my %args = @_;
753              
754             my $id = $args{'id'};
755             my $name = $args{'name'};
756             my $locale = $args{'locale'};
757             my $variant = $args{'variant'};
758              
759             # Look elsewhere for this localized text: in a database, pull
760             # from a server, an XML file, whatever.
761             $text = ...
762              
763             return $text if($defined $text); #
764              
765             # Fall back to the default mechanism
766             return $self->SUPER::get_localized_message_text(@_);
767             }
768              
769             By overriding this and othr methods in the L<Rose::HTML::Object::Message::Localizer> class, your localizer subclass could choose to entirely ignore the default mechanism for localized text storage and retrieval.
770              
771             Here's an example of a new L<field|Rose::HTML::Form::Field> subclass that uses localized messages and errors. It will use the default localized text mechanism to the sake of simplicity (i.e., text stored in C<__DATA__> sections of Perl modules). It's a "nickname" field intended to be used as part of a localized form that asks for user information. For the sake of demonstrating validation, let's say we've decided that nicknames may not contain space characters.
772              
773             The first step is to define our L<message|Rose::HTML::Object::Messages> and L<error|Rose::HTML::Object::Errors> ids. These should be added to the generated C<My::HTML::Object::Messages> and C<My::HTML::Object::Errors> classes, respectively. You can do this during private library generation by adding to the C<code> hash passed to the L<make_private_library|/make_private_library> call, or by editing the generated files on disk. (The relevant sections are indicated with comments that L<make_private_library|/make_private_library> will place in the generated C<*.pm> files.) First, the message ids:
774              
775             package My::HTML::Object::Messages;
776             ...
777             # Field labels
778             use constant FIELD_LABEL_NICKNAME => 100_000;
779             ...
780              
781             # Field errors
782             use constant FIELD_ERROR_BAD_NICKNAME => 101_000;
783             ...
784              
785             Now the error ids. Note that the error and message id numbers for each error message (just C<FIELD_ERROR_BAD_NICKNAME> in this case) should be the same in order to take advantage of the default behavior of the L<message_for_error_id|Rose::HTML::Object/message_for_error_id> method.
786              
787             package My::HTML::Object::Errors;
788             ...
789             # Field errors
790             use constant FIELD_ERROR_BAD_NICKNAME => 101_000;
791             ...
792              
793             Finally, the nickname field class itself. Note that it inherits from and uses classes from our private library, not from C<Rose::>.
794              
795             package My::HTML::Form::Field::Nickname;
796              
797             # Import message and error ids. Note that just the error id for
798             # FIELD_LABEL_NICKNAME is imported, not the message id. That's
799             # because we're using it as an error id below, passing it as an
800             # argument to the error_id() method.
801             use My::HTML::Object::Messages qw(FIELD_LABEL_NICKNAME);
802             use My::HTML::Object::Errors qw(FIELD_ERROR_BAD_NICKNAME);
803              
804             # Inherit from our private library version of a text field
805             use base qw(My::HTML::Form::Field::Text);
806              
807             sub init
808             {
809             my($self) = shift;
810              
811             # Set the default label before calling through to the superclass
812             $self->label_id(FIELD_LABEL_NICKNAME);
813              
814             $self->SUPER::init(@_);
815             }
816              
817             sub validate
818             {
819             my($self) = shift;
820              
821             # Do the default validation first
822             my $ret = $self->SUPER::validate(@_);
823             return $ret unless($ret);
824              
825             #
826             # Do our custom validation
827             #
828              
829             my $nick = $self->internal_value;
830              
831             # Nicknames may not contain space characters
832             if($nick =~ /\s/)
833             {
834             # Remember, the error_label falls back to the label if no
835             # explicit error_label is set. (And we set a default
836             # label_id in init() above.)
837             my $label = $self->error_label;
838              
839             # Pass the (also localized!) label as a parameter to this error.
840             # See the actual localized text in the __DATA__ section below.
841             $self->error_id(FIELD_ERROR_BAD_NICKNAME, { label => $label });
842             return 0;
843             }
844              
845             return 1;
846             }
847              
848             # Standard technique for conditionally loading all localized message
849             # text from the __DATA__ section below using the default localizer.
850             # (Alternately, you could remove the conditional and always load all
851             # the localized message text when this module is loaded.)
852             if(__PACKAGE__->localizer->auto_load_messages)
853             {
854             __PACKAGE__->localizer->load_all_messages;
855             }
856              
857             1;
858              
859             __DATA__
860              
861             [% LOCALE en %]
862              
863             FIELD_LABEL_NICKNAME = "Nickname"
864             FIELD_ERROR_BAD_NICKNAME = "[label] may not contain space characters."
865              
866             [% LOCALE fr %]
867              
868             FIELD_LABEL_NICKNAME = "Surnom"
869             FIELD_ERROR_BAD_NICKNAME = "[label] mai de ne pas contenir des espaces."
870              
871             (Sorry for the bad French translations. Corrections welcome!)
872              
873             Finally, let's map the new nickname field class to its own field type name:
874              
875             package My::HTML::Form;
876             ...
877             # Add new field type class mappings
878             __PACKAGE__->add_field_type_classes
879             (
880             nickname => 'My::HTML::Form::Field::Nickname',
881             ...
882             );
883              
884             Here it is in action:
885              
886             $field = My::HTML::Form::Field::Nickname->new(name => 'nick');
887             $field->input_value('bad nickname');
888             $field->validate;
889              
890             print $field->error; # "Nickname may not contain space characters."
891              
892             $field->locale('fr');
893              
894             print $field->error; # "Surnom mai de ne pas contenir des espaces."
895              
896             Of course, you'll rarely instantiate a field in isolation. It will usually be part of a L<form|Rose::HTML::Form>. Similarly, you will rarely set the L<locale|Rose::HTML::Object/locale> of a field directly. Instead, you will set the locale of the entire form and let the fields use that locale, accessed through the delegation chain searched when the L<locale|Rose::HTML::Object/locale> method is called on a field object. Example:
897              
898             $form = My::HTML::Form->new;
899             $form->add_fields(nick => { type => 'nickname' });
900              
901             $form->params(nick => 'bad nickname');
902             $form->validate;
903              
904             # "Nickname may not contain space characters."
905             print $form->field('nick')->error;
906              
907             $form->locale('fr');
908              
909             # "Surnom mai de ne pas contenir des espaces."
910             print $form->field('nick')->error;
911              
912             Or you could set the locale on the localizer itself for a similar effect.
913              
914             Also note the use of the label within the "bad nickname" error message. In general, incorporating (independently set, remember) labels into messages like this tends to lead to translation issues. (Is the label masculine? Feminine? Singular? Dual? Plural? Etc.) I've done so here to demonstrate that one localized message can be incorporated into another localized message, with both dynamically matching their locales based on the locale set higher up in the object hierarchy.
915              
916             =head1 CLASS METHODS
917              
918             =over 4
919              
920             =item B<make_private_library PARAMS>
921              
922             Create a comprehensive collection of C<Rose::HTML::*> subclasses, either in memory or as C<*.pm> files on disk, in order to provide a convenient and isolated location for your customizations. Please read the L<private libraries|/"PRIVATE LIBRARIES"> section above for more information.
923              
924             Valid PARAMS name/value pairs are:
925              
926             =over 4
927              
928             =item B<class_filter CODEREF>
929              
930             A reference to a subroutine that takes a C<Rose::HTML::*> class name as its argument and returns true if a subclass should be created for this class, false otherwise. The class name will also be available in C<$_>. If this parameter is omitted, all classes are subclassed.
931              
932             =item B<code HASHREF>
933              
934             A reference to a hash containing code to be added to subclasses. The keys of the hash are the subclass class names (i.e., the names I<after> the application of the C<rename> code or the C<trim_prefix>/C<prefix> processing).
935              
936             The value for each key may be either a string containing Perl code or a reference to a hash containing a C<code> key whose value is a string containing Perl code and a C<filter> key whose value is a reference to a subroutine used to filter the code.
937              
938             The C<filter> subroutine will be passed a reference to a scalar containing the full Perl code for a subclass and is expected to modify it directly. The Perl code will also be available in C<$_>. Example:
939              
940             code =>
941             {
942             'My::HTML::Object' => <<'EOF', # code string argument
943             sub my_method
944             {
945             # ...
946             }
947             EOF
948             'My::HTML::Form' =>
949             {
950             filter => sub { s/__FOO__//g },
951             code => <<'EOF',
952             sub my_other_method__FOO__
953             {
954             # ...
955             }
956             EOF
957             },
958             },
959              
960             This will create C<my_method()> in the C<My::HTML::Object> class and, with the C<__FOO__> removed, C<my_other_method()> will be created in the C<My::HTML::Form> class.
961              
962             Note that the use of this parameter is optional. You can always add your code to the Perl module files after they've been generated, or add your code directly into memory after the classes have been created C<in_memory>.
963              
964             =item B<code_filter CODEREF>
965              
966             A reference to a subroutine used to filter the Perl code for all generated subclasses. This filter will run before any subclass-specific C<filter> (see the C<code> parameter above for an explanation). This subroutine will be passed a reference to a scalar containing the Perl code and is expected to modify it directly. The Perl code will also be available in C<$_>.
967              
968             =item B<debug INT>
969              
970             Print debugging output to STDERR if INT is creater than 0. Higher numbers produce more output. The maximum useful value is 3.
971              
972             =item B<in_memory BOOL>
973              
974             If true, the classes that make up the private library will be compiled in memory. If false (the default), then a C<modules_dir> must be provided.
975              
976             =item B<modules_dir PATH>
977              
978             The path to the directory under which all C<*.pm> Perl module files will be created. The modules will be created in the expected tree structure. For example, the C<My::HTML::Object> class will be in the file C<My/HTML/Object.pm> beneath the C<modules_dir> PATH. This parameter is ignored if the C<in_memory> parameter is passed.
979              
980             =item B<overwrite BOOL>
981              
982             If true, overwrite any existing files that are located at the same paths as files created by this method call. This option is not applicable if the C<in_memory> parameter is passed.
983              
984             =item B<prefix STRING>
985              
986             The class name prefix with which to replace the C<trim_prefix> in all subclass class names. For example, a C<prefix> value of C<My::> combined with the (default) C<trim_prefix> of C<Rose::> would take a class named C<Rose::HTML::Whatever> and produce a subclass named C<My::HTML::Whatever>. You must pass this parameter or the C<rename> parameter.
987              
988             =item B<rename CODEREF>
989              
990             A reference to a subroutine that takes a C<Rose::HTML::*> class name as its argument and returns an appropriate subclass name. The name argument is also available in the C<$_> variable, enabling code like this:
991              
992             rename => sub { s/^Rose::/Foo::/ },
993              
994             You must pass this parameter or the C<prefix> parameter.
995              
996             =item B<trim_prefix STRING>
997              
998             The prefix string to be removed from each C<Rose::HTML::*> class name. This parameter is only relevant when the C<prefix> parameter is passed (and the C<rename> parameter is not). Defaults to C<Rose::> if this parameter is not passed.
999              
1000             =back
1001              
1002             =back
1003              
1004             =head1 DEVELOPMENT POLICY
1005              
1006             The L<Rose development policy|Rose/"DEVELOPMENT POLICY"> applies to this, and all C<Rose::*> modules. Please install L<Rose> from CPAN and then run C<perldoc Rose> for more information.
1007              
1008             =head1 SUPPORT
1009              
1010             Any L<Rose::HTML::Objects> questions or problems can be posted to the L<Rose::HTML::Objects> mailing list. To subscribe to the list or search the archives, go here:
1011              
1012             L<http://groups.google.com/group/rose-html-objects>
1013              
1014             Although the mailing list is the preferred support mechanism, you can also email the author (see below) or file bugs using the CPAN bug tracking system:
1015              
1016             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Rose-HTML-Objects>
1017              
1018             There's also a wiki and other resources linked from the Rose project home page:
1019              
1020             L<http://rosecode.org>
1021              
1022             =head1 CONTRIBUTORS
1023              
1024             Tom Heady, Cees Hek, Kevin McGrath, Denis Moskowitz, RJBS, Jacques Supcik, Uwe Voelker
1025              
1026             =head1 AUTHOR
1027              
1028             John C. Siracusa (siracusa@gmail.com)
1029              
1030             =head1 LICENSE
1031              
1032             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.