MAD::Loader - A tiny module loader
version 3.001002
MAD::loader is a module loader and object builder for situations when you want several modules being loaded dynamically.
For each module loaded this way a builder method may be called with or without arguments. You may also control where the loader will search for modules, you may prefix the module names with a custom namespace and you may change how it will behave on getting errors.
## Procedural interface, for handling one module each time use MAD::Loader qw{ fqn load_module build_object }; my $fqn = fqn( 'My::Module', 'My::Prefix' ); # $fqn is 'My::Prefix::My::Module' my $module = load_module( module => 'Bar', prefix => 'Foo', inc => [ 'my/local/lib' ], on_error => \&error_handler, ); # $module is 'Foo::Bar' if Foo::Bar was successfully loaded # error_handler() will be called in case of error my $object = build_object( module => 'Foo::Bar', builder => 'new', args => [ 123, 456 ], on_error => \&error_handler, ); # Foo::Bar must be already loaded # $object = Foo::Bar->new( 123, 456 ); ## OO interface, for handling many modules each time use MAD::Loader; my $loader = MAD::Loader->new( prefix => 'Foo', set_inc => [ 'my/module/dir' ], builder => 'new', args => [ 123, 456 ], on_error => \&error_handler, ); my $loaded = $loader->load( qw{ Bar Etc 123 } ); # Same as: use Foo::Bar; use Foo::Etc; use Foo::123; my $built = $loader->build( qw{ Foo::Bar Foo::Etc Foo::123 } ); # Same as: my $built = { Foo::Bar => Foo::Bar->new( 123, 456 ), Foo::Etc => Foo::Etc->new( 123, 456 ), Foo::123 => Foo::123->new( 123, 456 ), } my $built = $loader->load_and_build( qw{ Bar Etc 123 } ); # Same as: use Foo::Bar; use Foo::Etc; use Foo::123; my $built = { Foo::Bar => Foo::Bar->new( 123, 456 ), Foo::Etc => Foo::Etc->new( 123, 456 ), Foo::123 => Foo::123->new( 123, 456 ), }
This method is used to validate the full name of a $module. If an optional $prefix is given, it will be prepended to the $module before being validated.
$module
$prefix
The fqn is validated against the regular expression in $MODULE_NAME_REGEX which is qr{^[_[:upper:]]\w*(::\w+)*$}.
$MODULE_NAME_REGEX
qr{^[_[:upper:]]\w*(::\w+)*$}
If a valid fqn can not be found then an empty string is returned.
Note that only the non-ascii characters recognized by [:upper:] and \w can be part of the module name or prefix.
[:upper:]
\w
Numbers are valid except for the first character of the fqn.
Tries to load a single module.
Receives as argument a hash containing the following keys:
The module name.
An ArrayRef with the list of directories where to look for the module. This replaces locally the array @INC.
A namespace to prefix the module name. Defaults to ''.
''
An error handler to be executed when found errors. Defaults to \&Carp::croak.
\&Carp::croak
Tries to build an object from a loaded module.
The name of method used to build the object.
An ArrayRef of parameters to be passed to the builder method.
A shortcut for load_module then build_object with some predefined args.
load_module
build_object
inc is set to @INC and c<builder> to 'new'. It is expected to deal only with module, prefix and builder args.
inc
@INC
'new'
Creates a loader object.
You may provide any optional arguments: prefix, builder, args, add_inc, set_inc and on_error.
The namespace that will be prepended to the module names.
The default value is '' (empty string) meaning that no prefix will be used.
my $loader = MAD::Loader->new( prefix => 'Foo' ); $loader->load(qw{ Bar Etc 123 }); ## This will load the modules: ## * Foo::Bar ## * Foo::Etc ## * Foo::123
The name of the method used to create a new object or to initialize the module.
The default value is '' (empty string).
When an builder is defined the loader will try to call it like as a constructor passing the array args as argument.
builder
args
The code below:
my $loader = MAD::Loader->new( builder => 'init', args => [ 1, 2, 3 ], ); $loader->load( 'Foo' ); $loader->build( 'Foo' );
Will cause something like this to occur:
use Foo; Foo->init( 1, 2, 3 );
An ArrayRef with the arguments provided to all builders.
Note that although args is an ArrayRef, it will be passed as an array to builder.
When several modules are loaded together, the same args will be passed to their builders.
An ArrayRef with directories to be prepended to @INC.
The array @INC will be localized before the loader add these directories, so the original state of @INC will be preserved out of the loader.
The default value is undef meaning that original value of @INC will be used.
undef
An ArrayRef of directories used to override @INC.
This option has priority over add_inc, that is, if set_inc is defined the value of add_inc will be ignored.
add_inc
set_inc
Again, @INC will be localized internally so his original values will be left untouched.
An error handler called when a module fails to load or build an object. His only argument will be the exception thrown.
This is a coderef and the default value is \&Carp::croak.
Takes a list of module names and tries to load all of them in order.
For each module that fails to load, the error handler on_error will be called. Note that the default error handler is an alias to Carp::croak so in this case at the first fail, an exception will be thrown.
on_error
Carp::croak
All module names will be prefixed with the provided prefix and the loader will try to make sure that they all are valid before try to load them. All modules marked as "invalid" will not be loaded.
prefix
The term "invalid" is subject of discussion ahead.
The loader will search for modules into directories pointed by @INC which may be changed by attributes add_inc and set_inc.
In the end, if no exception was thrown, the method load will return a HashRef which the keys are the module names passed to it (without prefix) and the values are the fqn (with prefix) of the module if it was loaded or an empty string if it was not loaded.
load
Takes a list of modules (fqn) already loaded and for each one, tries to build an object calling the method indicated by builder, passing to it the arguments in args.
Returns a HashRef which the keys are the names of the modules and the values are the objects.
A mix of load and build. Receives a list of modules, tries to prepend them with prefix, load all and finally build an object for each one.
build
Returns the same as build.
Returns the namespace prefix as described above.
Returns the name of the builder as described above.
Returns an ArrayRef with the args provided to all builders.
Returns the ArrayRef of directories prepended to @INC.
Returns the ArrayRef of directories used to override @INC.
Returns the ArrayRef of directories that represents the content of @INC internally into the loader.
Returns the CodeRef of the error handler.
This module tries to define what is a valid module name. Arbitrarily we consider a valid module name whatever module that matches with the regular expression qr{^[_[:upper:]]\w*(::\w+)*$}.
This validation is to avoid injection of arbitrarily code as fake module names and the regular expression above should be changed in future versions or a better approach may be considered.
Therefore some valid module names are considered invalid within MAD::Loader as names with some UTF-8 characters for example. These modules cannot be loaded by MAD::Loader yet. For now this IS intentional.
MAD::Loader
The old package delimiter ' (single quote) is also intentionally ignored in favor of :: (double colon). Modules with single quote as package delimiter cannot be loaded by MAD::Loader.
'
::
The options add_inc and set_inc are used to isolate the environment where the search by modules is made, allowing you precisely control where MAD::Loader will look for modules.
You may use this features when your application must load plugins and you must assure that only modules within specific directories can be valid plugins for example.
A collateral effect is that when a module loaded by MAD::Loader tries to dynamically load another module, this module will be searched only within the directories known by MAD::Laoder.
If you use the option set_inc to limitate MAD::Loader to search only within the directory /my/plugins for example, and some plugin tries to load a module placed out of this path, your plugin will fail like this:
/my/plugins
Can't locate SomeModule.pm in @INC (@INC contains: /my/plugins) at /my/plugins/Myplugin.pm line 42.
Note that actually this is a feature, not a bug. If you isolate the search path with MAD::Loader you will be sure that no module will bypass your limitation, except if it know the search path of his sub-modules by itself (in this case, there is little to do :) ).
See https://github.com/blabos/MAD-Loader/issues/1 for an example.
Blabos de Blebe <blabos@cpan.org>
This software is copyright (c) 2014 by Blabos de Blebe.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install MAD::Loader, copy and paste the appropriate command in to your terminal.
cpanm
cpanm MAD::Loader
CPAN shell
perl -MCPAN -e shell install MAD::Loader
For more information on module installation, please visit the detailed CPAN module installation guide.