File Coverage

blib/lib/App/Modular.pm
Criterion Covered Total %
statement 105 187 56.1
branch 30 84 35.7
condition 1 12 8.3
subroutine 17 21 80.9
pod 14 14 100.0
total 167 318 52.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             #----------------------------------------------------------------------------
3             # App::Modular - perl program modularization framewok
4             # App::Modular.pm: module management class
5             #
6             # Copyright (c) 2003-2004 Baltasar Cevc
7             #
8             # This code is released under the L Perl Artistic
9             # License, which can should be accessible via the C
10             # perlartistic> command and the file COPYING provided with this
11             #
12             # DISCLAIMER: THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND
13             # COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
14             # IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY
15             # OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE
16             # OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
17             # TRADEMARKS OR OTHER RIGHTS.
18             # IF YOU USE THIS SOFTWARE, YOU DO SO AT YOUR OWN RISK.
19             #
20             # See this internet site for more details: http://technik.juz-kirchheim.de/
21             #
22             # Creation: 02.12.03 bc
23             # Last Update: 06.04.08 bc
24             # Version: 0. 1. 3
25             # ----------------------------------------------------------------------------
26              
27             ##################################
28             ## PRAGMA/DEPS ##
29             ##################################
30 6     6   5481 use strict;
  6         13  
  6         505  
31 6     6   98 use warnings;
  6         11  
  6         180  
32 6     6   224 use 5.006_001;
  6         21  
  6         309  
33              
34             package App::Modular;
35 6     6   33 use Carp;
  6         9  
  6         660  
36 6     6   31 use base qw(Class::Singleton);
  6         10  
  6         7997  
