File Coverage

blib/lib/Class/Runtime.pm
Criterion Covered Total %
statement 87 96 90.6
branch 22 34 64.7
condition 10 29 34.4
subroutine 13 14 92.8
pod 8 10 80.0
total 140 183 76.5


line stmt bran cond sub pod time code
1             =pod
2              
3             =head1 NAME
4              
5             Class::Runtime - API for dynamic class loading/unloading/status
6              
7             =head1 DEPENDENCIES
8              
9             =over 4
10              
11             =item *
12              
13             Symbol
14              
15             =item *
16              
17             File::Spec
18              
19             =back
20              
21             =head1 INSTALLATION
22              
23             To install this module type the following:
24              
25             =over 2
26              
27             =item *
28              
29             perl Makefile.PL
30              
31             =item *
32              
33             make
34              
35             =item *
36              
37             make test
38              
39             =item *
40              
41             make install
42              
43             =back
44              
45             =head1 OVERVIEW
46              
47             Class for dynamically loading/unloading/stat on modules. Currently
48             it is designed for loading a class local to the system at runtime. Future
49             versions may include loading in a distributed environment.
50              
51             A specific search path can be associated with the object which will be
52             'unshifted' onto @INC before attempting to load the class and 'shifted'
53             off after attempting to load.
54              
55             Also, a class can be checked whether it is loaded or not in the process.
56              
57             =head1 SYNOPSIS
58              
59             my $class = 'MyClass::MySubClass';
60             my $obj = Class::Runtime->new( class=> $class );
61              
62             ## LOADING CLASS AT RUNTIME
63             unless ( $cl->load ) {
64             warn "Error in loading class\n";
65             warn "\n\n", $@, "\n\n" if DEBUG;
66             }
67              
68             ## CHECKING FOR CLASS AVAILABILITY AT RUNTIME
69             unless ( $cl->isLoaded ) {
70             warn 'Class - ', $class, ' - is loaded', "\n";
71             }
72              
73             my $newPath;
74             ## ADDING SEACH PATH TO OBJECT
75             ## Multiple
76             $newPath = $cl->addPath( path=> [ qw( /tmp/lib /tmp/lib2 ) ] );
77            
78             ##OR Single
79             $newPath = $cl->addPath( path=> '/tmp/lib' );
80              
81             ## REMOVING SEARCH PATH FROM OBJECT
82             ## Multiple
83             $newPath = $cl->dropPath( path=> [ qw( /tmp/lib /tmp/lib2 ) ] );
84            
85             ##OR Single
86             $newPath = $cl->dropPath( path=> '/tmp/lib' );
87              
88             ## GETTING PATH ASSOCIATED WITH OBJECT
89             my @path = $cl->getPath;
90              
91             ## INVOKING METHOD
92             my $method = 'new';
93             if ( $cl->isLoaded and $class->can( 'new' ) ) {
94             my $obj = $cl->invoke( 'new', arg1=> 1, arg2=> 2 );
95             $obj->method2;
96             }
97              
98             ## NOT NECESSARY AS ONCE CLASS HAS BEEN LOADED CAN INVOKE DIRECTLY
99             if ( $cl->isLoaded and $class->can( 'new' ) ) {
100             my $obj = $class->new( arg1=> 1, arg2=> 2 );
101             $obj->method2;
102             }
103              
104             ## UNLOADING CLASS
105             if ( $cl->isLoaded ) {
106             $cl->unload or warn 'Unable to unload class - ', $class, "\n";
107             }
108            
109             =head1 METHODS
110              
111             =cut
112             package Class::Runtime;
113              
114             require 5.005;
115              
116 1     1   768 use strict;
  1         2  
  1         33  
117              
118 1     1   844 use Symbol ();
  1         914  
  1         23  
119 1     1   13 use File::Spec ();
  1         2  
  1         588  
