File Coverage

blib/lib/Object/Generic.pm
Criterion Covered Total %
statement 82 99 82.8
branch 22 34 64.7
condition 1 3 33.3
subroutine 18 23 78.2
pod 0 10 0.0
total 123 169 72.7


line stmt bran cond sub pod time code
1             package Object::Generic;
2             #
3             # Object::Generic.pm
4             #
5             # A generic base class for objects including
6             # several set/get interfaces for key/value pairs within the object.
7             #
8             # use Object::Generic;
9             # $thing = new Object::Generic color => 'red';
10             #
11             # $color = $thing->get('color');
12             # $color = $thing->get_color;
13             # $color = $thing->color
14             #
15             # $thing->set( color => 'blue' );
16             # $thing->set_color('blue');
17             # $thing->color('blue');
18             #
19             # See the bottom of this file for the documentation.
20             #
21             # $Id: Generic.pm 403 2005-09-08 20:17:37Z mahoney $
22             #
23             #
24 2     2   27198 use strict;
  2         6  
  2         90  
25 2     2   13 use warnings;
  2         2  
  2         73  
26 2     2   609 use Object::Generic::False qw(false);
  2         5  
  2         1092  
27              
28             our $VERSION = '0.13';
29              
30             my $false = Object::Generic::false();
31              
32             sub new {
33 4     4 0 45 my $class = shift;
34 4         9 my $self = bless {} => $class;
35 4         23 $self->args(@_);
36 4         15 return $self;
37             }
38              
39             # Return a list of the current keys.
40             sub keys {
41 2     2 0 3 my $self = shift;
42 2         10 return keys %$self;
43             }
44              
45             # Return true or false depending on whether a key has been defined.
46             sub exists {
47 15     15 0 19 my $self = shift;
48 15         24 my ($key) = @_;
49 15 50       34 return 0 unless defined $key;
50 15         100 return exists($self->{$key});
51             }
52              
53             #
54             # If the hash for a given class is empty, then any key is allowed
55             # in ->set_key() and its variants for that class.
56             # Otherwise, only the given keys are allowed.
57             # The allowed keys are defined relative to a given class name
58             # so that inherited classes will each have their own list of allowed keys.
59             #
60             # In other words, if MyClass inherits from Object::Generic,
61             # and only 'color' and 'height' are allowed keys for that class,
62             # then this hash will include
63             # $allowed_keys = { MyClass => { color=>1, height=>1 } }
64             # On the other hand, since there is no $allowed_keys->{Object::Generic},
65             # any key is allowed (by default) in Object::Generic.
66             #
67             our $allowed_keys = { };
68              
69             # Usage: InheritedClass->set_allowed_keys( 'color', 'size' );
70             # This sets the keys for an entire class, *not* for one instance.
71             # If you want different objects with different sets of allowed keys,
72             # define several classes that inherit from Object::Generic.
73             sub set_allowed_keys {
74 1     1 0 2 my $class = shift;
75 1 50       4 return 0 if ref($class); # do nothing and return false if this is an object.
76 1         4 my @keys = @_;
77 1         7 $allowed_keys->{$class}{$_} = 1 foreach @keys;
78 1         4 return 1; # return true
79             }
80              
81             #
82             # Usage: if ( InheritedClass->allows_key($key) ){ ... }
83             # or if ( $object->allows_key($key) ){ ... }
84             sub allows_key {
85 14     14 0 18 my $self_or_class = shift; # either class or object method; don't care.
86 14   33     58 my $class = ref($self_or_class) || $self_or_class;
87 14         18 my ($key) = @_;
88 14 100       53 return 1 unless exists($allowed_keys->{$class});
89 4         17 return $allowed_keys->{$class}{$key};
90             }
91              
92              
93             # Usage: InheritedClass->define_accessors( @keys );
94             # For each $key, defines $obj->get_key(), $obj->set_key(), and $obj->key().
95             # Also calls set_allowed_keys, so as a side effect, other keys not in
96             # this won't be allowed unless given in another call to set_allowed_keys
97             # or define_accessors. Note that this may be helpful if you're using
98             # multiple inheritance, since this can avoid the use of AUTOHANDLER which
99             # may not be available if there's another AUTOHANDER earlier in the
100             # inheritence chain.
101             sub define_subs {
102 0     0 0 0 my $class = shift;
103 0 0       0 return if ref($class); # This can't be called from an object instance.
104 0         0 my @keys = @_;
105 0         0 $class->set_allowed_keys(@keys);
106 0         0 for my $key (@keys){
107 2     2   17 no strict 'refs';
  2         4  
  2         1148  
108 0         0 *{$class . '::' . $key } = sub {
109 0 0   0   0 $_[0]->set( $key => $_[1] ) if exists $_[1];
110 0         0 return $_[0]->get( $key );
111 0         0 };
112 0         0 *{$class . '::' . 'set_' . $key } = sub {
113 0     0   0 $_[0]->set($key => $_[1]);
114 0         0 return $_[0]->get($key);
115 0         0 };
116 0         0 *{$class . '::' . 'get_' . $key } = sub {
117 0     0   0 return $_[0]->get($key);
118 0         0 };
119             }
120             }
121              
122             # $obj->remove($key) is the same as delete($obj->{$key});
123             sub remove {
124 1     1 0 3 my $self = shift;
125 1         2 my $key = shift;
126 1 50       5 return unless $key;
127 1         4 delete($self->{$key});
128             }
129              
130             #
131             # The following ->set(key=>value) and ->get(value) methods
132             # are the only authorized way to access the internal data;
133             # all other internal and external methods (including
134             # the memo-ized subs that AUTOHANDLER creates) use these.
135             # This makes it simpler to change the internal storage mechanism
136             # in an inherited class, at the cost of a bit of speed.
137             #
138              
139             # Usage: $value = $object->get( 'key' );
140             sub get {
141 13     13 0 19 my $self = shift;
142 13         20 my ($key) = @_;
143 13 50       28 return $false unless ref($self);
144 13 100       44 return $false unless $self->exists($key);
145 10         55 return $self->{$key};
146             }
147              
148             # Usage: $object->set( key => $value );
149             sub set {
150 11     11 0 15 my $self = shift;
151 11 50       30 return $false unless ref($self);
152 11         18 my ($key, $value) = @_;
153 11         46 $self->{$key} = $value;
154 11         27 return $value;
155             }
156              
157             # $obj->args(@_) :
158             # Extract key => value pairs from the @_ and put them in the object's hash.
159             # The motivation runs like this:
160             # When I call $foo->bar( one => 1, two => 2),
161             # I often want to have $foo->{one}=1 and $foo->{two}=2.
162             # This subroutine does that.
163             # While this is not the default behavior of all inherited methods,
164             # any methods that do want this behavior can implement it with this method.
165             # Note that the CORE::keys syntax distinguishes this from $obj->keys()
166             sub args {
167 6     6 0 9 my $self = shift;
168 6         19 my %hash = @_;
169 6         31 $self->set($_ => $hash{$_}) foreach CORE::keys(%hash);
170 6         36 return $self;
171             }
172              
173 0     0   0 sub DESTROY { # Define this here so AUTOLOAD won't handle it.
174             }
175              
176             sub AUTOLOAD {
177 16     16   1362 my $self = shift;
178 16         24 my ($value) = (@_);
179 16 100       130 return $false unless ref($self); # Don't handle class methods.
180 14         14 our $AUTOLOAD;
181 2     2   11 no strict 'refs';
  2         3  
  2         833  
182 14         62 $AUTOLOAD =~ m/^(.*)::\w+$/;
183 14         33 my $class = $1;
184 14         84 (my $subname = $AUTOLOAD) =~ s/.*:://; # Remove class:: from sub name.
185             # -- debugging --
186             #print " -- Generic::AUTOLOAD\n";
187             #print " autoload = '$AUTOLOAD'\n";
188             #print " subname = '$subname'\n";
189             #print " class = '$class'\n";
190 14 100       51 if ($subname =~ /^set_(.*)$/){ # Define $obj->set_key($value)
    100          
191 1         3 my $key = $1;
192 1 50       4 return $false unless $class->allows_key($key);
193 1         4 *{$AUTOLOAD} = sub {
194 1 50   1   4 return $false unless exists $_[1];
195 1         5 $_[0]->set( $key => $_[1] );
196 1         4 return $_[1];
197 1         6 };
198             }
199             elsif ($subname =~ /^get_(.*)$/){ # Define $obj->get_key()
200 2         5 my $key = $1;
201 2 50       4 return $false unless $class->allows_key($key);
202 2         7 *{$AUTOLOAD} = sub {
203 2     2   6 return $_[0]->get($key);
204 2         7 };
205             }
206             else { # Define $obj->key($value)
207 11         14 my $key = $subname;
208 11 100       41 return $false unless $class->allows_key($key);
209 9         34 *{$AUTOLOAD} = sub {
210 15 100   15   37 if (exists($_[1])){
211 4         13 $_[0]->set( $key => $_[1] );
212 4         21 return $_[1];
213             }
214             else {
215 11         46 return $_[0]->get($key);
216             }
217 9         32 };
218             }
219 12         38 return $self->$subname(@_); # Call it.
220             }
221              
222             1;
223              
224             __END__