Synopsis
package Your::Package;
use v5.12;
use Exporter::Almighty -setup => {
tag => {
foo => [ 'foo1', 'foo2' ],
bar => [ 'bar1' ],
},
const => {
colours => { RED => 'red', BLUE => 'blue', GREEN => 'green' },
},
enum => {
Status => [ 'dead', 'alive' ],
},
also => [
'strict',
'Scalar::Util' => [ 'refaddr' ],
'warnings',
],
};
sub foo1 { ... }
sub foo2 { ... }
sub bar1 { ... }
1;
Description
This module aims to make building exporters easier. It is based on
Exporter::Tiny
, but helps you avoid manually setting
@EXPORT_OK
,
%EXPORT_TAGS
, etc.
Exporter::Almighty supports lexical exports, even on Perl versions as old as 5.12.
Exporter::Almighty indeed requires Perl 5.12, so it's strongly recommended you add
use v5.12
(or higher) before
use Exporter::Almighty
so that your package can benefit from features which don't exist in legacy versions of Perl.
Setup Options
Exporter::Almighty's own setup happens through its import. A setup hashref is passed as per the example in the "SYNOPSIS" . Each key in this hash is a setup option.
The names are all short, singular names, in case you forget whether to use
tag
or
tags
!
tag
This is a hashref where the keys are tag names and the values are arrayrefs of function names.
use Exporter::Almighty -setup => {
tag => {
foo => [ 'foo1', 'foo2' ],
bar => [ 'bar1' ],
}
};
A user of the package defined in the "SYNOPSIS" could import:
use Your::Package qw( foo1 foo2 bar1 ); # import functions by name
use Your::Package qw( :foo ); # import 'foo1' and 'foo2'
use Your::Package qw( -foo ); # same!
If you have a tag called
default
, that is special. It will be automatically exported if your caller doesn't provide an explicit list of things they want to import.
The following other tags also have special meanings:
constants
,
types
,
assert
,
is
,
to
, and
all
.
By convention, tags names should be snake_case.
const
Similar to
tag
this is a hashref where keys are tag names, but instead of the values being arrayrefs of function names, they are hashrefs which define constants.
use Exporter::Almighty -setup => {
const => {
colours => { RED => 'red', BLUE => 'blue', GREEN => 'green' },
},
};
A user of the package defined in the "SYNOPSIS" could import:
use Your::Package qw( RED GREEN BLUE ); # import constants by name
use Your::Package qw( :colours ); # import 'colours' constants
use Your::Package qw( :constants ); # import ALL constants
By convention, the tag names should be snake_case, but constant names should be SHOUTING_SNAKE_CASE.
For every constant like
RED
, a readonly variable
$RED
is also created, making it easier to interpolate the constant into a string. These are not exported by default.
use Your::Package qw( $RED $GREEN $BLUE ); # import ro vars by name
use Your::Package qw( :ro_vars ); # import ALL ro vars
type
This is an arrayref of type libraries. Each library listed will be imported into your exporter, and then the types in it will be re-exported to the people who use your package. Each type library can optionally be followed by an arrayref of type names if you don't want to just import all types.
package Your::Package;
use Exporter::Almighty -setup => {
tags => {
foo => [ 'foo1', 'foo2' ],
},
type => [
'Types::Standard',
'Types::Common::String' => [ 'NonEmptyStr' ],
'Types::Common::Numeric' => [ 'PositiveInt', 'PositiveOrZeroInt' ],
],
};
sub foo1 { ... }
sub foo2 { ... }
...;
package main;
use Your::Package qw( -foo is_NonEmptyStr );
my $got = foo1();
if ( is_NonEmptyStr( $got ) ) {
foo2();
}
If you re-export types like this, then your module will be "promoted" to being a subclass of Type::Library instead of Exporter::Tiny . (Type::Library is itself a subclass of Exporter::Tiny, so you don't miss out on any features.)
enum
This is a hashref where keys are enumerated type names, and the values are arrayrefs of strings.
use Exporter::Almighty -setup => {
enum => {
Status => [ 'dead', 'alive' ],
},
};
A user of the package defined in the "SYNOPSIS" could import:
use Your::Package qw(
Status
is_Status
assert_Status
to_Status
STATUS_ALIVE
STATUS_DEAD
);
use Your::Package qw( +Status ); # shortcut for the above
The
Status
function exported by the above will return a
Type::Tiny::Enum
object.
The
:types
,
:is
,
:assert
,
:to
, and
:constants
tags will also automatically include the relevent exports.
If you export any enums then your module will be "promoted" from being an Exporter::Tiny to being a Type::Library .
By convention, enum types should be UpperCamelCase.
class
This is an arrayref of class names.
use Exporter::Almighty -setup => {
class => [
'HTTP::Tiny',
'LWP::UserAgent',
],
};
People can import:
use Your::Package qw( +HTTPTiny +LWPUserAgent );
unless ( is_HTTPTiny($x) or is_LWPUserAgent($x) ) {
$x = HTTPTiny->new();
}
These create
Type::Tiny::Class
type constraints similar to how
enum
works. It will similarly promote your exporter to a
Type::Library
.
Notice that the
new
method will be proxied through to the underlying class, so these can also work as useful aliases for long class names.
use Exporter::Almighty -setup => {
class => [
'ShortName' => { class => 'Very::Long::Class::Name' },
'TinyName' => { class => 'An::Even::Longer::Class::Name' },
],
};
Exporter::Almighty will attempt to pre-emptively load modules mentioned here, so you don't need to do it yourself. However if the modules don't exist, it won't complain.
role
This works the same as
class
, except for roles.
duck
This is a hashref where keys are "duck type" type names, and the values are arrayrefs of method names.
use Exporter::Almighty -setup => {
duck => [
'UserAgent' => [ 'head', 'get', 'post' ],
],
};
These create
Type::Tiny::Duck
type constraints similar to how
enum
works. It will similarly promote your exporter to be a
Type::Library
.
also
A list of other packages to also export to your caller. Each package name can optionally be followed by an arrayref of import arguments.
use Exporter::Almighty -setup => {
also => [
'strict',
'Scalar::Util' => [ 'refaddr' ],
'warnings',
],
};
Your caller isn't given any options allowing them to opt in or out of this, so it is recommended that this be used sparingly. strict , warnings , feature , experimental , and namespace::autoclean are good packages to consider listing here. Packages that export named functions are less good.
API
Instead of:
package Your::Package;
use Exporter::Almighty -setup => \%setup;
It is possible to do this at run-time:
Exporter::Almighty->setup_for( 'Your::Package', %setup );
This may allow slightly more flexibility in some cases.
Exporter::Almighty is also designed to be easily subclassable.
Exporter::Tiny features you get for free
Features for you
Exporter::Almighty will import strict and warnings into your package.
You can export package variables, though it's rarely a good idea:
package Your::Package;
use Exporter::Almighty -setup => {
tag => { default => [ 'xxx', '$YYY' ] },
};
our $YYY = 42;
You can use generators:
package Your::Package;
use Exporter::Almighty -setup => {
tag => { default => [ 'xxx' ] },
};
sub _generate_xxx {
my ( $me, $name, $vals, $opts ) = @_;
my $caller = $opts->{into};
# Return the sub which will be installed into caller as 'xxx'.
return sub {
};
}
...;
package main;
use Your::Package 'xxx' => \%vals;
xxx( ... );
Features for your caller
Your caller can do lexical imports:
use Your::Package -lexical, qw( ... );
Your caller can rename imported functions:
use Your::Package foo => { -as => 'foofoo' };
And everything else described in Exporter::Tiny::Manual::Importing .
See Also
Exporter::Tiny , Exporter::Shiny .
CXC::Exporter::Util was an inspiration for this module and the features overlap a bit.