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 )