File Coverage

blib/lib/Class/Data/Reloadable.pm
Criterion Covered Total %
statement 53 58 91.3
branch 12 22 54.5
condition 4 12 33.3
subroutine 12 13 92.3
pod 1 1 100.0
total 82 106 77.3


line stmt bran cond sub pod time code
1             package Class::Data::Reloadable;
2 4     4   165372 use warnings;
  4         9  
  4         147  
3 4     4   21 use strict;
  4         6  
  4         167  
4 4     4   20 use Carp;
  4         10  
  4         393  
5             # use Devel::StackTrace;
6              
7 4     4   5500 use Class::ISA;
  4         13825  
  4         93  
8 4     4   3779 use NEXT;
  4         49171  
  4         1548  
9              
10             our ( $VERSION, $AUTOLOAD, $DEBUG );
11              
12             =head1 NAME
13              
14             Class::Data::Reloadable - inheritable, overridable class data that survive reloads
15              
16             =cut
17              
18             $VERSION = 0.04;
19              
20             =head1 SYNOPSIS
21              
22             package Stuff;
23             use base qw(Class::Data::Reloadable);
24              
25             # Set up DataFile as inheritable class data.
26             Stuff->mk_classdata('DataFile');
27              
28             # Declare the location of the data file for this class.
29             Stuff->DataFile('/etc/stuff/data');
30              
31             # ... reload Stuff within same interpreter
32              
33             print Stuff->DataFile; # /etc/stuff/data
34              
35             =head1 DESCRIPTION
36              
37             A drop-in replacement for L,
38             but subclasses can be reloaded without losing their class data. This is useful
39             in mod_perl development, and may be useful elsewhere.
40              
41             In mod_perl, L
42             conveniently reloads modules that have been modified, rather than having to
43             restart Apache. This works well unless the module stores class data that are
44             not re-created during the reload. In this situation, you still need to restart the
45             server, in order to rebuild the class data.
46              
47             Saves many (if your code starts out buggy like mine) Apache restarts.
48              
49             But only if you're strict about storing B class data using this mechanism.
50              
51             See L for more examples.
52              
53             =head2 Drop-in
54              
55             If you want to switch over to this module in a large app, instead of changing
56             all references to L, you can
57             instead create an empty subclass C and put it somewhere
58             in your Perl search path that gets searched before the path with the real
59             L, e.g.
60              
61             use lib '/my/lib';
62              
63             and /my/lib/Class/Data/Inheritable.pm is:
64              
65             package Class::Data::Inheritable;
66             use base 'Class::Data::Reloadable';
67             1;
68              
69             =head1 METHODS
70              
71             =over
72              
73             =item mk_classdata
74              
75             Creates a classdata slot, optionally setting a value into it.
76              
77             $client->mk_classdata( 'foo' );
78             $client->classdata->foo( 'bar' );
79             # same thing:
80             $client->mk_classdata( foo => 'bar' );
81              
82             Note that during a reload, this method may be called again for an existing
83             attribute. If so, any value passed with the method is silently ignored, in
84             favour of whatever value was in the slot before the reload.
85              
86             This also provides a C<_foo_accessor> alias.
87              
88             =cut
89              
90             =item AUTOLOAD
91              
92             If the class has been reloaded, and if before the reload, other classes have
93             called C on this class, then some accessors will be missing after
94             the reload. AUTOLOAD replaces these methods the first time they are called.
95              
96             Redispatches (via L) to any C method further up the
97             chain if no attribute is found.
98              
99             =back
100              
101             =cut
102              
103             sub mk_classdata {
104 3     3 1 980 my ( $proto, $attribute ) = ( shift, shift );
105              
106             # During a reload, this method will often be called again. In that case,
107             # do _not_ set any value being passed in this call - discard it and return
108             # whatever was last stored there before the reload.
109 3 50 33     21 return $proto->$attribute if $proto->__has( $attribute ) && $proto->can( $attribute );
110              
111 3         21 $proto->__mk_accessor( $attribute, @_ );
112             }
113              
114             sub AUTOLOAD {
115 2     2   21 my $proto = shift;
116              
117 2         26 my ( $attribute ) = $AUTOLOAD =~ /([^:]+)$/;
118              
119 2 50       9 warn "AUTOLOADING $attribute ($AUTOLOAD) in $proto\n" if $DEBUG;
120              
121 2         3 my $owner = eval { $proto->__has( $attribute ) };
  2         6  
122              
123 2 50       7 if ( my $er = $@ )
124             {
125 0         0 die "Error AUTOLOADing $AUTOLOAD for $proto - $er";
126             }
127              
128 2 50       6 if ( $owner )
129             {
130             # put it back where it came from
131 0         0 $owner->__mk_accessor( $attribute );
132 0         0 return $proto->$attribute( @_ );
133             }
134             else
135             {
136 2 50       9 warn "'$attribute' not owned by C::D::Reloadable client - delegating AUTOLOAD in $proto\n" if $DEBUG;
137             # maybe it was intended for somewhere else
138 2         12 return $proto->NEXT::ACTUAL::DISTINCT::AUTOLOAD( @_ );
139             }
140             }
141              
142 0     0   0 sub DESTROY { $_[0]->NEXT::DISTINCT::DESTROY() }
143              
144             sub __mk_accessor {
145 3     3   6 my ( $proto, $attribute ) = ( shift, shift );
146              
147 3   33     22 my $client = ref( $proto ) || $proto;
148              
149 3 50       10 warn "making '$attribute' accessor in $client\n" if $DEBUG;
150              
151 3     7   14 my $accessor = sub { shift->__classdata( $attribute, @_ ) };
  7         1411  
152              
153 3         10 my $alias = "_${attribute}_accessor";
154              
155 4     4   427 no strict 'refs';
  4         9  
  4         1253  
156 3         6 *{"$client\::$attribute"} = $accessor;
  3         20  
157 3         6 *{"$client\::$alias"} = $accessor;
  3         18  
158              
159 3 50       15 $proto->$attribute( $_[0] ) if @_;
160             }
161              
162             # in case you want to mess with it - but don't do that
163             our $ClassData;
164              
165             sub __classdata {
166 7     7   13 my ( $proto, $attribute ) = ( shift, shift );
167              
168 7   33     29 my $client = ref( $proto ) || $proto;
169              
170             # if there's data to set, put it in the client slot
171 7 100       40 return( $ClassData->{ $client }{ $attribute } = $_[0] ) if @_;
172              
173             # if there's no data to set, search for a previous value
174 4         13 foreach my $ima ( Class::ISA::self_and_super_path( $client ) )
175             {
176 4 50       738 return $ClassData->{ $ima }{ $attribute } if
177             exists $ClassData->{ $ima }{ $attribute };
178             }
179              
180 0         0 return undef; # should always at least return undef (i.e. not an empty list)
181             }
182              
183             sub __has {
184 5     5   11 my ( $proto, $attribute ) = @_;
185              
186 5   33     58 my $client = ref( $proto ) || $proto;
187              
188 5         8 my $owner;
189              
190 5         49 foreach my $ima ( Class::ISA::self_and_super_path( $client ) )
191             {
192 10 50       196 $owner = $ima if exists $ClassData->{ $ima }{ $attribute };
193 10 50       35 last if $owner;
194             }
195              
196 5         20 return $owner;
197             }
198              
199             =head1 AUTHOR
200              
201             David Baird, C<< >>
202              
203             =head1 BUGS
204              
205             Please report any bugs or feature requests to
206             C, or through the web interface at
207             L. I will be notified, and then you'll automatically
208             be notified of progress on your bug as I make changes.
209              
210             =head1 DEBUGGING
211              
212             Set C<$Class::Data::Reloadable::DEBUG = 1> to get debugging output (via C) that
213             may be useful for debugging either this module, or classes that inherit from it.
214              
215             You may also want to dig around in C<$Class::Data::Reloadable::ClassData>, but
216             don't tell anyone I told you.
217              
218             =head1 COPYRIGHT & LICENSE
219              
220             Copyright 2004 David Baird, All Rights Reserved.
221              
222             This program is free software; you can redistribute it and/or modify it
223             under the same terms as Perl itself.
224              
225             =cut
226              
227             1; # End of Class::Data::Separated