NAME
pkg - transparently use packages and inner packages
SYNOPSIS
# standard operations
# works on either inner or normal packages
# ------------------------------- ----------------
use pkg 'A'; #=> use A;
use pkg 'A', 'a', 'b'; #=> use A 'a', 'b';
use pkg 'A', []; #=> use A ();
# extra operations
# default alias for a class package
use pkg -alias => 'A::B::C';
C->new(...); #equivalent to A::B::C->new();
# specific alias for a class package
use pkg 'A::B::C' => -as => 'ABC';
ABC->new( ); # equivalent to A:B::C->new;
# multiple packages
use pkg [ 'A::B::C' => -as => 'ABC'],
[ 'A::B' => -as => 'AB' ];
# operate on A and its inner packages
use pkg 'A', '-inner';
# operate only on the inner packages of A
use pkg 'A', '-only_inner';
# operate on A and its inner packages, excluding anything below A::B
use pkg 'A', -inner, -exclude => qr/^A::B::/;
DESCRIPTION
pkg extends the standard "use" statement to more transparently handle
inner packages, additionally incorporating some of the functionality of
the aliased and use pragmata with a few extra twists.
An inner package is one which does not have the same name as the (fully
qualified) module in which it is defined. For example, if A.pm contains
package A;
sub a { ... }
package A::B;
sub ab { ... }
package A::C;
sub ac { ... }
1;
packages "A::B" and "A::C" are inner packages. The use statement (as
well as most pragmata dealing with modules) does not handle inner
packages. Some, such as parent, do, but require the user (via the
"-norequire" option) to know if the package is inner or not.
For example, after loading the above module:
use A;
You could simply call
A::a();
A::B::ab();
A::C::ac();
But, what if package A::B exported ab? Its import routine is not
automatically called when A is loaded. If you try to do this
use A::B 'ab';
you'll get an error from Perl as it tries to search for a file named
e.g., A/B.pm. It doesn't check to see if the "A::B" package has been
loaded.
Instead, you'd need to do this:
A::B->import( 'ab' );
ab();
Or, using pkg:
use pkg [ 'A' ], [ 'A::B' => qw[ ab ] ];
Simple Usage
In its simplest form, pkg accepts a *list* of a package name (*as a
string*) and its imports.
use pkg 'A::B', qw( funca funcb );
This loads the package "A::B" (if necessary) and imports the functions
funca and funcb. Note that if "A::B" is an inner package, the module
(file) which contains it must be loaded prior to this e.g.
# either of these is sufficient
use A;
use pkg 'A';
This needs to be done only *once* (not every time an inner package is
used). Of course it can be combined with loading "A::B":
use pkg [ 'A' ], [ 'A::B' => qw( funca funcb ) ];
Controlling imports
There is a subtlety in how the standard use statement handles empty or
non-existent import lists:
use A; # call A->import();
use A 'a', 'b' # call A->import( 'a', 'b' );
use A (); # do *not* call A->import;
This mechanism isn't available to pkg as it cannot tell the difference
between:
use pkg 'A';
use pkg 'A', ();
Instead, use "[]" instead of "()":
use pkg 'A', [];
What if you need to pass a "[]" to "A->import()"? Use the "-import"
package option:
use pkg 'A', -import => []; #=> use A [];
use pkg 'A', -import => '-import'; #=> use A '-import';
"-import" instructs pkg that all remaining arguments should be passed to
the package's import routine.
Note that the following are equivalent
use A (), 'a';
use pkg 'A', [], 'a';
and result in
A->import( 'a' );
Multiple packages
Multiple packages may be operated on by passing each package's
specifications as separate array references:
use pkg ['A'], ['A::B', qw( funca funcb ) ];
OPTIONS
pkg accepts options to modify its behavior. "Global" options (which
affect more than one package) can appear in multiple places if more than
one package is manipulated. Package specific options always appear
directly after the package name and apply only to that package.
If there's only one package, the syntax is simple. Global options occur
before the package name.
use pkg -norequire => 'My::Package' -as => 'MyP';
"-norequire" is a global option, and "-as" is a package option.
If more than one package is specified, global options may occur both
outside of the package specifications as well as inside of them. For
example,
use pkg
-alias =>
[ 'My::FirstClass' ],
[ -noalias => 'My::SecondClass' ]
[ 'My::ThirdClass' => -as => 'ThirdClassIsBetterThanFirst' ]
-noalias =>
[ 'My::Library1' ],
[ 'My::Library2' ],
[ 'My::Library3' ],
;
The options appearing outside of the package specifications affect all
packages which follow. The options inside a specification affect that
package only. As shown, some options may be negated, and package options
may override global ones.
Global Options
"-alias"
"-noalias"
Provide (or don't provide) shortened names for class names. These
are simply the last component of the original name.
The idea is borrowed from the "aliased" pragma; pkg constructs and
exports a subroutine with the shortened name which returns the fully
qualified name.
For example,
use pkg -alias => 'A::Long:Class';
# these are equivalent
A::Long::Class->new();
Class->new();
If multiple classes are loaded, no checks are performed to ensure
that the shortened names are unique. Use the "-as" package option to
specify specific names.
"-strip"
Created aliases by removing a prefix from the succeeding class
names. The prefix may be specified in one of two ways:
"-strip" *string*
Remove a leading *string* from the class names. All component
separators ("::") are also removed. For example,
-strip => 'A::C', 'A::C::E::F::G'
results in an alias of "EFG".
"-strip { pfx => *string*, sep => *string* }"
Remove *prefix* from class names, and replace the class
component separators ("::") with the specified string. After
prefix removal, a leading "::" sequence is removed.
"-require"
"-norequire"
Try to load (or don't try to load) the packages with
Class::Load::load_class. If you know that the package is an inner
package and the file containing it has already been loaded,
specifying "-norequire" can speed things up by not loading
Class::Load.
By default packages are loaded (i.e. "-require").
Package Options
"-as" => *string*
Create an alias named *string* for the package. The aliased name
must be a legal subroutine name.
For example,
use pkg 'A::Long:Class' => -as => 'ALC';
# these are equivalent
A::Long::Class->new();
ALC->new();
"-import"
There's always a chance that a package's import list may be confused
with pkg package options (perhaps it also has a "-as" option). To
avoid this, a package's import list may be preceded with the
"-import" option, which indicates to pkg that all of the following
arguments are to be passed as is to the package's import routine.
# these are equivalent
use A ( '-as', 'func1', 'func2' );
use pkg 'A' => -import => ( '-as', 'func1', 'func2' );
"-require"
"-norequire"
This has the same functionality as the similarly named global
options, but as a package option may be placed after the package
name for aesthetics.
"-inner"
In addition to the package, process any of its currently loaded
inner packages. Inner packages are discovered via
Devel::InnerPackage, and must fall within the "hierarchy" of the
package. For example, given a module with the following contents:
package A;
sub a {}
package A::B;
sub ab {}
package B;
sub b {}
"A::B" is an inner package of "A", but "B" is not. Inner packages
must have defined symbols, otherwise they will not be identified.
"-only_inner"
Similar to "-inner", but *only* the inner packages are processed,
not the package itself.
This *does not* affect whether the package is loaded; this is
controlled by the "-require" option.
"-include" *specification*
Check the package name against the *specification* using the smart
match operator ("~~") and ignore it if it does not match. If
"-inner" or "-only_inner" are specified, inner packages are also
checked.
This *does not* affect whether the package is loaded; this is
controlled by the "-require" option.
This is most useful when either "-inner" or "-only_inner" is
specified.
"-exclude" *specification*
Check the package name against the *specification* using the smart
match operator ("~~") and ignore it if it matches. The "-exclude"
match is processed after "-include" if both are specified. If
"-inner" or "-only_inner" are specified, inner packages are also
checked.
This *does not* affect whether the package is loaded; this is
controlled by the "-require" option.
This is most useful when either "-inner" or "-only_inner" is
specified.
"-version" => *version*
Specify the minimum acceptable version of the package.
DIAGNOSTICS
"global option '%s': unknown option"
The specified option wasn't recognized as a global option.
"package option '%s': unknown option"
The specified option wasn't recognized as a package option.
"option '%s': cannot be negated"
An illegal negation of the specified option was specified.
"option '%s': not enough values"
The specified option required more values than was specified.
"can't use option "%s" when looping over inner packages"
The specifed option cannot be used in conjunction with "-inner" or
"-only_inner".
"-strip: no prefix specified"
The "-strip" option requires an argument specifying the prefix to
remove.
"internal error"
Something really bad happened.
IMPLEMENTATION
pkg does very little on its own. It uses the following modules:
Class::Load
Class::Load::load_class is used to load the package. It also takes
care of checking package versions.
Import::Into
This is used to call a package's import routine
aliased
This provided the inspiration for the aliasing implementation.
Devel::InnerPackages
Discover a package's inner self.
DEPENDENCIES
Class::Load, Import::Into, Devel::InnerPackages, Perl 5.10.1.
INCOMPATIBILITIES
None reported.
BUGS AND LIMITATIONS
pkg is focussed specifically on dealing with packages and is not
intended as a general purpose replacement for the standard use
statement. In particular it does not know how to deal with other
pragmata, e.g.,
use pkg strict;
will probably not do anything useful and will most probably advance the
heat death of the universe.
Please report any bugs or feature requests to "bug-pkg@rt.cpan.org", or
through the web interface at
<http://rt.cpan.org/Public/Dist/Display.html?Name=pkg>.
SEE ALSO
aliased, namespace, as, use.
VERSION
Version 0.01
LICENSE AND COPYRIGHT
Copyright (c) 2013 Diab Jerius
pkg is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
AUTHOR
Diab Jerius <djerius@cpan.org>