File Coverage

blib/lib/Rose/DB/Object/Metadata/MethodMaker.pm
Criterion Covered Total %
statement 132 165 80.0
branch 49 86 56.9
condition 24 60 40.0
subroutine 24 29 82.7
pod 0 19 0.0
total 229 359 63.7


line stmt bran cond sub pod time code
1             package Rose::DB::Object::Metadata::MethodMaker;
2              
3 61     61   429 use strict;
  61         133  
  61         1811  
4              
5 61     61   418 use Carp();
  61         168  
  61         960  
6              
7 61     61   27352 use Clone();
  61         157943  
  61         1659  
8 61     61   461 use Rose::Object::MakeMethods::Generic;
  61         149  
  61         655  
9              
10 61     61   27875 use Rose::DB::Object::Metadata::Object;
  61         172  
  61         4078  
11             our @ISA = qw(Rose::DB::Object::Metadata::Object);
12              
13             our $VERSION = '0.769';
14              
15             #
16             # Class data
17             #
18              
19             use Rose::Class::MakeMethods::Set
20             (
21 61         566 inherited_set =>
22             [
23             'common_method_maker_argument_name',
24             'default_auto_method_type',
25             ],
26 61     61   466 );
  61         157  
27              
28             #
29             # Object data
30             #
31              
32             Rose::Object::MakeMethods::Generic->make_methods
33             (
34             { preserve_existing => 1 },
35             scalar =>
36             [
37             'name',
38             __PACKAGE__->common_method_maker_argument_names,
39             ],
40              
41             array =>
42             [
43             'auto_method_types' => { interface => 'get_set_init' },
44             'add_auto_method_types' =>
45             {
46             interface => 'push',
47             init_method => 'init_auto_method_types',
48             hash_key => 'auto_method_types' ,
49             },
50             ],
51             );
52              
53             *method_types = \&auto_method_types;
54             *add_method_types = \&add_auto_method_types;
55              
56             #
57             # Class methods
58             #
59              
60             our %Method_Maker_Info;
61              
62             OVERRIDE:
63             {
64             my $orig_add_method = \&add_common_method_maker_argument_names;
65              
66 61     61   48150 no warnings 'redefine';
  61         174  
  61         24505  
67             *add_common_method_maker_argument_names = sub
68             {
69 319     319   979 my($class) = shift;
70              
71 319 50 33     2252 if(@_ && $Method_Maker_Info{$class})
72             {
73 0         0 foreach my $type (keys %{$Method_Maker_Info{$class}})
  0         0  
74             {
75 0         0 push(@{$Method_Maker_Info{$class}{$type}{'args'}}, @_);
  0         0  
76             }
77             }
78              
79 319         1247 $orig_add_method->($class, @_);
80             };
81              
82             my $orig_delete_method = \&delete_common_method_maker_argument_names;
83              
84             *delete_common_method_maker_argument_names = sub
85             {
86 1     1   3 my($class) = shift;
87              
88 1 50 33     10 if(@_ && $Method_Maker_Info{$class})
89             {
90 0         0 foreach my $type (keys %{$Method_Maker_Info{$class}})
  0         0  
91             {
92 0         0 delete @{$Method_Maker_Info{$class}{$type}{'args'}}{@_};
  0         0  
93             }
94             }
95              
96 1         10 $orig_delete_method->($class, @_);
97             };
98             }
99              
100 284     284 0 2896 sub init_auto_method_types { shift->default_auto_method_types }
101              
102             # This is basically a Rose::Class::MakeMethods::Set::inherited_set
103             # but it's keyed. I'm only implementing a one-time superclass copy
104             # here, instead of the more involved "inherited_set" version where
105             # values can be permanently deleted or re-inherited.
106             sub init_method_maker_info
107             {
108 1466     1466 0 2523 my($class) = shift;
109              
110 1466         2648 my $info = $Method_Maker_Info{$class};
111              
112 1466 100 66     5068 unless($info && %$info)
113             {
114 64         138 my @parents = ($class);
115              
116 64         151 while(my $parent = shift(@parents))
117             {
118 61     61   522 no strict 'refs';
  61         161  
  61         116268  
119 275         2890 foreach my $subclass (@{$parent . '::ISA'})
  275         965  
120             {
121 211         384 push(@parents, $subclass);
122              
123 211 100       1034 next unless($subclass->can('init_method_maker_info'));
124              
125 83         234 my $subclass_info = $subclass->init_method_maker_info;
126              
127 83   50     355 $info ||= $Method_Maker_Info{$class} ||= {};
      66        
128              
129 83         274 foreach my $type ($subclass->available_method_types)
130             {
131 152 50       8580 next unless($subclass_info->{$type});
132              
133 152         266 foreach my $attr (qw(class type interface))
134             {
135             next if(!$subclass_info->{$type}{$attr} ||
136 456 100 100     1550 defined $info->{$type}{$attr});
137              
138 194         880 $info->{$type}{$attr} = Clone::clone($subclass_info->{$type}{$attr});
139             }
140              
141             # Args come from an already-inherited set
142 152         462 $info->{$type}{'args'} = [ $class->common_method_maker_argument_names ];
143             }
144             }
145             }
146             }
147              
148 1466         2481 return $info;
149             }
150              
151             sub method_maker_info
152             {
153 186     186 0 592 my($class) = shift;
154              
155 186 50       791 $class = ref $class if(ref $class);
156              
157 186         683 while(@_)
158             {
159 817         1411 my $type = shift;
160 817         1226 my $info = shift;
161              
162 817 50 33     4369 Carp::confess "Method maker info must be passed in type/hashref pairs"
      33        
163             unless(defined $type && ref $info && ref $info eq 'HASH');
164              
165 817   50     3356 my $mm_info = $Method_Maker_Info{$class}{$type} ||= {};
166              
167 817         2709 while(my($key, $value) = each(%$info))
168             {
169 2207         6939 $mm_info->{$key} = $value;
170             }
171             }
172              
173 186         1384 $class->init_method_maker_info;
174 186         506 return $Method_Maker_Info{$class};
175             }
176              
177             sub add_method_maker_argument_names
178             {
179 0     0 0 0 my($class) = shift;
180              
181 0 0       0 $class = ref $class if(ref $class);
182              
183 0         0 while(@_)
184             {
185 0         0 my $type = shift;
186 0         0 my $new_names = shift;
187              
188 0 0 0     0 Carp::confess "Method maker argument names must be passed in type/arrayref pairs"
      0        
189             unless(defined $type && ref $new_names && ref $new_names eq 'ARRAY');
190              
191 0         0 my $names = $class->method_maker_argument_names($type);
192              
193 0         0 push(@$names, @$new_names);
194             }
195              
196 0         0 return;
197             }
198              
199             sub method_maker_argument_names
200             {
201 371     371 0 703 my($class, $type) = (shift, shift);
202              
203 371 50       710 Carp::confess "Missing required type argument" unless(defined $type);
204              
205 371 50       727 $class = ref $class if(ref $class);
206 371         898 $class->init_method_maker_info;
207              
208 371   50     953 my $mm_info = $Method_Maker_Info{$class}{$type} ||= {};
209              
210 371 50       785 if(@_)
211             {
212 0 0 0     0 if(@_ == 1 && ref $_[0] && ref $_[0] eq 'ARRAY')
      0        
213             {
214 0         0 $mm_info->{'args'} = $_[0];
215             }
216             else
217             {
218 0         0 $mm_info->{'args'} = [ @_ ];
219             }
220             }
221              
222 371 100       933 unless(defined $mm_info->{'args'})
223             {
224 15   50     84 $mm_info->{'args'} = $class->common_method_maker_argument_names || [];
225             }
226              
227 371         1835 return wantarray ? @{$mm_info->{'args'}} :
228 371 50       1977 $mm_info->{'args'};
229             }
230              
231             sub method_maker_class
232             {
233 386     386 0 833 my($class, $type) = (shift, shift);
234              
235 386 50       814 Carp::confess "Missing required type argument" unless(defined $type);
236              
237 386 100       1027 $class = ref $class if(ref $class);
238              
239 386         1277 $class->init_method_maker_info;
240              
241 386 100       889 if(@_)
242             {
243 15         45 return $Method_Maker_Info{$class}{$type}{'class'} = shift;
244             }
245              
246 371         1134 return $Method_Maker_Info{$class}{$type}{'class'};
247             }
248              
249             sub method_maker_type
250             {
251 440     440 0 954 my($class, $type) = (shift, shift);
252              
253 440 50       919 Carp::confess "Missing required type argument" unless(defined $type);
254              
255 440 100       1384 $class = ref $class if(ref $class);
256 440         1182 $class->init_method_maker_info;
257              
258 440 100       934 if(@_)
259             {
260 69         186 return $Method_Maker_Info{$class}{$type}{'type'} = shift;
261             }
262              
263 371         1010 return $Method_Maker_Info{$class}{$type}{'type'};
264             }
265              
266             sub available_method_types
267             {
268 106     106 0 191 my($class) = shift;
269 106 50       228 $class = ref $class if(ref $class);
270              
271 106 100 100     280 if($Method_Maker_Info{$class} && %{$Method_Maker_Info{$class}})
  51         164  
272             {
273 50   50     82 return sort keys %{$Method_Maker_Info{$class} ||= {}};
  50         336  
274             }
275              
276 56         152 return;
277             }
278              
279             # sub default_method_name
280             # {
281             # my($class, $type) = (shift, shift);
282             #
283             # Carp::confess "Missing required type argument" unless(defined $type);
284             #
285             # $class = ref $class if(ref $class);
286             #
287             # if(@_)
288             # {
289             # return $Method_Maker_Info{$class}{$type}{'name'} = shift;
290             # }
291             #
292             # return $Method_Maker_Info{$class}{$type}{'name'} ||=
293             # $class->build_method_name_for_type($type);
294             # }
295              
296             #
297             # Object methods
298             #
299              
300 148     148 0 483 sub hash_key { shift->name }
301              
302             sub methods
303             {
304 7     7 0 193 my($self) = shift;
305              
306 7 50       16 my %args = (@_ == 1) ? %{$_[0]} : @_;
  7         71  
307              
308 7         98 $self->add_auto_method_types(keys %args);
309              
310 7         187 while(my($type, $name) = each(%args))
311             {
312 21 50       51 $self->method_name($type => $name) if(defined $name);
313             }
314              
315 7         23 return;
316             }
317              
318             sub method_name
319             {
320 2553     2553 0 5054 my($self, $type) = (shift, shift);
321              
322 2553 50       4859 Carp::confess "Missing required type argument" unless(defined $type);
323              
324 2553 100       4741 if(@_)
325             {
326 424         1593 return $self->{'method_name'}{$type} = shift;
327             }
328              
329 2129         8945 return $self->{'method_name'}{$type};
330             }
331              
332             sub method_uses_formatted_key
333             {
334 286     286 0 567 my($self, $type) = @_;
335 286         586 return 0;
336             }
337              
338             sub method_should_set
339             {
340 0     0 0 0 my($self, $type, $args) = @_;
341              
342 0 0       0 return 1 if($type eq 'set');
343 0 0       0 return 0 if($type eq 'get');
344              
345             # $args is a reference to the method args *including* the invocant
346 0 0       0 return @$args > 1 ? 1 : 0;
347             }
348              
349 0     0 0 0 sub build_method_name_for_type { Carp::confess "Override in subclass" }
350              
351             sub defined_method_types
352             {
353 0     0 0 0 my($self) = shift;
354              
355 0   0     0 my @types = sort keys %{$self->{'method_name'} ||= {}};
  0         0  
356 0 0       0 return wantarray ? @types : \@types;
357             }
358              
359             sub method_maker_arguments
360             {
361 371     371 0 722 my($self, $type) = @_;
362              
363 371         622 my $class = ref $self;
364              
365 371 50       738 Carp::confess "Missing required type argument" unless(defined $type);
366              
367 371         906 my %opts = map { $_ => scalar $self->$_() } grep { defined scalar $self->$_() }
  2221         13683  
  4612         25127  
368             $class->method_maker_argument_names($type);
369              
370             # This is done by method_maker_argument_names() above
371             #$class->init_method_maker_info;
372              
373 371   50     1891 my $mm_info = $Method_Maker_Info{$class}{$type} ||= {};
374              
375 371 100       1056 $opts{'interface'} = $mm_info->{'interface'} if(exists $mm_info->{'interface'});
376              
377 371 100       1710 return wantarray ? %opts : \%opts;
378             }
379              
380             sub make_methods
381             {
382 271     271 0 740 my($self, %args) = @_;
383              
384 271   50     1158 my $options = $args{'options'} || {};
385              
386 271 100       676 if(exists $args{'preserve_existing'})
387             {
388 44         128 $options->{'preserve_existing'} = $args{'preserve_existing'};
389             }
390              
391 271 50       580 if(exists $args{'replace_existing'})
392             {
393 0 0       0 if($options->{'preserve_existing'})
394             {
395 0         0 Carp::croak "Cannot specify true values for both the ",
396             "'replace_existing' and 'preserve_existing' ",
397             "options";
398             }
399              
400 0         0 $options->{'override_existing'} = $args{'replace_existing'};
401             }
402              
403 271   33     1350 $options->{'target_class'} ||= $args{'target_class'} || (caller)[0];
      33        
404              
405 271   50     1013 my $types = $args{'types'} || [ $self->auto_method_types ];
406              
407 271         3485 foreach my $type (@$types)
408             {
409 371 50       994 my $method_maker_class = $self->method_maker_class($type)
410             or Carp::croak "No method maker class defined for method type '$type'";
411              
412 371 50       913 my $method_maker_type = $self->method_maker_type($type)
413             or Carp::croak "No method maker type defined for method type '$type'";
414              
415 371 50       829 my $method_name = $self->method_name($type)
416             or Carp::croak "No method name defined for method type '$type'";
417              
418 371 50       2206 if(Rose::DB::Object->can($method_name))
419             {
420 0         0 Carp::croak "Cannot create method '$method_name' in class ",
421             "$options->{'target_class'} - Rose::DB::Object defines a ",
422             "method with the same name";
423             }
424              
425             $method_maker_class->make_methods(
426 371         1150 $options,
427             $method_maker_type =>
428             [
429             $method_name => { $self->method_maker_arguments($type) }
430             ]);
431              
432 370         15447 $self->made_method_type($type => $method_name);
433              
434 370 100       1543 if($self->can('method_code'))
435             {
436 297         902 $self->method_code($type => undef);
437             }
438             }
439              
440 270         945 return;
441             }
442              
443       73 0   sub made_method_type { }
444       0 0   sub made_method_types { }
445              
446             1;