37              
38             ##################################
39             ## VERSION ##
40             ##################################
41             our ($VERSION);
42             $VERSION = 0.001_003;
43              
44             ##################################
45             ## METHODS ##
46             ##################################
47             ### new_instance
48             # only one instance of App::Modular should exist in a running program,
49             # so we use singleton
50             # => this is our "new" function which initializes the variables
51             # however, the program should only use "..=instance App::Modular;"
52             # to get the object, Class::Singleton will initialize everything
53             # when and only if needed
54             sub _new_instance {
55 6     6   281 my ($type) = @_;
56 6         22 my $self = bless { }, $type;
57              
58 6         49 $self->{'modules'} = {}; # hash modulename => object
59 6         17 $self->{'modules_files'} = {};; # hash modulename => source file
60 6         16 $self->{'dependencies'} = {};; # hast modulename => /-separated list
61             # of modules the module depends on
62 6         15 $self->{'debuglevel'} = 1; # (default) verbose level
63 6         17 $self->{'debugtrace'} = 0; # print stack trace with debug output
64 6         19 $self->{'moduledir'} = ''; # directory containing the mods
65 6         16 $self->{'moduleext'} = '.mom'; # extension of the module files
66 6         17 $self->{'autoload'} = 0; # automatically load module when
67             # it is accessed vi
68             # $modularizer->module{'name]}
69              
70 6         24 $self;
71             };
72              
73             ### mlog (modularizer logging/debugging)
74             # modularizer standarized log routine, should be used for debugging
75             # by any modularizer module
76             # depending of the trace setting, we use carp or cluck (output with or
77             # without a stack backtrace)
78             sub mlog {
79 234     234 1 456 my ($self, $level, @text) = @_;
80 234 50       779 if ($level < $self->{'debuglevel'}) {
81 0 0       0 unless ($self->{'debugtrace'}) {
82 0         0 Carp::carp (join(" ",@text));
83             } else {
84 0         0 Carp::cluck (join(" ",@text));
85             }
86             }
87             };
88              
89             ### loglevel (set modularizer logging/debugging level)
90             # set the level of debbuging output, 0 shows only critical errors, -1
91             # nothing, levels are up to 100 which shows every detail
92             sub loglevel {
93 2     2 1 17 my ($self, $level) = @_;
94 2 50       9 if (defined $level) {
95 2         3 ($self->{'debuglevel'} = $level);
96 2         16 $self->mlog (99, "setting log level from $self->{'debuglevel'}".
97             " to $level");
98             }
99 2         0 return $self->{'debuglevel'};
100             };
101              
102             ### logtrace (enable/disable stack backtrace on debug output)
103             sub logtrace {
104 0     0 1 0 my ($self, $trace) = @_;
105 0 0       0 ($self->{'debugtrace'} = $trace) if (defined $trace);
106 0         0 return $self->{'debugtrace'};
107             };
108              
109             ### module_register (load a module, create an instance and save a
110             ### reference to it)
111             # find a module (if needed) and register it in the local vars
112             # note: if you use a nested namespace as Input::SQL, use :: to separate the
113             # levels
114             # any module name containing a slash will be assumed to be a file name!
115             sub module_register {
116 18     18 1 54 my ($self, $module, $nodepends) = @_;
117 18         25 my ($modfile, $modfile2, $modfile3,
118             @dependencies, $dep, $instance, $err);
119              
120             # check if called correctly
121 18 50       90 unless ($module) {
122 0         0 $self->mlog (-1, "module_register(): you must specify a module ".
123             "to register");
124 0         0 return undef;
125             };
126            
127             # check if the module has yet been loaded (in that case, just return
128             # a positive status code (success)
129 18 50       44 if ($self->module_isloaded($module)) {
130 0         0 $self->mlog (90,"module_register($module):".
131             "cannot load a module twice");
132 0         0 return 1;
133             };
134            
135             # check if module exists and is readable
136 18 50       72 unless ($module =~ m"/") {
137 18 50       49 unless ( $self->{'module_dir'} ) {
138 0         0 $self->mlog(-1, "module load: module directory not defined");
139 0         0 return undef;
140             };
141 18 50       358 unless ( -d $self->{'module_dir'} ) {
142 0         0 $self->mlog(-1, "module load: module directory '".
143             $self->{'module_dir'}."' does not exist");
144 0         0 return undef;
145             };
146 18 50       61 unless ( defined $self->{'module_ext'} ) {
147 0         0 $self->mlog(-1, "module load: module extension not defined");
148 0         0 return undef;
149             };
150             # modfile: complete path name to module file, was: perl package name
151             # modfile2: file name relative to module directory
152             # modfile3: file name relative to module dir, changed ext to .pm
153            
154 18         62 $modfile = $module;
155 18         43 $modfile =~ s/::/\//g;
156 18         45 $modfile2 = "App/Modular/module/$modfile".$self->{'module_ext'};
157 18         38 $modfile3 = "App/Modular/module/$modfile.pm";
158 18         51 $modfile = $self->{'module_dir'}.$modfile.
159             $self->{'module_ext'};
160             } else {
161 0         0 $modfile = $module;
162 0         0 $module = substr $modfile, length($self->{'module_dir'}),
163             rindex($modfile, $self->{'module_ext'})
164             -length($self->{'module_dir'});
165 0         0 $module =~ s/\//::/g;
166             };
167 18         84 $self->mlog(99, "set module file for '$module' to '$modfile'");
168 18 50       335 if ( -r $modfile) {
169             # the module file was specified (the normal case)
170             # => we will load it and create an instance
171 18         1351 $instance = eval "do ('$modfile') && return ".
172             "(module_init App::Modular::Module::$module);";
173 18 50       191 unless ($instance) {
174 0         0 $self->mlog(1, "read module from '$modfile', however, init ".
175             "failed: $@");
176 0         0 return undef;
177             } else {
178 18         82 $self->mlog(99, "read module $module from '$modfile'");
179             }
180             } else {
181             # the module file was not specified or is not readable
182             # we will fall back to the standard perl way of finding modules
183             # in hope that will get the thing loaded.
184 0         0 $self->mlog (99, "module not found in module directory, falling ".
185             "back to @INC for search");
186 0         0 $instance = eval "do ('$modfile2') && return ".
187             "(module_init App::Modular::Module::$module);";
188 0 0 0     0 if ($@ || ! $instance) {
189 0 0       0 unless ($instance) {
190 0         0 $err = $@;
191 0 0       0 $self->mlog (0,
    0          
192             "unable to locate module $module via '".
193             "$modfile3' (at '$modfile')\n".
194             ($err ? "$err\n" : '') .
195             ($@ ? "$@" : '')
196             );
197 0         0 return undef;
198             };
199             }
200             };
201             # load and init App::Modular::module::$module);";
202 18         63 $self->mlog (60,"registering module $module");
203              
204             # now we have the module file, name and instance
205             # => register the module in our data structure
206 18         81 $self->mlog(99, "module $module loaded as $instance");
207 18         53 $self->{'modules'}{$module} = $instance;
208 18         45 $self->{'modules_files'}{$module} = $modfile;
209              
210             # find module dependencies and load modules if needed
211 18         931 $dep = eval "return \$instance->module_depends()";
212 18 100       76 if ($dep) {
213 4         14 @dependencies = split('/',$dep);
214 4         7 foreach $dep (@dependencies) {
215             # load the modules needed
216 4 50       14 if (!$self->module_isloaded($dep)) {
217 4         24 $self->module_register($dep);
218             };
219 4         19 $self->{'dependencies'}{$dep} .= '/'.$module;
220             };
221             };
222 18         64 return $self->{'modules'}->{$module};
223             };
224              
225             ### module_isloaded (boolean: have we loaded and instanciated the mod?)
226             sub module_isloaded {
227 78     78 1 114 my ($self, $module) = @_;
228 78 50       158 unless ($module) {
229 0         0 $self->mlog(0, "module_isloaded: no module specified");
230 0         0 return undef;
231             };
232 78         361 $self->mlog(99, "getting status of module '$module'");
233 78 100       317 return ($self->{'modules'}{$module} ? 1 : 0);
234             };
235              
236             ### module_deregister (unload a module, removing all references)
237             sub module_deregister {
238 8     8 1 25 my ($self,$module) = @_;
239 8         26 $self->mlog (60,"deregistering module '$module'");
240 8         27 $self->mlog (99,"unloading module '$module'");
241 8         48 delete ($self->{'modules'}{$module});
242 8         26 delete ($self->{'modules_files'}{$module});
243             };
244              
245             ### module_deregister_all (call module_deregister for all loaded mods)
246             sub modules_deregister_all {
247 2     2 1 29 my ($self,$module) = @_;
248 2         5 foreach $module (keys %{$self->{'modules'}}) {
  2         20  
249 6         16 $self->module_deregister ($module);
250             };
251             };
252              
253             ### modules (return all loaded modules mathing a given pattern or all when no
254             ### pattern is given)
255             sub modules {
256 2     2 1 12 my ($self, $pattern) = @_;
257 2 50       8 $pattern = ".*" unless ($pattern);
258              
259 2         4 return grep { /$pattern/ } keys ( %{$self->{'modules'}});
  0         0  
  2         11  
260             };
261              
262             ### modules_list (print a list of loaded modules to mlog)
263             sub modules_list {
264 0     0 1 0 my ($self, $pattern) = @_;
265 0         0 my ($module, $module_name, $module_file, $outputstring);
266              
267 0         0 $outputstring = "currently loaded modules:\n";
268 0         0 foreach $module_name ($self->modules ($pattern)) {
269 0         0 $module_file = ${$self->{'modules_files'}}{$module_name};
  0         0  
270 0         0 $outputstring .= " - $module_name: $module_file\n";
271             };
272 0         0 $self->mlog(-1, $outputstring);
273             };
274              
275             ### modules_register_all (load all available modules at once)
276             # autoload all modules at once (if recursive is set, descend to subdirs)
277             sub modules_register_all {
278 0     0 1 0 my ($self, $recursive, $mdir, $mext, $internal) = @_;
279 0         0 my ($dirhandle, $file, @modfiles);
280              
281             # we do not register all modules, unless autoload is available
282             # to handle the dependencies
283 0 0       0 unless ($self->module_autoload()) {
284 0         0 $self->mlog(1,"please switch module_autoload on before trying to".
285             " auto-register all modules");
286 0         0 return undef;
287             };
288              
289             # use the default module directory and extension if none is given
290 0 0       0 ($mdir = $self->module_directory() ) unless ($mdir);
291 0 0       0 ($mext = $self->module_extension() ) unless ($mext);
292 0 0       0 $mdir .= '/' unless ($mdir =~ /\/$/); # fix the path a bit
293            
294 0 0       0 unless (opendir ($dirhandle, $mdir)) {
295 0         0 $self->mlog(-1, "modules_register_all(): cannot open ".
296             "module directory $mdir");
297 0         0 return undef;
298             };
299              
300             # find module files
301 0         0 foreach $file (readdir ($dirhandle)) {
302 0 0       0 next if ($file =~ /^\./);
303 0 0 0     0 if ( -f $mdir.$file && -r $mdir.$file ) {
    0 0        
304 0 0       0 if (length($file) - length($mext)
305             == rindex $file, $mext) {
306 0         0 push @modfiles, $mdir.$file;
307             };
308             } elsif ($recursive && -d $mdir.$file) {
309 0         0 @modfiles = ( @modfiles,
310             $self->modules_register_all($recursive,
311             $mdir.$file, $mext, 1) );
312             };
313             };
314 0         0 $self->mlog(99, "finished searching modules (found '"/
315             (join "', '", @modfiles)."')");
316 0 0       0 closedir ($dirhandle) || $self->mlog(-1, "cannot close dir $mdir");
317              
318             # some more debugging if called by an "external"
319 0 0       0 unless ($internal) {
320 0         0 foreach $file (@modfiles) {
321 0         0 $self->mlog(20, "modules_register_all: autoload $file");
322 0         0 $self->module_register($file, 'nodepends');
323             };
324             };
325              
326             # return all modules loaded
327 0         0 return @modfiles;
328             };
329              
330             ### module_autoload ((de)activate autoloading of modules when
331             ### $modularizer->module($name) is called)
332             # switch module autoload on/off
333             sub module_autoload {
334 8     8 1 36 my ($self, $value) = @_;
335            
336 8 100       33 ($self->{'autoload'} = $value) if (defined $value);
337 8 50 33     57 unless ( ($self->{'module_dir'}) && ($self->{'module_ext'} ) ) {
338 0         0 $self->mlog(99,"module_autoload: will only autoload when I'll have ".
339             "'module_directory' and 'module_extension' set!");
340 0         0 return 2;
341             };
342 8         22 return $self->{'autoload'};
343             };
344              
345             ### module_directory (get or set the directory containing the mods)
346             sub module_directory {
347 8     8 1 52 my ($self, $moduledir) = @_;
348              
349 8 100       24 if ($moduledir) {
350 4 50       31 $moduledir .= '/' unless ($moduledir =~ /\/$/);
351 4         11 $self->{'module_dir'} = $moduledir;
352 4         23 $self->mlog(80, "set module directory to $moduledir");
353             } else {
354 4         16 return $self ->{'module_dir'};
355             };
356             };
357              
358             ### module_extension (get or set the extension for module files)
359             sub module_extension {
360 8     8 1 45 my ($self, $moduleext) = @_;
361              
362 8 100       20 if ($moduleext) {
363 4         12 $self -> {'module_ext'} = $moduleext;
364 4         25 $self->mlog(80, "set module extension to $moduleext");
365             } else {
366 4         16 return $self ->{'module_ext'};
367             };
368             };
369              
370             ### module (return a reference to the loaded instance of a module,
371             ### undef on error or when module not loaded and autoload=0)
372             sub module {
373 44     44 1 147 my ($self,$module_name,$noautoload)=@_;
374 44 100       103 if ($self->module_isloaded($module_name)) {
375             # just return a reference to the module object if loaded
376            
377 34         39 return ${$self->{'modules'}}{$module_name};
  34         180  
378             } else {
379             # else we have to check if we can load the module. If yes, we do that and return
380             # it, otherwise we fail *return undef)
381 10 50       28 if ($self->{'autoload'}) {
382 10 50       24 if ($noautoload) {
383             # autoloading is enabled -> check if we can load
384 0         0 $self->mlog(5, "module autoload temporarily disabled");
385 0         0 return undef;
386             } else {
387 10         36 $self->mlog(20, "autoloading module $module_name");
388 10         29 $self->module_register($module_name);
389 10 50       27 if ($self->module_isloaded($module_name)) {
390 10         43 return $self->module($module_name);
391             } else {
392 0           $self->mlog(0, "ERROR: autoload of module $module_name ".
393             "failed.");
394 0           return undef;
395             };
396             };
397             } else {
398             # autoload disabled -> return undef as the module is not loaded yet (programmer
399             # should have it loaded manually)
400 0           $self->mlog (0,"module $module_name is not loaded");
401 0           return undef;
402             };
403             };
404             };
405              
406             ### DESTROY (desturctor function which will unload all modules)
407             sub DESTROY {
408 0     0     my ($self) = @_;
409 0           my ($module);
410             my (@loaded_modules);
411              
412 0           @loaded_modules = keys %{$self->{'modules'}};
  0            
413              
414 0 0         if ($#loaded_modules > 0) {
415              
416 0           $self->mlog(99, "App::Modular is going to be destroyed, ".
417             "modules left to destroy");
418 0           foreach $module (@loaded_modules) {
419 0           $self->mlog(99, " -> $module");
420             }
421              
422 0           $self->modules_deregister_all();
423              
424             } else {
425 0           $self->mlog(99, "App::Modular finishing, no modules left to unload");
426             }
427 0           return;
428             };
429              
430             # return with something well-defined
431             1;
432              
433             ##################################
434             ## DOCUMENTATION ##
435             ##################################
436             =pod
437              
438             =head1 NAME
439              
440             B - modularization framework for perl programs
441              
442             =head1 SYNOPSIS
443              
444             package App::Modular::Module::Test;
445              
446             use base qw(App::Modular::Module);
447              
448             sub say_hello {
449             print "Hello, dear user!";
450             };
451              
452              
453              
454             package main;
455              
456             use App::Modular;
457              
458             my $modul = instance App::Modular;
459              
460             $modul->module('Test')->say_hello();
461              
462             exit;
463              
464             =head1 DESCRIPTION
465              
466             App::Modular aims to provide a framework which should it make very
467             easy to programmes to create any kind of modular program.
468              
469             It supports:
470              
471             =over 4
472              
473             =item * module dependency solving
474              
475             =item * autoloading of modules
476              
477             =item * event handling (implemented as a contributed App::Modular module)
478              
479             =back
480              
481             =head1 USAGE
482              
483             The usage description is split into two parts, one describing what the
484             main program has to do in order to work with App::Modular, one describing
485             how to create a module. The explanation is based on an example; I
486             suggest you to try to build a little modular script yourself and you'll
487             soon understand how App::Modular works.
488             First, we will create a little module that we'll use in the main program
489             to greet the user.
490              
491             =head2 A sample Module
492              
493             Modules come in the form of perl modules; however, they are not expected
494             to be in one of the inlcude (@INC) directories, but rather in a specific
495             directory like "/usr/local/lib/app-modular/sample". Their extension does
496             not default to ".pm" but to ".mom" (App::Modular Module).
497              
498             Every module should have C as a base class, as it
499             inherits some basic methods then automatically. As a package namespace,
500             you MUST use C, as App::Modular converts the
501             package/file name in a way that would brake otherwise.
502              
503             But now, that's enough talking - let's proceed to some real code:
504              
505             #!/usr/bin/perl -w
506             # File: Printer.mom
507             use strict;
508              
509             package App::Modular::Module::Printer;
510              
511             use base qw(App::Modular::Module);
512              
513             sub printer {
514             shift;
515             App::Modular->instance()->mlog(99, "printer printing!");
516             print(join ' ', @_);
517             };
518              
519             1;
520              
521             As you will have noticed, the module only provides one method - a method
522             to print a string or an array to stdout. That's not really much. Anyway,
523             it's enough for our first test: we can see some action.
524              
525             =head2 Main Program
526              
527             Now we just need some work for our little bet... Here it comes:
528              
529             #!/usr/bin/perl -w
530             # File: AppModularSample.pl
531             use strict;
532            
533             package main;
534            
535             use App::Modular 0.001_001;
536            
537             my $mod = instance App::Modular;
538            
539             $mod -> module_directory ('.');
540             $mod -> module_extension ('.mom');
541              
542             $mod -> module('Printer') -> printer ('Hello,' 'world!', 'How are you?');
543              
544             =head2 Interdependant Modules
545              
546             Now that we know how to write a simple module, we can advance to some
547             more complicated.
548              
549             !!!FIXME!!! Here should be an example using module dependencies.
550              
551             Meanwhile, see the fererence for App::Modular::Modul->depends() and the bugs
552             section of this document.
553              
554             =head1 REFERENCE
555              
556             In this man page, you will only find the method descriptions fror hte App::Modular
557             object; the standard functions of the application modules can be found in
558             L.
559              
560             =over 4
561              
562             =item instance (void)
563              
564             Returns the one and only instance of App::Modular (inherited from Class::Singleton).
565              
566             =item loglevel (int level)
567              
568             Set the logging level (if the number given here is >= the value given to the
569             logging function mlog, the message will be logged.
570              
571             Return value: (int) current log level
572              
573             =item logtrace (optional bool logtrace)
574              
575             print stack backtrace on debug output? (returns setting, and sets the value if
576             the optional argument is given)
577              
578             Return value: (bool) value of logtrace
579              
580             =item mlog (int level, string text)
581              
582             Do some logging (if the given leven is <= the maximum logging level set before)
583              
584             Note: Depending on the setting of logtrace the messages will either contain a
585             function stack backtrace or not.
586              
587             Return value: void
588              
589             =item module_autoload
590              
591             Set/Get status of autoloading (true => modules will be loaded automatically when needed;
592             false => no module will ever be loaded without the explicit command).
593              
594             Return value: (bool) current setting of autoload
595              
596             =item module_deregister (string module_name_
597              
598             Unload a App::Modular module. (Internally, this function will delete the reference to the
599             module, hence perl's garbage collector will destroy the object)
600              
601             Return value: (void)
602              
603             =item module_directory (string path)
604              
605             Get/set the directory that contains the App::Modular modules.
606              
607             Return value: (string) current setting
608              
609             =item module_extension (string filespec)
610              
611             Get/set the extension that is common to all App::Modular modules (e.g. if the module is named
612             Printer and the file is saved as Printer.mom, the extension is '.mom').
613              
614             Return value: (string) current value
615              
616             =item module_isloaded (string module_name)
617              
618             Is the module named module_name loaded in the system?
619              
620             Return value: (bool) true if loaded
621              
622             =item module_register (string module_name | module_path)
623              
624             Load the module named module_name or from the file named module_path.
625              
626             Return value: undef on failure; reference to the module object on success
627              
628             =item modules ([string regexp_pattern])
629              
630             Returns an array containing the names of all loaded modules. If a pattern is given, only the
631             names mathing it are returned.
632              
633             =item modules_deregister_all (void)
634              
635             Will unload all modules. (Or to be exact, will call module_deregister for every single loaded
636             module).
637              
638             =item modules_list (string regexp_pattern)
639              
640             Print a list of all modules matching pattern (if given) or just all loaded modules (if no pattern
641             was given) to the log.
642              
643             Return value: (void)
644              
645             =item modules_register_all ( [bool recurs, string module_dir, string module_ext ]);
646              
647             Register all modules in module_dir with extension module_ext (the standards are used for
648             these two variables if nothing is given here). If recurs it true, it will recursively walk
649             trough all subdirs, with the effect of loading modules in a nested namespace, too
650             (e.g. Input::Reader, found at $module_dir/Input/Reader$module_ext).
651             Note: module_dir and module_ext will only be valid during this procedure; they
652             will NOT be set as defaults!
653              
654             Return value: (array of strings) names of all modules loaded
655              
656             =item Internal-only use methods
657              
658             =over 8
659              
660             =item _new_instance (create the instance of App::Modular which will be returned by instance())
661              
662             =item DESTROY (cleanup on exit/unload of App::Modular)
663              
664             =back
665              
666             =back
667              
668             =head2 Log levels
669              
670             The modulariyer code usees the following log levels:
671             (in general they are all between 0 and 100)
672              
673             =over 4
674              
675             =item -1 ABSOLUTELY VITAL messages that should never be switched off
676              
677             =item 0 FATAL ERRROR
678              
679             =item 1 ERRORS
680              
681              
682             =item 2 WARNINGS
683              
684             =item 10 information
685              
686             =item 20 notices (more or less unimportant info)
687              
688             =item 80 normal debugging info (external debugging info)
689              
690             =item 99 absolute debug information (system internals)
691              
692             =back
693              
694             =head1 BUGS
695              
696             =over 4
697              
698             =item * Documentation
699              
700             Documentation should be much better, user-friendly and elaborate.
701              
702             =item * Testing
703              
704             This set of modules is tested in a quite limited fashion; I use it in production
705             code, however at the moment of this writing no one else tested it. If you have any
706             reports, positive or negative, I would be pleased to hear about your experiences.
707              
708             =item * Logging
709              
710             The logging mechanism is quite ugly; however, I do not have any idea how a better
711             one could look like - if you have ideas, please contact me.
712              
713             =item * Dependency handling not 100% accurate
714              
715             The pre-requisites of a module are only loaded after the module has been loaded and
716             initialized. This results in the module being unable to call functions of its
717             pre-requisites during initialization.
718              
719             =back
720              
721             =head1 AUTOR
722              
723             (c) 2003-2005 Baltasar Cevc (baltasar A.T. cevc-topp .D.O.T. de)
724              
725             Permission to use this software is granted under the terms of the
726             L Perl Artistic License, which can should be accessible
727             via the C command and the file COPYING provided
728             with this package.
729              
730             B: THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND
731             COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
732             OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE
733             OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
734             TRADEMARKS OR OTHER RIGHTS.
735             IF YOU USE THIS SOFTWARE, YOU DO SO AT YOUR OWN RISK.
736              
737             =head1 SEE ALSO
738              
739             L, L
740              
741             B: L, L, L,
742             L
743              
744             =cut