Exporter-Almighty
view release on metacpan or search on metacpan
lib/Exporter/Almighty.pm view on Meta::CPAN
for my $name ( @constants ) {
no strict 'refs';
my $full_name = "$into\::$name";
${ $full_name } = &{ $full_name }();
Internals::SvREADONLY( ${ $full_name }, 1 );
push @{ $into_EXPORT_TAGS->{'ro_vars'} //= [] }, '$' . $name;
}
return;
}
sub finalize_export_variables_for {
my ( $me, $into, $setup ) = @_;
my ( $into_ISA, $into_EXPORT, $into_EXPORT_OK, $into_EXPORT_TAGS ) =
$me->standard_package_variables( $into );
my %all_exports;
for my $list ( $into_EXPORT, $into_EXPORT_OK, values %{ $into_EXPORT_TAGS // {} } ) {
is_ArrayRef $list or next;
$all_exports{$_}++ for @$list;
}
@{ $into_EXPORT_OK } = sort keys %all_exports;
my %default_exports;
for my $list ( $into_EXPORT, $into_EXPORT_TAGS->{default} ) {
is_ArrayRef $list or next;
$default_exports{$_}++ for @$list;
}
@{ $into_EXPORT } = sort keys %default_exports;
return;
}
1;
__END__
=pod
=encoding utf-8
=head1 NAME
Exporter::Almighty - combining Exporter::Tiny with some other stuff for added power
=head1 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;
=head1 DESCRIPTION
This module aims to make building exporters easier. It is based on
L<Exporter::Tiny>, but helps you avoid manually setting C<< @EXPORT_OK >>,
C<< %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 C<< use v5.12 >> (or higher) before C<< use Exporter::Almighty >>
so that your package can benefit from features which don't exist in legacy
versions of Perl.
=head2 Setup Options
Exporter::Almighty's own setup happens through its import. A setup hashref
is passed as per the example in the L</SYNOPSIS>. Each key in this hash is
a setup option.
The names are all short, singular names, in case you forget whether to use
C<tag> or C<tags>!
=head3 C<< 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 L</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 C<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: C<constants>,
lib/Exporter/Almighty.pm view on Meta::CPAN
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 C<< RED >>, a readonly variable C<< $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
=head3 C<< type >>
This is an arrayref of type libraries. Each library listed will be I<imported>
into your exporter, and then the types in it will be I<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 L<Type::Library> instead of L<Exporter::Tiny>. (Type::Library is
itself a subclass of Exporter::Tiny, so you don't miss out on any features.)
=head3 C<< 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 L</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 C<Status> function exported by the above will return a L<Type::Tiny::Enum>
object.
The C<< :types >>, C<< :is >>, C<< :assert >>, C<< :to >>, and C<< :constants >>
tags will also automatically include the relevent exports.
If you export any enums then your module will be "promoted" from being an
L<Exporter::Tiny> to being a L<Type::Library>.
By convention, enum types should be UpperCamelCase.
=head3 C<< 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 L<Type::Tiny::Class> type constraints similar to how C<enum>
works. It will similarly promote your exporter to a L<Type::Library>.
Notice that the C<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
( run in 3.539 seconds using v1.01-cache-2.11-cpan-d7a12ab2c7f )