package Package::Variant;
use strictures 1;
+use Carp qw( croak );
our %Variable;
};
*{"${target}::import"} = sub {
my $target = caller;
+ my (undef, %arg) = @_;
+ my $as = defined($arg{as}) ? $arg{as} : $last;
no strict 'refs';
- *{"${target}::${last}"} = sub {
+ *{"${target}::${as}"} = sub {
$me->build_variant_of($variable, @_);
};
};
}
}
+my $sanitize_importing = sub {
+ my ($me, $spec) = @_;
+ return []
+ unless defined $spec;
+ return [map [$_ => $spec->{$_}], keys %$spec]
+ if ref $spec eq 'HASH';
+ croak q{The 'importing' option has to be either a hash or array ref}
+ unless ref $spec eq 'ARRAY';
+ my @specced = @$spec;
+ my @imports;
+ while (@specced) {
+ push @imports, [shift(@specced), shift(@specced)];
+ }
+ return \@imports;
+};
+
sub build_variant_of {
my ($me, $variable, @args) = @_;
my $variant_name = "${variable}::_Variant_".++$Variable{$variable}{anon};
- my $import = $Variable{$variable}{args}{importing} || {};
+ my $import = $me
+ ->$sanitize_importing($Variable{$variable}{args}{importing});
my $setup = join("\n",
"package ${variant_name};",
(map sprintf(
- q!use %s @{$import->{'%s'}||[]};!, $_, quotemeta($_),
- ), keys %$import),
+ q!use %s %s;!,
+ $import->[$_][0],
+ not(defined $import->[$_][1])
+ ? ''
+ : sprintf(
+ q!@{$import->[%d][1]}!,
+ $_,
+ ),
+ ), 0..$#$import),
"1;",
);
eval $setup
use strictures 1;
use Package::Variant
# what modules to 'use'
- importing => { 'Moo::Role' => [] },
+ importing => { 'Moo::Role' => undef },
# proxied subroutines
subs => [qw( has around before after extends )],
arguments as values. These packages will be imported into every new
variant, and need to set up every declarative subroutine you require to
build your variable package. The next option will allow you to use these
-functions.
+functions. See L</importing> for more options.
The L</subs> option is an array reference of subroutine names that are
exported by the packages specified with L</importing>. These subroutines
use My::Variant;
my $new_variant_package = Variant( @variant_arguments );
-The package is now fully initialized and used.
+The package is now fully initialized and used. You can import the
+subroutine under a different name by specifying an C<as> argument.
=head2 Dynamic creation of variant packages
arguments by every variation before the L</make_variant> method is asked
to create the package.
+If import order is important to you, you can also pass the C<importing>
+arguments as a flag array reference:
+
+ use Package::Variant
+ importing => [ PackageA => [], PackageB => [] ];
+
+If you want to import whatever the package exports by default, you can
+also pass C<undef> instead of an empty array reference.
+
=head2 subs
An array reference of strings listing the names of subroutines that should
package and receive a subroutine taking C<@arguments> defining the variant
and returning the name of the newly created variant package.
+The following options can be specified when importing:
+
+=over
+
+=item * B<as>
+
+ use Some::Variant::Package as => 'Foo';
+ my $variant_package = Foo( @arguments );
+
+Exports the generator subroutine under a different name than the default.
+
+=back
+
=head1 C<Package::Variant> METHODS
These methods are available on C<Package::Variant> itself.