File Coverage

blib/lib/Class/Accessor/Ref.pm
Criterion Covered Total %
statement 44 46 95.6
branch 10 16 62.5
condition n/a
subroutine 10 10 100.0
pod 1 2 50.0
total 65 74 87.8


line stmt bran cond sub pod time code
1             package Class::Accessor::Ref;
2              
3 2     2   24709 use strict;
  2         4  
  2         84  
4 2     2   10 use vars qw($VERSION $_DEBUG);
  2         4  
  2         117  
5             $VERSION = '0.05';
6 2     2   10 use base 'Class::Accessor';
  2         8  
  2         2303  
7              
8             $_DEBUG = 0;
9              
10             =pod
11              
12             =head1 NAME
13              
14             Class::Accessor::Ref - Access members by reference
15              
16             =head1 SYNOPSIS
17              
18             package Foo;
19             use Class::Accessor::Ref;
20             use base qw(Class::Accessor::Ref);
21             use Some::API;
22              
23             my @members = qw(fruit color);
24             Foo->mk_accessors(@members); # as with Class::Accessor
25             Foo->mk_refaccessors(@members);
26              
27             my $obj = Foo->new({fruit => 'grape', color => 'green'});
28             Some::API::redden($obj->_ref_color); # OR
29             Some::API::redden($obj->get_ref('color'));
30             print $obj->color; # prints 'red'
31              
32             # safe against typos in memeber name
33             ${ $obj->get_ref('color') } =~ s/^(.)/\U$1/;
34              
35             # same as above, but shorter setup
36             package Foo;
37             use Class::Accessor::Ref qw(fruit color);
38              
39             =head1 DESCRIPTION
40              
41             This is an extension of Class::Accessor that allows taking a reference
42             of members of an object. This is typically useful when your class
43             implementation uses a third-party module that expects an in/out parameter
44             in its interface.
45              
46             Without Class::Accessor::Ref, you might try to do something like
47              
48             my $reference = \$obj->member; # WRONG!
49             Some::API::call($reference);
50              
51             But that takes a reference to a B of $obj->member, and is thus
52             not useful if you want to use the reference to later change the member's
53             value.
54              
55             It is quite possible to do something like
56              
57             my $reference = \$obj->{member}; # right, but risky
58              
59             But then you will get no errors if you accidentally mistype the member's
60             name.
61              
62             Class::Accessor::Ref is used very similarly to Class::Accessor --
63             just subclass it instead of Class::Accessor in your module, and call
64             mk_accessors on the fields you want to generate accessors for. Then, call
65             mk_refaccessors on the subset of the fields you want reference-taking
66             accessors generated for. The accessors will be automatically named
67             _ref_FIELD. You can continue to use the normal (non-reference) accessors
68             as before whenever appropriate.
69              
70              
71             =cut
72              
73 2     2   5655 use vars qw(%CLASSES);
  2         4  
  2         205  
