File Coverage

blib/lib/Rose/Class/MakeMethods/Generic.pm
Criterion Covered Total %
statement 374 411 91.0
branch 205 320 64.0
condition 71 124 57.2
subroutine 55 57 96.4
pod 6 6 100.0
total 711 918 77.4


line stmt bran cond sub pod time code
1             package Rose::Class::MakeMethods::Generic;
2              
3 3     8   20 use strict;
  3         5  
  3         117  
4              
5 3     3   15 use Carp();
  3         6  
  3         108  
6              
7             our $VERSION = '0.854';
8              
9 3     3   821 use Rose::Object::MakeMethods;
  3         7  
  3         18  
10             our @ISA = qw(Rose::Object::MakeMethods);
11              
12             our %Scalar;
13             # (
14             # class_name =>
15             # {
16             # some_attr_name1 => ...,
17             # some_attr_name2 => ...,
18             # ...
19             # },
20             # ...
21             # );
22              
23             sub scalar
24             {
25 7     7 1 19 my($class, $name, $args, $options) = @_;
26              
27 7         11 my %methods;
28              
29 7   100     37 my $interface = $args->{'interface'} || 'get_set';
30              
31 7 100       25 if($interface eq 'get_set')
    50          
32             {
33             $methods{$name} = sub
34             {
35 13 100   13   25512 return $Scalar{$_[0]}{$name} = $_[1] if(@_ > 1);
36 8         49 return $Scalar{$_[0]}{$name};
37 5         48 };
38             }
39             elsif($interface eq 'get_set_init')
40             {
41 2   33     12 my $init_method = $args->{'init_method'} || "init_$name";
42              
43             $methods{$name} = sub
44             {
45 12 100   12   2935 return $Scalar{$_[0]}{$name} = $_[1] if(@_ > 1);
46 8 100       67 return defined $Scalar{$_[0]}{$name} ?
47             $Scalar{$_[0]}{$name} : ($Scalar{$_[0]}{$name} = $_[0]->$init_method())
48 2         21 };
49             }
50              
51 7         42 return \%methods;
52             }
53              
54             our %Inheritable_Scalar;
55             # (
56             # class_name =>
57             # {
58             # some_attr_name1 => ...,
59             # some_attr_name2 => ...,
60             # ...
61             # },
62             # ...
63             # );
64              
65             sub inheritable_scalar
66             {
67 2     2 1 7 my($class, $name, $args, $options) = @_;
68              
69 2         4 my %methods;
70              
71 2   50     19 my $interface = $args->{'interface'} || 'get_set';
72              
73 2 50       20 if($interface eq 'get_set')
74             {
75             $methods{$name} = sub
76             {
77 34 50   34   180 my($class) = ref($_[0]) ? ref(shift) : shift;
78              
79 34 100       109 if(@_)
80             {
81 6         44 return $Inheritable_Scalar{$class}{$name} = shift;
82             }
83              
84 28 100       134 return $Inheritable_Scalar{$class}{$name}
85             if(exists $Inheritable_Scalar{$class}{$name});
86              
87 16         33 my @parents = ($class);
88              
89 16         47 while(my $parent = shift(@parents))
90             {
91 3     3   17 no strict 'refs';
  3         6  
  3         1166  
92 26         33 foreach my $subclass (@{$parent . '::ISA'})
  26         95  
93             {
94 26         49 push(@parents, $subclass);
95              
96 26 100       419 if(exists $Inheritable_Scalar{$subclass}{$name})
97             {
98 16         95 return $Inheritable_Scalar{$subclass}{$name}
99             }
100             }
101             }
102              
103 0         0 return undef;
104 2         16 };
105             }
106 0         0 else { Carp::croak "Unknown interface: $interface" }
107              
108 2         9 return \%methods;
109             }
110              
111             our %Inheritable_Boolean;
112              
113             sub inheritable_boolean
114             {
115 4     4 1 12 my($class, $name, $args, $options) = @_;
116              
117 4         7 my %methods;
118              
119 4   50     44 my $interface = $args->{'interface'} || 'get_set';
120              
121 4 50       16 if($interface eq 'get_set')
122             {
123             $methods{$name} = sub
124             {
125 82 50   82   254 my($class) = ref($_[0]) ? ref(shift) : shift;
126              
127 82 100       208 if(@_)
128             {
129 18 100       143 return $Inheritable_Boolean{$class}{$name} = $_[0] ? 1 : 0;
130             }
131              
132 64 100       303 return $Inheritable_Boolean{$class}{$name}
133             if(exists $Inheritable_Boolean{$class}{$name});
134              
135 34         67 my @parents = ($class);
136              
137 34         135 while(my $parent = shift(@parents))
138             {
139 3     3   17 no strict 'refs';
  3         5  
  3         6157  
140 54         61 foreach my $subclass (@{$parent . '::ISA'})
  54         213  
141             {
142 48         92 push(@parents, $subclass);
143              
144 48 100       202 if(exists $Inheritable_Boolean{$subclass}{$name})
145             {
146 28         315 return $Inheritable_Boolean{$subclass}{$name}
147             }
148             }
149             }
150              
151 6         29 return undef;
152 4         33 };
153             }
154 0         0 else { Carp::croak "Unknown interface: $interface" }
155              
156 4         16 return \%methods;
157             }
158              
159             our %Hash;
160             # (
161             # class_name =>
162             # {
163             # key =>
164             # {
165             # some_attr_name1 => ...,
166             # some_attr_name2 => ...,
167             # ...
168             # },
169             # ...
170             # },
171             # ...
172             # );
173              
174             sub hash
175             {
176 14     14 1 25 my($class, $name, $args) = @_;
177              
178 14         18 my %methods;
179              
180 14   66     53 my $key = $args->{'hash_key'} || $name;
181 14   100     37 my $interface = $args->{'interface'} || 'get_set';
182              
183 14 100       96 if($interface eq 'get_set_all')
    100          
    50          
    100          
    100          
    100          
    100          
    50          
184             {
185             $methods{$name} = sub
186             {
187 10 50   10   1875 my($class) = ref $_[0] ? ref shift : shift;
188              
189             # If called with no arguments, return hash contents
190 10 50       57 return wantarray ? %{$Hash{$class}{$key} || {}} : $Hash{$class}{$key} unless(@_);
  2 100       63  
    100          
191              
192             # Set hash to arguments
193 4 100 66     35 if(@_ == 1 && ref $_[0] eq 'HASH')
194             {
195 2         9 $Hash{$class}{$key} = $_[0];
196             }
197             else
198             {
199             # Push on new values and return complete set
200 2 50       10 Carp::croak "Odd number of items in assigment to $name" if(@_ % 2);
201              
202 2         9 while(@_)
203             {
204 4         8 local $_ = shift;
205 4         22 $Hash{$class}{$key}{$_} = shift;
206             }
207             }
208              
209 4 0       21 return wantarray ? %{$Hash{$class}{$key} || {}} : $Hash{$class}{$key};
  0 50       0  
210             }
211 2         30 }
212             elsif($interface eq 'clear')
213             {
214             $methods{$name} = sub
215             {
216 0     0   0 $Hash{$_[0]}{$key} = {}
217             }
218 2         10 }
219             elsif($interface eq 'reset')
220             {
221             $methods{$name} = sub
222             {
223 0     0   0 $Hash{$_[0]}{$key} = undef
224             }
225 0         0 }
226             elsif($interface eq 'delete')
227             {
228             $methods{($interface eq 'manip' ? 'delete_' : '') . $name} = sub
229             {
230 2 50   2   13 Carp::croak "Missing key(s) to delete" unless(@_ > 1);
231 2         8 delete @{$Hash{$_[0]}{$key}}{@_[1 .. $#_]};
  2         11  
232             }
233 2 50       18 }
234             elsif($interface eq 'exists')
235             {
236             $methods{$name . ($interface eq 'manip' ? '_exists' : '')} = sub
237             {
238 2 50   2   23 Carp::croak "Missing key argument" unless(@_ == 2);
239 2 50       23 defined $Hash{$_[0]}{$key} ? exists $Hash{$_[0]}{$key}{$_[1]} : undef;
240             }
241 2 50       14 }
242             elsif($interface =~ /^(?:keys|names)$/)
243             {
244             $methods{$name} = sub
245             {
246 4         43 wantarray ? (defined $Hash{$_[0]}{$key} ? keys %{$Hash{$_[0]}{$key}} : ()) :
  0         0  
247 4 50   4   26 (defined $Hash{$_[0]}{$key} ? [ keys %{$Hash{$_[0]}{$key}} ] : []);
    0          
    50          
248             }
249 2         18 }
250             elsif($interface eq 'values')
251             {
252             $methods{$name} = sub
253             {
254 4         52 wantarray ? (defined $Hash{$_[0]}{$key} ? values %{$Hash{$_[0]}{$key}} : ()) :
  0         0  
255 4 50   4   102 (defined $Hash{$_[0]}{$key} ? [ values %{$Hash{$_[0]}{$key}} ] : []);
    0          
    50          
256             }
257 2         9 }
258             elsif($interface eq 'get_set')
259             {
260             $methods{$name} = sub
261             {
262 4 50   4   17 my($class) = ref $_[0] ? ref shift : shift;
263              
264             # If called with no arguments, return hash contents
265 4 50       17 unless(@_)
266             {
267 0 0       0 return wantarray ? (defined $Hash{$class}{$key} ? %{$Hash{$class}{$key}} : ()) : $Hash{$class}{$key}
  0 0       0  
268             }
269              
270             # If called with a hash ref, set value
271 4 50 66     29 if(@_ == 1 && ref $_[0] eq 'HASH')
272             {
273 0         0 $Hash{$class}{$key} = $_[0];
274             }
275             else
276             {
277             # If called with an index, get that value, or a slice for array refs
278 4 100       16 if(@_ == 1)
279             {
280 2 50       18 return ref $_[0] eq 'ARRAY' ? @{$Hash{$class}{$key}}{@{$_[0]}} :
  0         0  
  0         0  
281             $Hash{$class}{$key}{$_[0]};
282             }
283              
284             # Push on new values and return complete set
285 2 50       14 Carp::croak "Odd number of items in assigment to $name" if(@_ % 2);
286              
287 2         9 while(@_)
288             {
289 4         9 local $_ = shift;
290 4         21 $Hash{$class}{$key}{$_} = shift;
291             }
292             }
293              
294 2 0       16 return wantarray ? %{$Hash{$class}{$key} || {}} : $Hash{$class}{$key};
  0 50       0  
295 2         13 };
296             }
297 0         0 else { Carp::croak "Unknown interface: $interface" }
298              
299 14         46 return \%methods;
300             }
301             our %Inheritable_Hash;
302             # (
303             # class_name =>
304             # {
305             # key =>
306             # {
307             # some_attr_name1 => ...,
308             # some_attr_name2 => ...,
309             # ...
310             # },
311             # ...
312             # },
313             # ...
314             # );
315              
316             sub inheritable_hash
317             {
318 16     16 1 27 my($class, $name, $args) = @_;
319              
320 16         18 my %methods;
321              
322 16   66     48 my $key = $args->{'hash_key'} || $name;
323 16   100     52 my $interface = $args->{'interface'} || 'get_set';
324              
325             my $init_method = sub
326             {
327 14 50   14   53 my($class) = ref $_[0] ? ref shift : shift;
328              
329             # Inherit shallow copy from subclass
330 14         26 my @parents = ($class);
331              
332 14         44 SEARCH: while(my $parent = shift(@parents))
333             {
334 3     3   32 no strict 'refs';
  3         7  
  3         6103  
335 14         17 foreach my $subclass (@{$parent . '::ISA'})
  14         79  
336             {
337 10         23 push(@parents, $subclass);
338              
339 10 50       34 if(exists $Inheritable_Hash{$subclass}{$key})
340             {
341 10         14 $Inheritable_Hash{$class}{$key} = { %{$Inheritable_Hash{$subclass}{$key}} };
  10         59  
342 10         40 last SEARCH;
343             }
344             }
345             }
346 16         67 };
347              
348 16 100       95 if($interface eq 'get_set_all')
    100          
    100          
    100          
    100          
    100          
    100          
    50          
349             {
350             $methods{$name} = sub
351             {
352 10 50   10   1675 my($class) = ref $_[0] ? ref shift : shift;
353              
354 10 100       47 defined $Inheritable_Hash{$class}{$key} || $init_method->($class);
355              
356             # If called with no arguments, return hash contents
357 10 50       133 return wantarray ? %{$Inheritable_Hash{$class}{$key} || {}} : $Inheritable_Hash{$class}{$key} unless(@_);
  2 100       26  
    100          
358              
359             # Set hash to arguments
360 4 100 66     27 if(@_ == 1 && ref $_[0] eq 'HASH')
361             {
362 2         8 $Inheritable_Hash{$class}{$key} = $_[0];
363             }
364             else
365             {
366             # Push on new values and return complete set
367 2 50       12 Carp::croak "Odd number of items in assigment to $name" if(@_ % 2);
368              
369 2         9 while(@_)
370             {
371 4         10 local $_ = shift;
372 4         19 $Inheritable_Hash{$class}{$key}{$_} = shift;
373             }
374             }
375              
376 4 0       1279 return wantarray ? %{$Inheritable_Hash{$class}{$key} || {}} : $Inheritable_Hash{$class}{$key};
  0 50       0  
377             }
378 2         23 }
379             elsif($interface eq 'clear')
380             {
381             $methods{$name} = sub
382             {
383 2     2   10 $Inheritable_Hash{$_[0]}{$key} = {}
384             }
385 2         10 }
386             elsif($interface eq 'reset')
387             {
388             $methods{$name} = sub
389             {
390 2     2   10 $Inheritable_Hash{$_[0]}{$key} = undef;
391             }
392 2         9 }
393             elsif($interface eq 'delete')
394             {
395             $methods{($interface eq 'manip' ? 'delete_' : '') . $name} = sub
396             {
397 4 50   4   21 Carp::croak "Missing key(s) to delete" unless(@_ > 1);
398 4 50       19 defined $Inheritable_Hash{$_[0]}{$key} || $init_method->($_[0]);
399 4         17 delete @{$Inheritable_Hash{$_[0]}{$key}}{@_[1 .. $#_]};
  4         19  
400             }
401 2 50       16 }
402             elsif($interface eq 'exists')
403             {
404             $methods{$name . ($interface eq 'manip' ? '_exists' : '')} = sub
405             {
406 8 50   8   73 Carp::croak "Missing key argument" unless(@_ == 2);
407 8 50       37 defined $Inheritable_Hash{$_[0]}{$key} || $init_method->($_[0]);
408 8 50       135 defined $Inheritable_Hash{$_[0]}{$key} ? exists $Inheritable_Hash{$_[0]}{$key}{$_[1]} : undef;
409             }
410 2 50       14 }
411             elsif($interface =~ /^(?:keys|names)$/)
412             {
413             $methods{$name} = sub
414             {
415 24 100   24   113 defined $Inheritable_Hash{$_[0]}{$key} || $init_method->($_[0]);
416 24 50       230 wantarray ? (defined $Inheritable_Hash{$_[0]}{$key} ? keys %{$Inheritable_Hash{$_[0]}{$key} || {}} : ()) :
  0 0       0  
417 24 50       81 (defined $Inheritable_Hash{$_[0]}{$key} ? [ keys %{$Inheritable_Hash{$_[0]}{$key} || {}} ] : []);
    0          
    50          
418             }
419 2         11 }
420             elsif($interface eq 'values')
421             {
422             $methods{$name} = sub
423             {
424 24 50   24   94 defined $Inheritable_Hash{$_[0]}{$key} || $init_method->($_[0]);
425 24 50       233 wantarray ? (defined $Inheritable_Hash{$_[0]}{$key} ? values %{$Inheritable_Hash{$_[0]}{$key} || {}} : ()) :
  0 0       0  
426 24 50       166 (defined $Inheritable_Hash{$_[0]}{$key} ? [ values %{$Inheritable_Hash{$_[0]}{$key} || {}} ] : []);
    0          
    50          
427             }
428 2         17 }
429             elsif($interface eq 'get_set')
430             {
431             $methods{$name} = sub
432             {
433 6 50   6   28 my($class) = ref $_[0] ? ref shift : shift;
434              
435 6 50       38 defined $Inheritable_Hash{$class}{$key} || $init_method->($class);
436              
437             # If called with no arguments, return hash contents
438 6 50       24 unless(@_)
439             {
440 0 0       0 return wantarray ? (defined $Inheritable_Hash{$class}{$key} ? %{$Inheritable_Hash{$class}{$key} || {}} : ()) : $Inheritable_Hash{$class}{$key}
  0 0       0  
    0          
441             }
442              
443             # If called with a hash ref, set value
444 6 50 66     34 if(@_ == 1 && ref $_[0] eq 'HASH')
445             {
446 0         0 $Inheritable_Hash{$class}{$key} = $_[0];
447             }
448             else
449             {
450             # If called with an index, get that value, or a slice for array refs
451 6 100       24 if(@_ == 1)
452             {
453 2 50       28 return ref $_[0] eq 'ARRAY' ? @{$Inheritable_Hash{$class}{$key}}{@{$_[0]}} :
  0         0  
  0         0  
454             $Inheritable_Hash{$class}{$key}{$_[0]};
455             }
456              
457             # Push on new values and return complete set
458 4 50       23 Carp::croak "Odd number of items in assigment to $name" if(@_ % 2);
459              
460 4         15 while(@_)
461             {
462 6         11 local $_ = shift;
463 6         26 $Inheritable_Hash{$class}{$key}{$_} = shift;
464             }
465             }
466              
467 4 0       23 return wantarray ? %{$Inheritable_Hash{$class}{$key} || {}} : $Inheritable_Hash{$class}{$key};
  0 50       0  
468 2         14 };
469             }
470 0         0 else { Carp::croak "Unknown interface: $interface" }
471              
472 16         83 return \%methods;
473             }
474              
475 3     3   25 use constant CLASS_VALUE => 1;
  3         8  
  3         1016  
476 3     3   21 use constant INHERITED_VALUE => 2;
  3         6  
  3         163  
477 3     3   17 use constant DELETED_VALUE => 3;
  3         5  
  3         355  
478              
479             our %Inherited_Hash;
480             # (
481             # some_name =>
482             # {
483             # class1 =>
484             # {
485             # meta => { ... },
486             # cache =>
487             # {
488             # meta =>
489             # {
490             # attr1 => CLASS_VALUE,
491             # attr2 => DELETED_VALUE,
492             # ...
493             # },
494             # attrs =>
495             # {
496             # attr1 => value1,
497             # attr2 => value2,
498             # ...
499             # },
500             # },
501             # },
502             # class2 => ...,
503             # ...
504             # },
505             # ...
506             # );
507              
508             # Used as array indexes to replace {'meta'}, {'attrs'}, and {'cache'}
509 3     3   17 use constant META => 0;
  3         4  
  3         146  
510 3     3   15 use constant CACHE => 1;
  3         5  
  3         142  
511 3     3   66 use constant ATTRS => 1;
  3         8  
  3         1623  
512              
513             # XXX: This implementation is space-inefficient and pretty silly
514             sub inherited_hash
515             {
516 8     8 1 25 my($class, $name, $args) = @_;
517              
518 8         19 my %methods;
519              
520             # Interface example:
521             # name: object_type_class
522             # plural_name: object_type_classes
523             #
524             # get_set: object_type_class
525             # get_set_all_method: object_type_classes
526             # keys_method: object_type_class_keys
527             # cache_method: object_type_classes_cache
528             # exists_method: object_type_class_exists
529             # add_method: add_object_type_class
530             # adds_method: add_object_type_classes
531             # delete_method: delete_object_type_class
532             # deletes_method: delete_object_type_classes
533             # clear_method clear_object_type_classes
534             # inherit_method: inherit_object_type_class
535             # inherits_method: inherit_object_type_classes
536              
537 8   33     48 my $plural_name = $args->{'plural_name'} || $name . 's';
538              
539 8         11 my $get_set_method = $name;
540 8   33     74 my $get_set_all_method = $args->{'get_set_all_method'} || $args->{'hash_method'} || $plural_name;
541 8   66     35 my $keys_method = $args->{'keys_method'} || $name . '_keys';
542 8   33     41 my $cache_method = $args->{'cache_method'} || $plural_name . '_cache';
543 8   66     54 my $exists_method = $args->{'exists_method'} || $args->{'exists_method'} || $name . '_exists';
544 8   33     37 my $add_method = $args->{'add_method'} || 'add_' . $name;
545 8   33     42 my $adds_method = $args->{'adds_method'} || 'add_' . $plural_name;
546 8   33     44 my $delete_method = $args->{'delete_method'} || 'delete_' . $name;
547 8   33     37 my $deletes_method = $args->{'deletes_method'} || 'delete_' . $plural_name;
548 8   33     40 my $clear_method = $args->{'clear_method'} || 'clear_' . $plural_name;
549 8   33     38 my $inherit_method = $args->{'inherit_method'} || 'inherit_' . $name;
550 8   33     49 my $inherits_method = $args->{'inherits_method'} || 'inherit_' . $plural_name;
551              
552 8   50     38 my $interface = $args->{'interface'} || 'all';
553              
554 8         12 my $add_implies = $args->{'add_implies'};
555 8         13 my $delete_implies = $args->{'delete_implies'};
556 8         13 my $inherit_implies = $args->{'inherit_implies'};
557              
558 8 100 66     37 $add_implies = [ $add_implies ]
559             if(defined $add_implies && !ref $add_implies);
560              
561 8 100 66     41 $delete_implies = [ $delete_implies ]
562             if(defined $delete_implies && !ref $delete_implies);
563              
564 8 100 66     58 $inherit_implies = [ $inherit_implies ]
565             if(defined $inherit_implies && !ref $inherit_implies);
566              
567             $methods{$cache_method} = sub
568             {
569 244   33 244   745 my($class) = ref($_[0]) || $_[0];
570              
571 244 100       1069 if($Inherited_Hash{$name}{$class}[META]{'cache_is_valid'})
572             {
573             return
574 142 50 0     832 wantarray ? (%{$Inherited_Hash{$name}{$class}[CACHE] ||= []}) :
  0   50     0  
575             ($Inherited_Hash{$name}{$class}[CACHE] ||= []);
576             }
577              
578 102   100     359 my $cache = $Inherited_Hash{$name}{$class}[CACHE] ||= [];
579              
580 102         198 my @parents = ($class);
581              
582 102         259 while(my $parent = shift(@parents))
583             {
584 3     3   19 no strict 'refs';
  3         5  
  3         1521  
585 216         240 foreach my $superclass (@{$parent . '::ISA'})
  216         1087  
586             {
587 114         262 push(@parents, $superclass);
588              
589 114 50       840 if($superclass->can($cache_method))
    0          
590             {
591 114         358 my $supercache = $superclass->$cache_method();
592              
593 114 100       165 while(my($attr, $state) = each %{$supercache->[META] || {}})
  578         2780  
594             {
595 464 100       940 next if($state == DELETED_VALUE);
596              
597 3     3   21 no warnings 'uninitialized';
  3         10  
  3         2130  
598 298 100       748 unless(exists $cache->[ATTRS]{$attr})
599             {
600 128         277 $cache->[ATTRS]{$attr} = $supercache->[ATTRS]{$attr};
601 128         756 $cache->[META]{$attr} = INHERITED_VALUE;
602             }
603             }
604             }
605             # Slower method for superclasses that don't want to implement the
606             # cache method (which is not strictly part of the public API)
607             elsif($superclass->can($keys_method))
608             {
609 0         0 foreach my $attr ($superclass->$keys_method())
610             {
611 0 0       0 unless(exists $Inherited_Hash{$name}{$class}[CACHE][ATTRS]{$attr})
612             {
613 0         0 $Inherited_Hash{$name}{$class}[CACHE][META]{$attr} = INHERITED_VALUE;
614 0         0 $Inherited_Hash{$name}{$class}[CACHE][ATTRS]{$attr} =
615             $Inherited_Hash{$name}{$superclass}[CACHE][ATTRS]{$attr};
616             }
617             }
618             }
619             }
620             }
621              
622 102         263 $Inherited_Hash{$name}{$class}[META]{'cache_is_valid'} = 1;
623              
624 102         161 my $want = wantarray;
625              
626 102 100       224 return unless(defined $want);
627 96 50 0     669 $want ? (%{$Inherited_Hash{$name}{$class}[CACHE] ||= []}) :
  0   50     0  
628             ($Inherited_Hash{$name}{$class}[CACHE] ||= []);
629 8         74 };
630              
631             $methods{$get_set_method} = sub
632             {
633 216 50   216   766 my($class) = ref($_[0]) ? ref(shift) : shift;
634 216 50       512 return 0 unless(defined $_[0]);
635              
636 216         291 my $key = shift;
637              
638 216 100       509 if(@_)
639             {
640 16 50       100 Carp::croak "More than one value passed to $get_set_method()" if(@_ > 1);
641 16         172 $class->$adds_method($key, @_);
642             }
643             else
644             {
645 200 100       724 if($Inherited_Hash{$name}{$class}[META]{'cache_is_valid'})
646             {
647 194   50     565 my $cache = $Inherited_Hash{$name}{$class}[CACHE] ||= [];
648              
649 3     3   18 no warnings 'uninitialized';
  3         6  
  3         332  
650 194 100       1557 return $cache->[ATTRS]{$key} unless($cache->[META]{$key} == DELETED_VALUE);
651 16         97 return undef;
652             }
653              
654 6         34 my $cache = $class->$cache_method();
655              
656 3     3   22 no warnings 'uninitialized';
  3         4  
  3         5554  
657 6 50       66 return $cache->[ATTRS]{$key} unless($cache->[META]{$key} == DELETED_VALUE);
658 0         0 return undef;
659             }
660 8         40 };
661              
662             $methods{$keys_method} = sub
663             {
664 42     42   124 my($class) = shift;
665 42 50       109 $class = ref $class if(ref $class);
666 42         164 return wantarray ? keys %{$class->$get_set_all_method()} :
  0         0  
667 42 50       88 [ keys %{$class->$get_set_all_method()} ];
668 8         44 };
669              
670             $methods{$get_set_all_method} = sub
671             {
672 48     48   1541 my($class) = shift;
673              
674 48 50       105 $class = ref $class if(ref $class);
675              
676 48 100       109 if(@_)
677             {
678 6         33 $class->$clear_method();
679 6         31 return $class->$adds_method(@_);
680             }
681              
682 42         131 my $cache = $class->$cache_method();
683 42 100       63 my %hash = %{$cache->[ATTRS] || {}};
  42         249  
684              
685 42         155 foreach my $k (keys %hash)
686             {
687 128 100       855 delete $hash{$k} if($Inherited_Hash{$name}{$class}[CACHE][META]{$k} == DELETED_VALUE);
688             }
689              
690 42 50       482 return wantarray ? %hash : \%hash;
691 8         76 };
692              
693             $methods{$exists_method} = sub
694             {
695 288 50   288   5151 my($class) = ref($_[0]) ? ref(shift) : shift;
696              
697 288         438 my $key = shift;
698              
699 288 50       633 return 0 unless(defined $key);
700              
701 288 100       1181 if($Inherited_Hash{$name}{$class}[META]{'cache_is_valid'})
702             {
703 212   50     683 my $cache = $Inherited_Hash{$name}{$class}[CACHE] ||= [];
704 212 100 100     2437 return (exists $cache->[ATTRS]{$key} && $cache->[META]{$key} != DELETED_VALUE) ? 1 : 0;
705             }
706              
707 76         281 my $cache = $class->$cache_method();
708              
709 76 100 66     1239 return (exists $cache->[ATTRS]{$key} && $cache->[META]{$key} != DELETED_VALUE) ? 1 : 0;
710 8         48 };
711              
712 8     48   44 $methods{$add_method} = sub { shift->$adds_method(@_) };
  48         1759  
713              
714             $methods{$adds_method} = sub
715             {
716 72 50   72   220 my($class) = ref($_[0]) ? ref(shift) : shift;
717 72 50       181 Carp::croak("Missing name/value pair(s) to add") unless(@_);
718              
719 72         83 my @attrs;
720 72         89 my $count = 0;
721              
722 72   100     290 my $cache = $Inherited_Hash{$name}{$class}[CACHE] ||= [];
723              
724             # XXX: Lame duplication to avoid copying the hash
725 72 100 66     241 if(@_ == 1 && ref $_[0] eq 'HASH')
726             {
727 2         15 while(my($attr, $value) = each(%{$_[0]}))
  8         38  
728             {
729 6 50       14 next unless(defined $attr);
730              
731 6         9 push(@attrs, $attr);
732              
733 6         13 $cache->[ATTRS]{$attr} = $value;
734 6         10 $cache->[META]{$attr} = CLASS_VALUE;
735              
736 6 50       17 if($add_implies)
737             {
738 0         0 foreach my $method (@$add_implies)
739             {
740 0         0 $class->$method($attr => $value);
741             }
742             }
743              
744 6         12 $count++;
745             }
746             }
747             else
748             {
749 70 50       409 Carp::croak("Odd number of arguments passed to $adds_method") if(@_ % 2);
750              
751 70         158 while(@_)
752             {
753 82         158 my($attr, $value) = (shift, shift);
754              
755 82         127 push(@attrs, $attr);
756              
757 3     3   23 no strict 'refs';
  3         6  
  3         1930  
758 82 50       188 next unless(defined $attr);
759 82         768 $cache->[ATTRS]{$attr} = $value;
760 82         159 $cache->[META]{$attr} = CLASS_VALUE;
761              
762 82 100       208 if($add_implies)
763             {
764 28         63 foreach my $method (@$add_implies)
765             {
766 28         122 $class->$method($attr => $value);
767             }
768             }
769              
770 82         234 $count++;
771             }
772             }
773              
774 72 50       148 if($count)
775             {
776 72         83 foreach my $test_class (keys %{$Inherited_Hash{$name}})
  72         230  
777             {
778 228 100 100     1901 if($test_class->isa($class) && $test_class ne $class)
779             {
780 90         277 $Inherited_Hash{$name}{$test_class}[META]{'cache_is_valid'} = 0;
781              
782 90         136 foreach my $attr (@attrs)
783             {
784 102         384 delete $Inherited_Hash{$name}{$test_class}[CACHE][ATTRS]{$attr};
785             }
786             }
787             }
788             }
789              
790 72         645 return $count;
791 8         77 };
792              
793             $methods{$clear_method} = sub
794             {
795 8 50   8   36 my($class) = ref($_[0]) ? ref(shift) : shift;
796 8         185 my @keys = $class->$keys_method();
797 8 100       42 return unless(@keys);
798 4         23 $class->$deletes_method(@keys);
799 8         54 };
800              
801 8     68   49 $methods{$delete_method} = sub { shift->$deletes_method(@_) };
  68         335  
802              
803             $methods{$deletes_method} = sub
804             {
805 72 50   72   199 my($class) = ref($_[0]) ? ref(shift) : shift;
806 72 50       188 Carp::croak("Missing value(s) to delete") unless(@_);
807              
808             # Init set if it doesn't exist
809 72 100       385 unless(exists $Inherited_Hash{$name}{$class})
810             {
811 6         35 $class->$cache_method();
812             }
813              
814 72         100 my $count = 0;
815              
816 72   50     241 my $cache = $Inherited_Hash{$name}{$class}[CACHE] ||= [];
817              
818 72         139 foreach my $attr (@_)
819             {
820 3     3   18 no strict 'refs';
  3         7  
  3         9024  
821 82 50       163 next unless(defined $attr);
822              
823 82 100 66     460 if(exists $cache->[ATTRS]{$attr} &&
824             $cache->[META]{$attr} != DELETED_VALUE)
825             {
826 52         105 $cache->[META]{$attr} = DELETED_VALUE;
827 52         62 $count++;
828              
829 52 100       132 if($delete_implies)
830             {
831 32         55 foreach my $method (@$delete_implies)
832             {
833 32         124 $class->$method($attr);
834             }
835             }
836              
837 52         468 foreach my $test_class (keys %{$Inherited_Hash{$name}})
  52         203  
838             {
839 180 100       433 next if($class eq $test_class);
840              
841 128   50     374 my $test_cache = $Inherited_Hash{$name}{$test_class}[CACHE] ||= [];
842              
843 128 100 66     1212 if($test_class->isa($class) && exists $test_cache->[ATTRS]{$attr} &&
      100        
844             $test_cache->[META]{$attr} == INHERITED_VALUE)
845             {
846 46         94 delete $test_cache->[ATTRS]{$attr};
847 46         79 delete $test_cache->[META]{$attr};
848 46         343 $Inherited_Hash{$name}{$test_class}[META]{'cache_is_valid'} = 0;
849             }
850             }
851             }
852             }
853              
854 72         285 return $count;
855 8         58 };
856              
857 8     14   33 $methods{$inherit_method} = sub { shift->$inherits_method(@_) };
  14         134  
858              
859             $methods{$inherits_method} = sub
860             {
861 14 50   14   47 my($class) = ref($_[0]) ? ref(shift) : shift;
862 14 50       42 Carp::croak("Missing value(s) to inherit") unless(@_);
863              
864 14         22 my $count = 0;
865              
866 14   50     63 my $cache = $Inherited_Hash{$name}{$class}[CACHE] ||= [];
867              
868 14         31 foreach my $attr (@_)
869             {
870 14 100       47 if(exists $cache->[ATTRS]{$attr})
871             {
872 12         29 delete $cache->[ATTRS]{$attr};
873 12         81 delete $cache->[META]{$attr};
874 12         36 $Inherited_Hash{$name}{$class}[META]{'cache_is_valid'} = 0;
875 12         20 $count++;
876             }
877              
878 14 100       50 if($inherit_implies)
879             {
880 6         18 foreach my $method (@$inherit_implies)
881             {
882 6         43 $class->$method($attr);
883             }
884             }
885             }
886              
887 14         46 return $count;
888 8         59 };
889              
890 8 50       23 if($interface ne 'all')
891             {
892 0         0 Carp::croak "Unknown interface: $interface";
893             }
894              
895 8         52 return \%methods;
896             }
897              
898              
899             1;
900              
901             __END__