120              
121             $Class::Runtime::VERSION = '0.2';
122              
123             =pod
124              
125             =head2 new B
126              
127             Creates new object and initializes member variables if
128             passed in as arguments. Takes parameterized argument list.
129              
130             =over 2
131              
132             =item Input
133              
134             =over 2
135              
136             =item *
137              
138             class => name of class to dynamically load
139              
140             =back
141              
142             =item Output
143              
144             =over 2
145              
146             =item *
147              
148             Class::Runtime object
149              
150             =back
151              
152             =back
153              
154             =cut
155             sub new {
156 1     1 1 70 my $class = shift;
157 1         3 my $param = { @_ };
158 1   33     4 my $loadClass = $param->{'class'} || do {
159             warn __PACKAGE__ . " object construction requires parameter 'class'\n";
160             return;
161             };
162              
163 1         5 return bless {
164             class_=> $loadClass,
165             path_=> [],
166             }, $class;
167             }
168              
169             sub name {
170 0     0 0 0 my $obj = shift;
171 0         0 return $obj->{'class_'};
172             }
173              
174             =pod
175              
176             =head2 getPath
177              
178             Method used to retrieve path associated with this object
179              
180             =over 2
181              
182             =item Input
183              
184             =over 2
185              
186             =item *
187              
188             None
189              
190             =back
191              
192             =item Output
193              
194             =over 2
195              
196             =item *
197              
198             array of paths
199              
200             =item *
201              
202             integer 0 if no paths exist
203              
204             =back
205              
206             =back
207              
208             =cut
209             sub getPath {
210 2     2 1 2 my $obj = shift;
211              
212 2         5 @{ $obj->{'path_'} } ?
  2         7  
213 2 50       2 return @{ $obj->{'path_'} } :
214             return 0;
215             }
216              
217             =pod
218              
219             =head2 addPath
220              
221             Method used to add path to object path list to search from
222              
223             =over 2
224              
225             =item Input
226              
227             =over 2
228              
229             =item *
230              
231             path => As a single string or as a reference to an array
232              
233             =back
234              
235             =item Output
236              
237             =over 2
238              
239             =item *
240              
241             array of paths
242              
243             =item *
244              
245             undef if error
246              
247             =back
248              
249             =back
250              
251             =cut
252             sub addPath {
253 2     2 1 58 my $obj = shift;
254 2         4 my $param = { @_ };
255 2   33     6 my $path = $param->{'path'} || do {
256             warn "Method 'dropPath' requires argument 'path'\n";
257             return;
258             };
259              
260 2 100       5 if ( ref($path) eq 'ARRAY' ) {
261 1         2 foreach my $incPath ( @INC ) {
262 11         20 for ( my $i = 0; $i < @$path; ++$i ) {
263 33 50       72 if ( $incPath eq $path->[$i] ) {
264 0         0 splice @$path, $i, 1
265             }
266             }
267             }
268             } else {
269 1         3 for ( my $i = 0; $i < @INC; ++$i ) {
270 11 50       24 if ( $path eq $INC[$i] ) {
271 0         0 $path = undef;
272             }
273             }
274             }
275              
276 2 50       22 if ( defined $path ) {
277 2 100       2 push @{ $obj->{'path_'} }, ref($path) eq 'ARRAY' ? @$path : $path;
  2         9  
278 2         2 return @{ $obj->{'path_'} };
  2         6  
279             } else {
280 0         0 return;
281             }
282             }
283              
284             =pod
285              
286             =head2 dropPath
287              
288             Method used to remove path from object search path
289              
290             =over 2
291              
292             =item Input
293              
294             =over 2
295              
296             =item *
297              
298             path=> As a single string or as a reference to an array
299              
300             =back
301              
302             =item Output
303              
304             =over 2
305              
306             =item *
307              
308             array of paths
309              
310             =item *
311              
312             undef if error
313              
314             =back
315              
316             =back
317              
318             =cut
319             sub dropPath {
320 2     2 1 87 my $obj = shift;
321 2         4 my $param = { @_ };
322 2   33     5 my $path = $param->{'path'} || do {
323             warn "Method 'dropPath' requires argument 'path'\n";
324             return;
325             };
326              
327 2 50       4 return unless defined $obj->getPath;
328              
329 2         3 my @curPath = @{ $obj->{'path_'} };
  2         5  
330 2 100       4 if ( ref($path) eq 'ARRAY' ) {
331 1         2 foreach my $dropPath ( @$path ) {
332 3         5 for ( my $i = 0; $i < @curPath; ++$i ) {
333 4 100       9 if ( $dropPath eq $curPath[$i] ) {
334 3         7 splice @curPath, $i, 1
335             }
336             }
337             }
338             } else {
339 1         3 for ( my $i = 0; $i < @curPath; ++$i ) {
340 3 100       8 if ( $path eq $curPath[$i] ) {
341 1         4 splice @curPath, $i, 1;
342             }
343             }
344             }
345 2         5 $obj->{'path_'} = \@curPath;
346 2         6 return @curPath;
347             }
348              
349              
350             =pod
351              
352             =head2 isLoaded
353              
354             Method used to check whether given class is loaded.
355              
356             =over 2
357              
358             =item Input
359              
360             =over 2
361              
362             =item *
363              
364             None
365              
366             =back
367              
368             =item Output
369              
370             =over 2
371              
372             =item *
373              
374             1 if loaded
375              
376             =item *
377              
378             0 if not loaded
379              
380             =back
381              
382             =back
383              
384             =cut
385             sub isLoaded {
386 2     2 1 142 my $obj = shift;
387 2         27 my $param = { @_ };
388 2   33     10 my $class = $obj->{'class_'} || do {
389             warn __PACKAGE__ . " object is not initialized with class name\n";
390             return;
391             };
392              
393 2 50       18 $class =~ /^(.*::)(\w+)/ if ( $class =~ /::/ );
394 2   50     9 my $base = $1 || 'main::';
395 2   33     9 my $tail = ( $2 || $class ) . '::';
396              
397             {
398 1     1   5 no strict 'refs';
  1         2  
  1         505  
  2         3  
399 2 100       3 exists ${ $base }{ $tail } ?
  2         16  
400             return 1 :
401             return 0;
402             }
403              
404             }
405              
406             =pod
407              
408             =head2 load
409              
410             Method used to load library/class. If a path has been
411             associated with this object it will be 'unshifted' onto
412             the global @INC array. Immediately after the attempted
413             load the paths 'unshifted' onto the @INC array will be
414             'spliced' out. This is done so as to prevent any wrongful
415             modification of @INC since the loading library may modify
416             @INC or perhaps some other code.
417              
418             =over 2
419              
420             =item Input
421              
422             =over 2
423              
424             =item *
425              
426             None
427              
428             =back
429              
430             =item Output
431              
432             =over 2
433              
434             =item *
435              
436             1 on successful load
437              
438             =item *
439              
440             undef if error (setting $@)
441              
442             =back
443              
444             =back
445              
446             =cut
447             sub load {
448 1     1 1 39 my $obj = shift;
449 1         2 my $param = { @_ };
450 1   33     3 my $class = $obj->{'class_'} || do {
451             warn __PACKAGE__ . " object is not initialized with class name\n";
452             return;
453             };
454              
455 1         1 my $loadPath = @{ $obj->{'path_'} };
  1         2  
456 1         24 my $file = File::Spec->catfile( split '::', $class ) . '.pm';
457              
458 1 50       4 unshift @INC, @{ $obj->{'path_'} } if $loadPath;
  0         0  
459 1         2 eval { require $file; };
  1         785  
460 1         66606 $obj->cleanINC_;
461              
462 1 50       10 $@ ? return : return 1;
463             }
464              
465             =pod
466              
467             =head2 unload
468              
469             Method used to unload class/library
470              
471             =over 2
472              
473             =item Input
474              
475             =over 2
476              
477             =item *
478              
479             None
480              
481             =back
482              
483             =item Output
484              
485             =over 2
486              
487             =item *
488              
489             1 on successful unload
490              
491             =item *
492              
493             undef if error
494              
495             =back
496              
497             =back
498              
499             =cut
500             sub unload {
501 1     1 1 283 my $obj = shift;
502 1         2 my $param = { @_ };
503 1   33     14 my $class = $obj->{'class_'} || do {
504             warn __PACKAGE__ . " object is not initialized with class name\n";
505             return;
506             };
507 1 50       4 return if $class eq __PACKAGE__;
508              
509 1         4 Symbol::delete_package($class);
510 1         186 my $file = File::Spec->catfile( split '::', $class ) . '.pm';
511 1 50       6 delete $INC{$file} if exists $INC{$file};
512              
513 1         3 return 1;
514              
515             }
516              
517             =pod
518              
519             =head2 invoke
520              
521             Method used to load class/library and call specific method with that library.
522              
523             =over 2
524              
525             =item Input
526              
527             =over 2
528              
529             =item *
530              
531             name of method
532              
533             =item *
534              
535             remaining list of arguments to pass off to invoked method
536              
537             =back
538              
539             =item Output
540              
541             =over 2
542              
543             =item *
544              
545             value of returned method call
546              
547             =back
548              
549             =back
550              
551             =cut
552             sub invoke {
553 1     1 1 62 my $obj = shift;
554 1   33     7 my $class = $obj->{'class_'} || do {
555             warn __PACKAGE__ . " object is not initialized with class name\n";
556             return;
557             };
558 1   33     3 my $method = shift || do {
559             warn "First argument to 'invoke' needs to be valid method name\n";
560             return;
561             };
562              
563 1         12 return $class->$method( @_ );
564             }
565              
566             sub cleanINC_ () {
567 1     1 0 2 my $obj = shift;
568              
569 1         3 my @curPath = @{ $obj->{'path_'} };
  1         5  
570 1         3 foreach my $dropPath ( @curPath ) {
571 0         0 for ( my $i = 0; $i < @INC; ++$i ) {
572 0 0       0 if ( $dropPath eq $INC[$i] ) {
573 0         0 splice @INC, $i, 1
574             }
575             }
576             }
577 1         2 return 1;
578             }
579              
580             1;
581              
582             __END__