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 . 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 . AUTHOR Diab Jerius