File Coverage

blib/lib/DBIx/VersionedSubs/AutoLoad.pm
Criterion Covered Total %
statement 67 72 93.0
branch 10 18 55.5
condition 2 4 50.0
subroutine 15 15 100.0
pod 5 5 100.0
total 99 114 86.8


line stmt bran cond sub pod time code
1             package DBIx::VersionedSubs::AutoLoad;
2 4     4   2466 use strict;
  4         7  
  4         155  
3 4     4   20 use base 'DBIx::VersionedSubs';
  4         7  
  4         3004  
4 4     4   26 use vars qw($VERSION);
  4         7  
  4         160  
5 4     4   23 use Carp qw(carp croak);
  4         7  
  4         400  
6              
7             $VERSION = '0.07';
8              
9             =head1 NAME
10              
11             DBIx::VersionedSubs::AutoLoad - autoload subroutines from the database
12              
13             =head1 SYNOPSIS
14              
15             package My::App;
16             use strict;
17             use base 'DBIx::VersionedSubs::AutoLoad';
18              
19             package main;
20             use strict;
21              
22             My::App->startup($dsn);
23             while (my $request = Some::Server->get_request) {
24             My::App->update_code; # update code from the DB
25             My::App->handle_request($request);
26             }
27              
28             =head1 ABSTRACT
29              
30             This module overrides some methods in L
31             to prevent loading of the whole code at startup and installs
32             an AUTOLOAD handler to load the needed code on demand. This
33             is useful if startup time is more important than response time
34             or you fork() before loading the code from the database.
35              
36             =head1 CAVEATS
37              
38             You should be able to switch between the two implementations
39             without almost any further code changes. There is one
40             drawback of the AUTOLOAD implementation:
41              
42             =head2 Preexisting functions don't get overwritten from the database
43              
44             You need to explicitly load functions from the database
45             that you wish to overwrite Perl code obtained from elsewhere.
46              
47             This is the price you pay for using AUTOLOAD.
48              
49             =head1 CLASS METHODS
50              
51             =cut
52              
53             =head2 C<< __PACKAGE__->init_code >>
54              
55             Overridden to just install the AUTOLOAD handler.
56              
57             =cut
58              
59             sub init_code {
60 3     3 1 46907 my ($package) = @_;
61 4     4   30 no strict 'refs';
  4         13  
  4         306  
62 3 50       10 if (! defined &{"$package\::AUTOLOAD"}) {
  3         34  
63 3         22 *{"$package\::AUTOLOAD"} = sub {
64 4     4   22 use vars qw($AUTOLOAD);
  4         8  
  4         1882  
65 3 50   3   1751 if ($AUTOLOAD !~ /::(\w+)$/) {
66 0         0 croak "Undecipherable subroutine '$AUTOLOAD' called";
67             };
68 3         9 my $name = $1;
69 3         27 $package->install_and_invoke($name,@_);
70 3         19 };
71             } else {
72 0         0 carp "$package->init_code called, but there already is an AUTOLOAD handler installed.";
73             };
74              
75 3         33 my $begin = $package->retrieve_code('BEGIN');
76 3 100       15 if (defined $begin) {
77 1         91 eval "{ $begin }";
78 1 50       7 carp "$package\::BEGIN: $@" if $@
79             };
80             };
81              
82             =head2 C<< __PACKAGE__->install_and_invoke NAME, ARGS >>
83              
84             Loads code from the database, installs it
85             into the namespace and immediately calls it
86             with the remaining arguments via C<< goto &code; >>.
87              
88             If no row with a matching name exists, an
89             error is raised.
90              
91             =cut
92              
93             sub install_and_invoke {
94 3     3 1 12 my ($package,$name) = splice @_,0,2;
95              
96 3         22 my $code = $package->load_code($name);
97 3 50       12 if (defined $code) {
98 3         170 goto &$code;
99             } else {
100 0         0 croak "Undefined subroutine $package\::$name called";
101             };
102             };
103              
104             =head2 C<< __PACKAGE__->update_code >>
105              
106             Overridden to do lazy updates. It wipes all code that
107             is out of date from the namespace and lets the AUTOLOAD
108             handler sort out the reloading.
109              
110             =cut
111              
112             sub update_code {
113 1     1 1 587 my ($package) = @_;
114              
115 1   50     5 my $version = $package->code_version || 0;
116 1         15 my $sth = $package->dbh->prepare_cached(sprintf <<'SQL', $package->code_history);
117             SELECT distinct name,version FROM %s
118             WHERE version > ?
119             ORDER BY version DESC
120             SQL
121              
122 1         206 $sth->execute($version);
123              
124             # If update is needed, wipe the touched elements:
125 1         2 my %seen;
126              
127 1   50     7 my $current_version = $version || 0;
128 1         14 while (my ($name,$new_version) = $sth->fetchrow()) {
129 1 50       6 next if $seen{$name}++;
130            
131 1 50       4 $current_version = $current_version < $new_version
132             ? $new_version
133             : $current_version;
134              
135 1         5 delete $package->code_source->{$name};
136              
137             # This manual AUTOLOAD is less than ideal
138 4     4   24 no strict 'refs';
  4         7  
  4         119  
139 4     4   19 no warnings 'redefine';
  4         6  
  4         1381  
140 1         18 *{"$package\::$name"} = sub {
141 1     1   14 local *AUTOLOAD = "$package\::$name";
142 1         2 goto &{"$package\::AUTOLOAD"};
  1         10  
143 1         13 };
144             # = sub { $package->install_and_invoke( $name, @_ ); };
145             }
146 1         4 $package->code_version($current_version);
147             };
148              
149             =head2 C<< __PACKAGE__->load_code NAME >>
150              
151             Retrieves the code for the subroutine C
152             from the database and calls
153             C<< __PACKAGE__->install_code $name,$code >>
154             to install it.
155              
156             =cut
157              
158             sub load_code {
159 3     3 1 6 my ($package,$name) = @_;
160              
161 3         14 my $code = $package->retrieve_code($name);
162 3 50       12 if (! defined $code) {
163             # let caller decide whether to croak or to ignore
164 0         0 return;
165             };
166 3         34 $package->create_sub($name,$code);
167             };
168              
169             =head2 C<< __PACKAGE__->retrieve_code NAME >>
170              
171             Retrieves the code for the subroutine C
172             from the database and returns it as a string.
173              
174             =cut
175              
176             sub retrieve_code {
177 6     6 1 15 my ($package,$name) = @_;
178              
179 6         62 my $sql = sprintf <<'SQL', $package->code_live;
180             SELECT code FROM %s
181             WHERE name = ?
182             SQL
183              
184 6         73 my $sth = $package->dbh->prepare_cached($sql);
185 6 50       737 if (! $sth->execute($name)) {
186             # let caller decide whether to croak or to ignore
187 0         0 return;
188             }
189 6         57 my($code) = $sth->fetchrow;
190 6         28 $sth->finish;
191              
192 6         16 return $code
193             };
194              
195             =head1 INSTALLED CODE
196              
197             =head2 C<< AUTOLOAD >>
198              
199             An AUTOLOAD handler is installed to manage the loading
200             of code that has not been retrieved from the database
201             yet. If another AUTOLOAD handler already exists,
202             the AUTOLOAD handler is not installed and a warning
203             is issued.
204              
205             =cut
206              
207             1;
208              
209             =head1 BUGS
210              
211             =over 4
212              
213             =item * Currently, if a routine gets changed, the AUTOLOAD
214             handler is not fired directly but by using a callback. This
215             is because I couldn't delete the typeglob properly such
216             that the AUTOLOAD fires again.
217              
218             =back
219              
220             =head1 AUTHOR
221              
222             Max Maischein, Ecorion@cpan.orgE
223              
224             =head1 LICENSE
225              
226             This module is licensed under the same terms as Perl itself.
227              
228             =cut
229