74              
75             my $ref_accessor = sub {
76             my($self, $field) = @_;
77             return \$self->{$field};
78             };
79              
80             sub mk_refaccessors {
81 2     2 0 292 my($class, @fields) = @_;
82 2     2   12 no strict 'refs';
  2         4  
  2         761  
83 2         5 for my $field (@fields) {
84 4 50       15 if ($_DEBUG) { warn "$class->mk_refaccessors($field)\n" }
  0         0  
85 4 50       32 die "$field is not a valid field" unless $class->can($field);
86             # Canfield's some sort of a game, isn't it?
87 4     4   15 *{"${class}::_ref_$field"} = sub { $ref_accessor->($_[0], $field) };
  4         19  
  4         1444  
88 4         1840 $CLASSES{$class}->{$field} = 1;
89             }
90             }
91              
92              
93             =pod
94              
95             =head2 Methods
96              
97             =over 4
98              
99             =item B
100              
101             Class->mk_refaccessors(@fields);
102              
103             This creates accessor methods for each named field given in @fields.
104             Foreach field in @fields it will generate one accessor called
105             "_ref_field()". Normal accessors for the fields *must* have already
106             been created with Class::Accessor::mk_accessors(). For example:
107              
108             # Generates _ref_foo(), _ref_bar() but not _ref_baz():
109             Class->mk_accessors(qw(foo bar baz));
110             Class->mk_refaccessors(qw(foo bar));
111              
112             It is up to the user of this reference to know what to do with it.
113              
114             =item B
115              
116             $obj->get_ref(@field_names)
117              
118             This returns references to members of $obj, specified by name in
119             @field_names. In scalar context, returns a reference to the first field.
120             This method is useful if you want to fetch several references from the object
121             at once, or if you don't like the _ref_ prefix.
122              
123             # Get referece to $obj->{foo}
124             $fooref = $obj->get_ref('foo');
125             #
126             # Get several references at once
127             ($fooref, $barref) = $obj->get_ref(qw/foo bar/);
128             #
129             # Stringify the reference, not the number "1":
130             print "\$obj->{foo} is at " . $obj->get_ref('foo');
131              
132             =cut
133              
134             # XXX: This could benefit from memoization, but I don't know if
135             # I want to add that without asking the users -- if they call this
136             # on many many objects, it'll just be a waste of space. But adding
137             # a real LRU cache seems like a bit of an overkill :/
138              
139             sub get_ref {
140 2     2 1 6 my($self, @fields) = @_;
141 2         4 my $class = ref $self;
142 2 50       14 die "Can't take reference to members of unknown class $class. ".
143             "Did you call $class->mk_refaccessors?"
144             unless $CLASSES{$class};
145 2         3 my @refs;
146 2         4 foreach my $field (@fields) {
147 3 50       11 die "Can't take reference to member $field of class $class. ".
148             "Did you specify this field when calling $class->mk_refaccessors?"
149             unless $CLASSES{$class}->{$field};
150 3         9 push @refs, \$self->{$field};
151             }
152 2 100       14 return wantarray ? @refs : $refs[0];
153             }
154              
155             =item B
156              
157             use Class::Accessor::Ref qw(foo bar baz);
158              
159             For the sake of convenience, you can specify what fields to generate
160             accessors for on the C line. It also makes your calling package
161             a subclass of Class::Accessor::Ref, so you don't need to C.
162             If you want to generate refaccessors for only a subset of your regular
163             accessors, don't use this option, but rather make separate calls to
164             mk_accessors and mk_refaccessors. [Supporting this on the C line
165             was considered, but I decided it was too cumbersome and would break code
166             that's just switching from Class::Accessor.]
167              
168             package Foo;
169             use Class::Accessor::Ref qw(foo bar baz);
170              
171             Is equivalent to
172              
173             package Foo;
174             use Class::Accessor::Ref;
175             use base 'Class::Accessor::Ref';
176             Foo->mk_accessors(qw/foo bar baz/);
177             Foo->mk_refaccessors(qw/foo bar baz/);
178              
179             =back
180              
181             =cut
182              
183             sub import {
184 2     2   17 my($class, @fields) = @_;
185 2 100       236 return if !@fields;
186 1         3 my $call_pkg = (caller)[0];
187 1 50       4 if ($_DEBUG) { warn "$class: use C::A::R qw(".(join " ", @fields).")\n" }
  0         0  
188             {
189             # fake C<< packge Foo; use base 'Class::Accessor::Ref' >>
190 2     2   12 no strict 'refs';
  2         4  
  2         177  
  1         1  
191 1         2 push @{"$call_pkg\::ISA"}, $class;
  1         11  
192             }
193 1 50       3 if (@fields) {
194 1         7 $call_pkg->mk_accessors(@fields);
195 1         101 $call_pkg->mk_refaccessors(@fields);
196             }
197             }
198              
199             =head1 CAVEATS
200              
201             Class::Accessor::Ref generates methods called _ref_SOMETHING in the
202             caller's namespace. Having an existing member whose name begins with
203             _ref_ would render the normal accessor to that member inaccessible,
204             so don't do that.
205              
206             One point of Class::Accessor is to allow you to avoid changing members
207             directly. Since whoever gets hold of the return value of a _ref_ accessor
208             can circumvent any validations you may have imposed on the member (for
209             example, by overriding the normal setter method), this can be considered
210             somewhat unsafe. The main use of Class::Accessor::Ref is inside class
211             implementations, where you have control over who you trust with giving
212             a reference to your private data and who you don't.
213              
214             =head1 COPYRIGHT (The "MIT" License)
215              
216             Copyright 2003-2007 Gaal Yahas.
217              
218             Permission is hereby granted, free of charge, to any person obtaining a
219             copy of this software and associated documentation files (the "Software"),
220             to deal in the Software without restriction, including without limitation
221             the rights to use, copy, modify, merge, publish, distribute, sublicense,
222             and/or sell copies of the Software, and to permit persons to whom the
223             Software is furnished to do so, subject to the following conditions:
224              
225             The above copyright notice and this permission notice shall be included
226             in all copies or substantial portions of the Software.
227              
228             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
229             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
230             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
231             THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
232             OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
233             ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
234             OTHER DEALINGS IN THE SOFTWARE.
235              
236              
237             =head1 AUTHOR
238              
239             Gaal Yahas
240              
241              
242             =head1 SEE ALSO
243              
244             L
245              
246             =cut
247              
248              
249             1;