Package-Variant-1.003002/0000755000372100001440000000000012554742650014462 5ustar matthewtusersPackage-Variant-1.003002/lib/0000755000372100001440000000000012554742650015230 5ustar matthewtusersPackage-Variant-1.003002/lib/Package/0000755000372100001440000000000012554742650016563 5ustar matthewtusersPackage-Variant-1.003002/lib/Package/Variant.pm0000644000372100001440000003471412554742643020540 0ustar matthewtuserspackage Package::Variant; use strictures 2; use Import::Into; use Module::Runtime qw(require_module); use Carp qw(croak); our $VERSION = '1.003002'; $VERSION = eval $VERSION; our %Variable; my $sanitize_importing = sub { my ($me, $spec) = @_; return [] unless defined $spec; my @specced = not(ref $spec) ? ($spec) : (ref($spec) eq 'ARRAY') ? (@$spec) : (ref($spec) eq 'HASH') ? (map { croak qq{The import argument list for '$_' is not an array ref} unless ref($spec->{$_}) eq 'ARRAY'; ($_ => $spec->{$_}); } sort keys %$spec) : croak q{The 'importing' option has to be either a hash or array ref}; my @imports; my $arg_count = 1; while (@specced) { my $key = shift @specced; croak qq{Value $arg_count in 'importing' is not a package string}, $arg_count unless defined($key) and not(ref $key); $arg_count++; my $import_args = (not(@specced) or (defined($specced[0]) and not ref($specced[0]))) ? [] : (ref($specced[0]) eq 'ARRAY') ? do { $arg_count++; shift @specced } : croak( qq{Value $arg_count for package '$key' in 'importing' is not} . qq{ a package string or array ref} ); push @imports, [$key, $import_args]; } return \@imports; }; my $sub_namer = eval { require Sub::Name; sub { shift if @_ > 2; Sub::Name::subname(@_) } } || sub { $_[-1] }; sub import { my $variable = caller; my $me = shift; my $last = (split '::', $variable)[-1]; my $anon = 'A000'; my %args = @_; no strict 'refs'; $Variable{$variable} = { anon => $anon, args => { %args, importing => $me->$sanitize_importing($args{importing}), }, subs => { map +($_ => sub {}), @{$args{subs}||[]}, }, }; *{"${variable}::import"} = sub { my $target = caller; my (undef, %arg) = @_; my $as = defined($arg{as}) ? $arg{as} : $last; no strict 'refs'; *{"${target}::${as}"} = sub { $me->build_variant_of($variable, @_); }; }; my $subs = $Variable{$variable}{subs}; foreach my $name (keys %$subs) { *{"${variable}::${name}"} = sub { goto &{$subs->{$name}} }; } *{"${variable}::install"} = sub { goto &{$Variable{$variable}{install}}; }; *{"${variable}::build_variant"} = sub { shift; $me->build_variant_of($variable, @_); }; } sub build_variant_package_name { my ($me, $variable, @args) = @_; if ($variable->can('make_variant_package_name')) { return $variable->make_variant_package_name(@args); } return "${variable}::_Variant_".++$Variable{$variable}{anon}; } sub build_variant_of { my ($me, $variable, @args) = @_; my $variant_name = $me->build_variant_package_name($variable, @args); foreach my $to_import (@{$Variable{$variable}{args}{importing}}) { my ($pkg, $args) = @$to_import; require_module $pkg; eval q{ BEGIN { $pkg->import::into($variant_name, @{$args}) }; 1; } or die $@; } my $subs = $Variable{$variable}{subs}; local @{$subs}{keys %$subs} = map $variant_name->can($_), keys %$subs; local $Variable{$variable}{install} = sub { my $full_name = "${variant_name}::".shift; my $ref = $sub_namer->($full_name, @_); no strict 'refs'; *$full_name = $ref; }; $variable->make_variant($variant_name, @args); return $variant_name; } 1; __END__ =head1 NAME Package::Variant - Parameterizable packages =head1 SYNOPSIS Creation of anonymous variants: # declaring a variable Moo role package My::VariableRole::ObjectAttr; use strictures 2; use Package::Variant # what modules to 'use' importing => ['Moo::Role'], # proxied subroutines subs => [ qw(has around before after with) ]; sub make_variant { my ($class, $target_package, %arguments) = @_; # access arguments my $name = $arguments{name}; # use proxied 'has' to add an attribute has $name => (is => 'lazy'); # install a builder method install "_build_${name}" => sub { return $arguments{class}->new; }; } # using the role package My::Class::WithObjectAttr; use strictures 2; use Moo; use My::VariableRole::ObjectAttr; with ObjectAttr(name => 'some_obj', class => 'Some::Class'); # using our class my $obj = My::Class::WithObjectAttr->new; $obj->some_obj; # returns a Some::Class instance And the same thing, only with named variants: # declaring a variable Moo role that can be named package My::VariableRole::ObjectAttrNamed; use strictures 2; use Package::Variant importing => ['Moo::Role'], subs => [ qw(has around before after with) ]; use Module::Runtime 'module_notional_filename'; # only if you need protection # this method is run at variant creation time to determine its custom # package name. it can use the arguments or do something entirely else. sub make_variant_package_name { my ($class, $package, %arguments) = @_; $package = "Private::$package"; # you can munge the input here if you like # only if you *need* protection die "Won't clobber $package" if $INC{module_notional_filename $package}; return $package; } # same as in the example above, except for the argument list. in this example # $package is the user input, and # $target_package is the actual package in which the variant gets installed sub make_variant { my ($class, $target_package, $package, %arguments) = @_; my $name = $arguments{name}; has $name => (is => 'lazy'); install "_build_${name}" => sub {return $arguments{class}->new}; } # using the role package My::Class::WithObjectAttr; use strictures 2; use Moo; use My::VariableRole::ObjectAttrNamed; # create the role under a specific name ObjectAttrNamed "My::Role" => (name => 'some_obj', class => 'Some::Class'); # and use it with "Private::My::Role"; # using our class my $obj = My::Class::WithObjectAttr->new; $obj->some_obj; # returns a Some::Class instance =head1 DESCRIPTION This module allows you to build a variable package that contains a package template and can use it to build variant packages at runtime. Your variable package will export a subroutine which will build a variant package, combining its arguments with the template, and return the name of the new variant package. The implementation does not care about what kind of packages it builds, be they simple function exporters, classes, singletons or something entirely different. =head2 Declaring a variable package There are two important parts to creating a variable package. You first have to give C some basic information about what kind of variant packages you want to provide, and how. The second part is implementing a method which builds the components of the variant packages that use the user's arguments or cannot be provided with a static import. =head3 Setting up the environment for building variants When you C, you pass along some arguments that describe how you intend to build your variants. use Package::Variant importing => { $package => \@import_arguments, ... }, subs => [ @proxied_subroutine_names ]; The L option needs to be a hash or array reference with package names to be Cd as keys, and array references containing the import arguments as values. These packages will be imported into every new variant package, to provide static functionality of the variant packages and to set up every declarative subroutine you require to build variants package components. The next option will allow you to use these functions. See L for more options. You can omit empty import argument lists when passing an array reference. The L option is an array reference of subroutine names that are exported by the packages specified with L. These subroutines will be proxied from your variable package to the variant to be generated. With L initializing your package and L declaring what subroutines you want to use to build a variant, you can now write a L method building your variants. =head3 Declaring a method to produce variants Every time a user requests a new variant, a method named L will be called with the name of the target package and the arguments from the user. It can then use the proxied subroutines declared with L to customize the variant package. An L subroutine is exported as well allowing you to dynamically install methods into the variant package. If these options aren't flexible enough, you can use the passed name of the variant package to do any other kind of customizations. sub make_variant { my ($class, $target, @arguments) = @_; # ... # customization goes here # ... } When the method is finished, the user will receive the name of the new variant package you just set up. =head2 Using variable packages After your variable package is L your users can get a variant generator subroutine by simply importing your package. use My::Variant; my $new_variant_package = Variant(@variant_arguments); # the variant package is now fully initialized and used You can import the subroutine under a different name by specifying an C argument. =head2 Dynamic creation of variant packages For regular uses, the L provides more than enough flexibility. However, if you want to create variants of dynamically determined packages, you can use the L method. You can use this to create variants of other packages and pass arguments on to them to allow more modular and extensible variants. =head1 OPTIONS These are the options that can be passed when importing C. They describe the environment in which the variants are created. use Package::Variant importing => { $package => \@import_arguments, ... }, subs => [ @proxied_subroutines ]; =head2 importing This option is a hash reference mapping package names to array references containing import arguments. The packages will be imported with the given arguments by every variant before the L method is asked to create the package (this is done using L). If import order is important to you, you can also pass the C arguments as a flat array reference: use Package::Variant importing => [ 'PackageA', 'PackageB' ]; # same as use Package::Variant importing => [ 'PackageA' => [], 'PackageB' => [] ]; # or use Package::Variant importing => { 'PackageA' => [], 'PackageB' => [] }; The import method will be called even if the list of import arguments is empty or not specified, If you just want to import a single package's default exports, you can also pass a string instead: use Package::Variant importing => 'Package'; =head2 subs An array reference of strings listing the names of subroutines that should be proxied. These subroutines are expected to be installed into the new variant package by the modules imported with L. Subroutines with the same name will be available in your variable package, and will proxy through to the newly created package when used within L. =head1 VARIABLE PACKAGE METHODS These are methods on the variable package you declare when you import C. =head2 make_variant Some::Variant::Package->make_variant( $target, @arguments ); B This method will be called for every new variant of your package. This method should use the subroutines declared in L to customize the new variant package. This is a class method receiving the C<$target> package and the C<@arguments> defining the requested variant. =head2 make_variant_package_name Some::Variant::Package->make_variant_package_name( @arguments ); B If present, this method will be used to determine the package name for a particular variant being constructed. If you do not implement it, a unique package name something like Some::Variant::Package::_Variant_A003 will be created for you. =head2 import use Some::Variant::Package; my $variant_package = Package( @arguments ); This method is provided for you. It will allow a user to C your 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 use Some::Variant::Package as => 'Foo'; my $variant_package = Foo(@arguments); Exports the generator subroutine under a different name than the default. =back =head2 build_variant use Some::Variant::Package (); my $variant_package = Some::Variant::Package->build_variant( @arguments ); This method is provided for you. It will generate a variant package and return its name, just like the generator sub provided by L. This allows you to avoid importing anything into the consuming package. =head1 C METHODS These methods are available on C itself. =head2 build_variant_of my $variant_package = Package::Variant ->build_variant_of($variable_package, @arguments); This is the dynamic method of creating new variants. It takes the C<$variable_package>, which is a pre-declared variable package, and a set of C<@arguments> passed to the package to generate a new C<$variant_package>, which will be returned. =head2 import use Package::Variant @options; Sets up the environment in which you declare the variants of your packages. See L for details on the available options and L for a list of exported subroutines. =head1 EXPORTS Additionally to the proxies for subroutines provided in L, the following exports will be available in your variable package: =head2 install install($method_name, $code_reference); Installs a method with the given C<$method_name> into the newly created variant package. The C<$code_reference> will be used as the body for the method, and if L is available the coderef will be named. If you want to name it something else, then use: install($method_name, $name_to_use, $code_reference); =head1 AUTHOR mst - Matt S. Trout (cpan:MSTROUT) =head1 CONTRIBUTORS phaylon - Robert Sedlacek (cpan:PHAYLON) haarg - Graham Knop (cpan:HAARG) =head1 COPYRIGHT Copyright (c) 2010-2012 the C L and L as listed above. =head1 LICENSE This library is free software and may be distributed under the same terms as perl itself. =cut Package-Variant-1.003002/META.yml0000644000372100001440000000134512554742650015736 0ustar matthewtusers--- abstract: 'Parameterizable packages' author: - 'mst - Matt S. Trout (cpan:MSTROUT) ' build_requires: Test::Fatal: '0' dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.150001' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Package-Variant no_index: directory: - t - xt package: - string requires: Carp: '0' Import::Into: '1.000000' Module::Runtime: '0.013' perl: '5.006' strictures: '2.000000' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Package-Variant repository: git://git.shadowcat.co.uk/p5sagit/Package-Variant.git version: '1.003002' Package-Variant-1.003002/META.json0000644000372100001440000000264412554742650016111 0ustar matthewtusers{ "abstract" : "Parameterizable packages", "author" : [ "mst - Matt S. Trout (cpan:MSTROUT) " ], "dynamic_config" : 0, "generated_by" : "ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.150001", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Package-Variant", "no_index" : { "directory" : [ "t", "xt" ], "package" : [ "string" ] }, "prereqs" : { "build" : {}, "configure" : {}, "runtime" : { "requires" : { "Carp" : "0", "Import::Into" : "1.000000", "Module::Runtime" : "0.013", "perl" : "5.006", "strictures" : "2.000000" } }, "test" : { "requires" : { "Test::Fatal" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-Package-Variant@rt.cpan.org", "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Package-Variant" }, "repository" : { "type" : "git", "url" : "git://git.shadowcat.co.uk/p5sagit/Package-Variant.git", "web" : "http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Package-Variant.git" } }, "version" : "1.003002" } Package-Variant-1.003002/Makefile.PL0000644000372100001440000000502112554741422016426 0ustar matthewtusersuse strict; use warnings FATAL => 'all'; my %META = ( name => 'Package-Variant', prereqs => { test => { requires => { 'Test::Fatal' => '0', }, }, runtime => { requires => { 'perl' => '5.006', 'strictures' => '2.000000', 'Carp' => '0', 'Import::Into' => '1.000000', 'Module::Runtime' => '0.013', }, }, }, dynamic_config => 0, resources => { # r/w: p5sagit@git.shadowcat.co.uk:Package-Variant.git repository => { url => 'git://git.shadowcat.co.uk/p5sagit/Package-Variant.git', web => 'http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/Package-Variant.git', type => 'git', }, bugtracker => { mailto => 'bug-Package-Variant@rt.cpan.org', web => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Package-Variant', }, }, no_index => { directory => [ 't', 'xt', ], package => [ 'string' ] }, ); my %MM_ARGS = (); ## BOILERPLATE ############################################################### require ExtUtils::MakeMaker; (do 'maint/Makefile.PL.include' or die $@) unless -f 'META.yml'; # have to do this since old EUMM dev releases miss the eval $VERSION line my $eumm_version = eval $ExtUtils::MakeMaker::VERSION; my $mymeta = $eumm_version >= 6.57_02; my $mymeta_broken = $mymeta && $eumm_version < 6.57_07; ($MM_ARGS{NAME} = $META{name}) =~ s/-/::/g; ($MM_ARGS{VERSION_FROM} = "lib/$MM_ARGS{NAME}.pm") =~ s{::}{/}g; $META{license} = [ $META{license} ] if $META{license} && !ref $META{license}; $MM_ARGS{LICENSE} = $META{license}[0] if $META{license} && $eumm_version >= 6.30; $MM_ARGS{NO_MYMETA} = 1 if $mymeta_broken; $MM_ARGS{META_ADD} = { 'meta-spec' => { version => 2 }, %META } unless -f 'META.yml'; for (qw(configure build test runtime)) { my $key = $_ eq 'runtime' ? 'PREREQ_PM' : uc $_.'_REQUIRES'; my $r = $MM_ARGS{$key} = { %{$META{prereqs}{$_}{requires} || {}}, %{delete $MM_ARGS{$key} || {}}, }; defined $r->{$_} or delete $r->{$_} for keys %$r; } $MM_ARGS{MIN_PERL_VERSION} = delete $MM_ARGS{PREREQ_PM}{perl} || 0; delete $MM_ARGS{MIN_PERL_VERSION} if $eumm_version < 6.47_01; $MM_ARGS{BUILD_REQUIRES} = {%{$MM_ARGS{BUILD_REQUIRES}}, %{delete $MM_ARGS{TEST_REQUIRES}}} if $eumm_version < 6.63_03; $MM_ARGS{PREREQ_PM} = {%{$MM_ARGS{PREREQ_PM}}, %{delete $MM_ARGS{BUILD_REQUIRES}}} if $eumm_version < 6.55_01; delete $MM_ARGS{CONFIGURE_REQUIRES} if $eumm_version < 6.51_03; ExtUtils::MakeMaker::WriteMakefile(%MM_ARGS); ## END BOILERPLATE ########################################################### Package-Variant-1.003002/README0000644000372100001440000002722312554742650015350 0ustar matthewtusersNAME Package::Variant - Parameterizable packages SYNOPSIS Creation of anonymous variants: # declaring a variable Moo role package My::VariableRole::ObjectAttr; use strictures 2; use Package::Variant # what modules to 'use' importing => ['Moo::Role'], # proxied subroutines subs => [ qw(has around before after with) ]; sub make_variant { my ($class, $target_package, %arguments) = @_; # access arguments my $name = $arguments{name}; # use proxied 'has' to add an attribute has $name => (is => 'lazy'); # install a builder method install "_build_${name}" => sub { return $arguments{class}->new; }; } # using the role package My::Class::WithObjectAttr; use strictures 2; use Moo; use My::VariableRole::ObjectAttr; with ObjectAttr(name => 'some_obj', class => 'Some::Class'); # using our class my $obj = My::Class::WithObjectAttr->new; $obj->some_obj; # returns a Some::Class instance And the same thing, only with named variants: # declaring a variable Moo role that can be named package My::VariableRole::ObjectAttrNamed; use strictures 2; use Package::Variant importing => ['Moo::Role'], subs => [ qw(has around before after with) ]; use Module::Runtime 'module_notional_filename'; # only if you need protection # this method is run at variant creation time to determine its custom # package name. it can use the arguments or do something entirely else. sub make_variant_package_name { my ($class, $package, %arguments) = @_; $package = "Private::$package"; # you can munge the input here if you like # only if you *need* protection die "Won't clobber $package" if $INC{module_notional_filename $package}; return $package; } # same as in the example above, except for the argument list. in this example # $package is the user input, and # $target_package is the actual package in which the variant gets installed sub make_variant { my ($class, $target_package, $package, %arguments) = @_; my $name = $arguments{name}; has $name => (is => 'lazy'); install "_build_${name}" => sub {return $arguments{class}->new}; } # using the role package My::Class::WithObjectAttr; use strictures 2; use Moo; use My::VariableRole::ObjectAttrNamed; # create the role under a specific name ObjectAttrNamed "My::Role" => (name => 'some_obj', class => 'Some::Class'); # and use it with "Private::My::Role"; # using our class my $obj = My::Class::WithObjectAttr->new; $obj->some_obj; # returns a Some::Class instance DESCRIPTION This module allows you to build a variable package that contains a package template and can use it to build variant packages at runtime. Your variable package will export a subroutine which will build a variant package, combining its arguments with the template, and return the name of the new variant package. The implementation does not care about what kind of packages it builds, be they simple function exporters, classes, singletons or something entirely different. Declaring a variable package There are two important parts to creating a variable package. You first have to give "Package::Variant" some basic information about what kind of variant packages you want to provide, and how. The second part is implementing a method which builds the components of the variant packages that use the user's arguments or cannot be provided with a static import. Setting up the environment for building variants When you "use Package::Variant", you pass along some arguments that describe how you intend to build your variants. use Package::Variant importing => { $package => \@import_arguments, ... }, subs => [ @proxied_subroutine_names ]; The "importing" option needs to be a hash or array reference with package names to be "use"d as keys, and array references containing the import arguments as values. These packages will be imported into every new variant package, to provide static functionality of the variant packages and to set up every declarative subroutine you require to build variants package components. The next option will allow you to use these functions. See "importing" for more options. You can omit empty import argument lists when passing an array reference. The "subs" option is an array reference of subroutine names that are exported by the packages specified with "importing". These subroutines will be proxied from your variable package to the variant to be generated. With "importing" initializing your package and "subs" declaring what subroutines you want to use to build a variant, you can now write a "make_variant" method building your variants. Declaring a method to produce variants Every time a user requests a new variant, a method named "make_variant" will be called with the name of the target package and the arguments from the user. It can then use the proxied subroutines declared with "subs" to customize the variant package. An "install" subroutine is exported as well allowing you to dynamically install methods into the variant package. If these options aren't flexible enough, you can use the passed name of the variant package to do any other kind of customizations. sub make_variant { my ($class, $target, @arguments) = @_; # ... # customization goes here # ... } When the method is finished, the user will receive the name of the new variant package you just set up. Using variable packages After your variable package is created your users can get a variant generator subroutine by simply importing your package. use My::Variant; my $new_variant_package = Variant(@variant_arguments); # the variant package is now fully initialized and used You can import the subroutine under a different name by specifying an "as" argument. Dynamic creation of variant packages For regular uses, the normal import provides more than enough flexibility. However, if you want to create variants of dynamically determined packages, you can use the "build_variant_of" method. You can use this to create variants of other packages and pass arguments on to them to allow more modular and extensible variants. OPTIONS These are the options that can be passed when importing "Package::Variant". They describe the environment in which the variants are created. use Package::Variant importing => { $package => \@import_arguments, ... }, subs => [ @proxied_subroutines ]; importing This option is a hash reference mapping package names to array references containing import arguments. The packages will be imported with the given arguments by every variant before the "make_variant" method is asked to create the package (this is done using Import::Into). If import order is important to you, you can also pass the "importing" arguments as a flat array reference: use Package::Variant importing => [ 'PackageA', 'PackageB' ]; # same as use Package::Variant importing => [ 'PackageA' => [], 'PackageB' => [] ]; # or use Package::Variant importing => { 'PackageA' => [], 'PackageB' => [] }; The import method will be called even if the list of import arguments is empty or not specified, If you just want to import a single package's default exports, you can also pass a string instead: use Package::Variant importing => 'Package'; subs An array reference of strings listing the names of subroutines that should be proxied. These subroutines are expected to be installed into the new variant package by the modules imported with "importing". Subroutines with the same name will be available in your variable package, and will proxy through to the newly created package when used within "make_variant". VARIABLE PACKAGE METHODS These are methods on the variable package you declare when you import "Package::Variant". make_variant Some::Variant::Package->make_variant( $target, @arguments ); You need to provide this method. This method will be called for every new variant of your package. This method should use the subroutines declared in "subs" to customize the new variant package. This is a class method receiving the $target package and the @arguments defining the requested variant. make_variant_package_name Some::Variant::Package->make_variant_package_name( @arguments ); You may optionally provide this method. If present, this method will be used to determine the package name for a particular variant being constructed. If you do not implement it, a unique package name something like Some::Variant::Package::_Variant_A003 will be created for you. import use Some::Variant::Package; my $variant_package = Package( @arguments ); This method is provided for you. It will allow a user to "use" your package and receive a subroutine taking @arguments defining the variant and returning the name of the newly created variant package. The following options can be specified when importing: * as use Some::Variant::Package as => 'Foo'; my $variant_package = Foo(@arguments); Exports the generator subroutine under a different name than the default. build_variant use Some::Variant::Package (); my $variant_package = Some::Variant::Package->build_variant( @arguments ); This method is provided for you. It will generate a variant package and return its name, just like the generator sub provided by "import". This allows you to avoid importing anything into the consuming package. "Package::Variant" METHODS These methods are available on "Package::Variant" itself. build_variant_of my $variant_package = Package::Variant ->build_variant_of($variable_package, @arguments); This is the dynamic method of creating new variants. It takes the $variable_package, which is a pre-declared variable package, and a set of @arguments passed to the package to generate a new $variant_package, which will be returned. import use Package::Variant @options; Sets up the environment in which you declare the variants of your packages. See "OPTIONS" for details on the available options and "EXPORTS" for a list of exported subroutines. EXPORTS Additionally to the proxies for subroutines provided in "subs", the following exports will be available in your variable package: install install($method_name, $code_reference); Installs a method with the given $method_name into the newly created variant package. The $code_reference will be used as the body for the method, and if Sub::Name is available the coderef will be named. If you want to name it something else, then use: install($method_name, $name_to_use, $code_reference); AUTHOR mst - Matt S. Trout (cpan:MSTROUT) CONTRIBUTORS phaylon - Robert Sedlacek (cpan:PHAYLON) haarg - Graham Knop (cpan:HAARG) COPYRIGHT Copyright (c) 2010-2012 the "Package::Variant" "AUTHOR" and "CONTRIBUTORS" as listed above. LICENSE This library is free software and may be distributed under the same terms as perl itself. Package-Variant-1.003002/maint/0000755000372100001440000000000012554742650015572 5ustar matthewtusersPackage-Variant-1.003002/maint/Makefile.PL.include0000644000372100001440000000040212545555151021160 0ustar matthewtusersBEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") } use lib "Distar/lib"; use Distar; use ExtUtils::MakeMaker 6.68; # ensure meta-spec v2 compatibility author 'mst - Matt S. Trout (cpan:MSTROUT) '; Package-Variant-1.003002/MANIFEST0000644000372100001440000000066012554742650015615 0ustar matthewtusersChanges lib/Package/Variant.pm maint/Makefile.PL.include Makefile.PL MANIFEST This list of files t/01simple.t t/10argument-types.t t/11dynamic-build.t t/20moo-param-role.t t/30-pragma-leak.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) README README file (added by Distar) Package-Variant-1.003002/t/0000755000372100001440000000000012554742650014725 5ustar matthewtusersPackage-Variant-1.003002/t/30-pragma-leak.t0000644000372100001440000000106712554742570017520 0ustar matthewtusersuse strictures 2; use Test::More; use Test::Fatal; use Package::Variant (); BEGIN { package TestPragma; use Package::Variant importing => [ 'strict' ]; sub make_variant { } $INC{'TestPragma.pm'} = __FILE__; } is exception { eval q{ no strict; use TestPragma; $var = $var; 1; } or die $@; }, undef, 'pragmas not applied where PV package used'; is exception { eval q{ no strict; BEGIN { my $p = TestPragma(); } $var2 = $var2; 1; } or die $@; }, undef, 'pragmas not applied where PV generator used'; done_testing; Package-Variant-1.003002/t/01simple.t0000644000372100001440000000744212554742570016554 0ustar matthewtusersuse strictures 2; use Test::More; use Test::Fatal; use Package::Variant (); my @DECLARED; BEGIN { package TestSugar; use Exporter 'import'; our @EXPORT_OK = qw( declare ); sub declare { push @DECLARED, [@_] } $INC{'TestSugar.pm'} = __FILE__; } BEGIN { package TestVariable; use Package::Variant importing => { 'TestSugar' => [qw( declare )] }, subs => [qw( declare )]; sub make_variant { my ($class, $target, @args) = @_; ::ok(__PACKAGE__->can('install'), 'install() is available') or ::BAIL_OUT('install() subroutine was not exported!'); ::ok(__PACKAGE__->can('declare'), 'declare() import is available') or ::BAIL_OUT('proxy declare() subroutine was not exported!'); declare target => $target; declare args => [@args]; declare class => $class->_test_class_method; install target => sub { $target }; install args => sub { [@args] }; } sub _test_class_method { return shift; } $INC{'TestVariable.pm'} = __FILE__; } my $variant = do { package TestScopeA; use TestVariable; TestVariable(3..7); }; ok defined($variant), 'new variant is a defined value'; ok length($variant), 'new variant has length'; is $variant->target, $variant, 'target was new variant'; is_deeply $variant->args, [3..7], 'correct arguments received'; is_deeply shift(@DECLARED), [target => $variant], 'target passed via proxy'; is_deeply shift(@DECLARED), [args => [3..7]], 'arguments passed via proxy'; is_deeply shift(@DECLARED), [class => 'TestVariable'], 'class method resolution'; is scalar(@DECLARED), 0, 'proxy sub called right amount of times'; use TestVariable as => 'RenamedVar'; is exception { my $renamed = RenamedVar(9..12); is_deeply $renamed->args, [9..12], 'imported generator can be renamed'; }, undef, 'no errors for renamed usage'; my @imported; BEGIN { package TestImportableA; sub import { push @imported, shift } $INC{'TestImportableA.pm'} = __FILE__; package TestImportableB; sub import { push @imported, shift } $INC{'TestImportableB.pm'} = __FILE__; package TestArrayImports; use Package::Variant importing => [ 'TestImportableA', 'TestImportableB', ]; sub make_variant { } $INC{'TestArrayImports.pm'} = __FILE__; } use TestArrayImports; TestArrayImports(23); is_deeply [@imported], [qw( TestImportableA TestImportableB )], 'multiple imports in the right order'; BEGIN { package TestSingleImport; use Package::Variant importing => 'TestImportableA'; sub make_variant { } $INC{'TestSingleImport.pm'} = __FILE__; } @imported = (); use TestSingleImport; TestSingleImport(23); is_deeply [@imported], [qw( TestImportableA )], 'scalar import works'; @imported = (); TestSingleImport::->build_variant; is_deeply [@imported], [qw( TestImportableA )], 'build_variant works'; like exception { Package::Variant->import( importing => \'foo', subs => [qw( foo )], ); }, qr/importing.+option.+hash.+array/i, 'invalid "importing" option'; like exception { Package::Variant->import( importing => { foo => \'bar' }, subs => [qw( bar )], ); }, qr/import.+argument.+foo.+not.+array/i, 'invalid import argument list'; like exception { Package::Variant->import( importing => [ foo => ['bar'], ['bam'], subs => [qw( bar )] ], ); }, qr/value.+3.+importing.+not.+string/i, 'importing array invalid key'; like exception { Package::Variant->import( importing => [ foo => \'bam', subs => [qw( bar )] ], ); }, qr/value.+2.+foo.+importing.+array/i, 'importing array invalid list'; BEGIN { package TestOverrideName; use Package::Variant; sub make_variant_package_name { my (undef, @args) = @_; return $args[0]; } sub make_variant { install hey => sub { 'hey' }; } } is(TestOverrideName::->build_variant('hey'), 'hey'); is(hey->hey, 'hey', 'hey'); done_testing; Package-Variant-1.003002/t/20moo-param-role.t0000644000372100001440000000154712554742570020113 0ustar matthewtusersuse strictures 2; use Test::More; BEGIN { eval { require Moo::Role; 1 } or plan skip_all => q{Requires Moo::Role}; } BEGIN { package My::Role::OnOff; use Package::Variant importing => { 'Moo::Role' => [] }, subs => [ qw(has before after around) ]; sub make_variant { my ($me, $into, %args) = @_; my $name = $args{name}; has $name => (is => 'rw'); install "${name}_on" => sub { shift->$name(1); }; install "${name}_off" => sub { shift->$name(0); }; } $INC{"My/Role/OnOff.pm"} = __FILE__; } BEGIN { package LightSwitch; use My::Role::OnOff; use Moo; with OnOff(name => 'lights'); } my $lights = LightSwitch->new; is($lights->lights, undef, 'Initial state'); is($lights->lights_on, 1, 'Turn on'); is($lights->lights, 1, 'On'); is($lights->lights_off, 0, 'Turn off'); is($lights->lights, 0, 'Off'); done_testing; Package-Variant-1.003002/t/11dynamic-build.t0000644000372100001440000000056212554742570020001 0ustar matthewtusersuse strictures 2; use Test::More; BEGIN { package TestVariable; use Package::Variant; sub make_variant { my ($class, $target, @args) = @_; install variant_values => sub { [@args] }; } } is_deeply( Package::Variant ->build_variant_of('TestVariable', 3..7) ->variant_values, [3..7], 'build_variant_of with scalar values', ); done_testing; Package-Variant-1.003002/t/10argument-types.t0000644000372100001440000000103212554742570020234 0ustar matthewtusersuse strictures 2; use Test::More; BEGIN { package TestVariable; use Package::Variant; sub make_variant { my ($class, $target, @args) = @_; install variant_values => sub { [@args] }; } $INC{'TestVariable.pm'} = __FILE__; } use TestVariable; is_deeply TestVariable(23)->variant_values, [23], 'simple value argument'; is_deeply TestVariable(3..7)->variant_values, [3..7], 'multiple value arguments'; is_deeply TestVariable({ foo => 23 })->variant_values, [{ foo => 23 }], 'hash reference argument'; done_testing; Package-Variant-1.003002/Changes0000644000372100001440000000230112554742644015754 0ustar matthewtusersRevision history for Package-Variant 1.003002 - 2015-07-25 - also switch the tests to strictures 2 (aaaaaaaaaaaaaaaaaaaaaaaaaa) 1.003001 - 2015-07-25 - also switch the documentation to strictures 2 (slow clap for mst there) 1.003000 - 2015-07-25 - switch to strictures 2 - add make_variant_package_name optional method 1.002002 - 2014-08-21 - fix license in metadata 1.002001 - 2014-08-16 - specify perl prerequisite on metadata - documentation fixes and clarifications 1.002000 - 2013-12-10 - add build_variant method on variable packages, to allow avoiding importing a generator sub - fix pragmas applied by modules listed in "importing" from leaking out into unexpected scopes 1.001004 - 2013-05-04 - fix documentation of "build_variant_of" method (RT#84554 -- thanks, Scott Miller!) 1.001003 - 2013-03-25 - fix NAME in Makefile.PL (RT#84209) 1.001002 - 2012-09-19 - Declare the Test::Fatal build dependency 1.001001 - 2012-05-12 - Actually declare the Import::Into dependency (stupid mst) 1.001000 - 2012-05-12 - Switch to Import::Into for exporting other things - Use Sub::Name to name installed things if available 1.000000 - 2012-01-23 - initial release