1 package Package::Variant;
11 my $last = (split '::', $target)[-1];
13 my $variable = $target;
16 $Variable{$variable} = {
20 map +($_ => sub {}), @{$args{subs}||[]},
23 *{"${target}::import"} = sub {
25 my (undef, %arg) = @_;
26 my $as = defined($arg{as}) ? $arg{as} : $last;
28 *{"${target}::${as}"} = sub {
29 $me->build_variant_of($variable, @_);
32 my $subs = $Variable{$variable}{subs};
33 foreach my $name (keys %$subs) {
34 *{"${target}::${name}"} = sub {
35 goto &{$subs->{$name}}
38 *{"${target}::install"} = sub {
39 goto &{$Variable{$variable}{install}};
43 my $sanitize_importing = sub {
47 return [map [$_ => $spec->{$_}], keys %$spec]
48 if ref $spec eq 'HASH';
49 croak q{The 'importing' option has to be either a hash or array ref}
50 unless ref $spec eq 'ARRAY';
54 push @imports, [shift(@specced), shift(@specced)];
59 sub build_variant_of {
60 my ($me, $variable, @args) = @_;
61 my $variant_name = "${variable}::_Variant_".++$Variable{$variable}{anon};
63 ->$sanitize_importing($Variable{$variable}{args}{importing});
64 my $setup = join("\n",
65 "package ${variant_name};",
69 not(defined $import->[$_][1])
72 q!@{$import->[%d][1]}!,
79 or die "evaling ${setup} failed: $@";
80 my $subs = $Variable{$variable}{subs};
81 local @{$subs}{keys %$subs} = map $variant_name->can($_), keys %$subs;
82 local $Variable{$variable}{install} = sub {
83 my ($name, $ref) = @_;
85 *{"${variant_name}::${name}"} = $ref;
87 $variable->make_variant($variant_name, @args);
97 Package::Variant - Parameterizable packages
101 # declaring a variable Moo role
102 package My::Role::ObjectAttr;
105 # what modules to 'use'
106 importing => { 'Moo::Role' => undef },
107 # proxied subroutines
108 subs => [qw( has around before after extends )],
111 my ($class, $target_package, %arguments) = @_;
113 my $name = $arguments{name};
114 # use proxied 'has' to add an attribute
115 has $name => (is => 'lazy');
116 # install a builder method
117 install "_build_${name}" => sub {
118 return $arguments{class}->new;
123 package My::Class::WithObjectAttr;
126 use My::Role::ObjectAttr;
128 with ObjectAttr(name => 'some_obj', class => 'Some::Class');
131 my $obj = My::Class::WithObjectAttr->new;
132 $obj->some_obj; # returns a Some::Class instance
136 This module allows you to build packages that return different variations
137 depending on what parameters are given.
139 Users of your package will receive a subroutine able to take parameters
140 and return the name of a suitable variant package. The implmenetation does
141 not care about what kind of package it builds.
143 =head2 Declaring a variable package
145 There are two important parts to creating a variable package. You first
146 have to give C<Package::Variant> some basic information about what kind of
147 package you want to provide, and how. The second part is implementing a
148 method receiving the user's arguments and generating your variants.
150 =head3 Setting up the environment for building variations
152 When you C<use Package::Variant>, you pass along some arguments that
153 describe how you intend to build your variations.
156 importing => { $package => \@import_arguments, ... },
157 subs => [ @proxied_subroutine_names ];
159 The L</importing> option needs to be a hash reference with package names
160 to be C<use>d as keys, and array references containing the import
161 arguments as values. These packages will be imported into every new
162 variant, and need to set up every declarative subroutine you require to
163 build your variable package. The next option will allow you to use these
164 functions. See L</importing> for more options.
166 The L</subs> option is an array reference of subroutine names that are
167 exported by the packages specified with L</importing>. These subroutines
168 will be proxied from your declaration package to the variant to be
171 With L</importing> initializing your package and L</subs> declaring what
172 subroutines you want to use to build a variant, you can now write a
173 L</make_variant> method building your variants.
175 =head3 Declaring a method to produce variants
177 Every time a user requests a new variant a method named L</make_variant>
178 will be called with the name of the target package and the arguments from
181 It can then use the proxied subroutines declared with L</subs> to
182 customize the new package. An L</install> subroutine is exported as well
183 allowing you to dynamically install methods into the new package. If these
184 options aren't flexible enough, you can use the passed name of the new
185 package to do any other kind of customizations.
188 my ($class, $target, @arguments) = @_;
190 # customization goes here
194 When the method is finished, the user will receive the name of the new
195 package variant you just set up.
197 =head2 Using variable packages
199 After your variable package is L<created|/Declaring a variable package>
200 your users can get a variant generating subroutine by simply importing
204 my $new_variant_package = Variant( @variant_arguments );
206 The package is now fully initialized and used. You can import the
207 subroutine under a different name by specifying an C<as> argument.
209 =head2 Dynamic creation of variant packages
211 For regular uses, the L<normal import|/Using variable packages> provides
212 more than enough flexibility. However, if you want to create variations of
213 dynamically determined packages, you can use the L</build_variation_of>
216 You can use this to create variations of other packages and pass arguments
217 on to them to allow more modular and extensible variations.
221 These are the options that can be passed when importing
222 C<Package::Variant>. They describe the environment in which the variants
226 importing => { $package => \@import_arguments, ... },
227 subs => [ @proxied_subroutines ];
231 This option is a hash reference mapping package names to array references
232 containing import arguments. The packages will be C<use>d with the given
233 arguments by every variation before the L</make_variant> method is asked
234 to create the package.
236 If import order is important to you, you can also pass the C<importing>
237 arguments as a flag array reference:
240 importing => [ PackageA => [], PackageB => [] ];
242 If you want to import whatever the package exports by default, you have to
243 pass C<undef> instead of an empty array reference.
247 An array reference of strings listing the names of subroutines that should
248 be proxied. These subroutines are expected to be installed into the new
249 variant package by the modules imported with L</importing>. Subroutines
250 with the same name will be availabe in your declaration package, and will
251 proxy through to the newly created package when used within
254 =head1 VARIABLE PACKAGE METHODS
256 These are methods on the variable package you declare when you import
261 Some::Variant::Package->make_variant( $target, @arguments );
263 B<You need to provide this method.> This method will be called for every
264 new variant of your package. This method should use the subroutines
265 declared in L</subs> to customize the new variant package.
267 This is a class method receiving the C<$target> package and the
268 C<@arguments> defining the requested variant.
272 use Some::Variant::Package;
273 my $variant_package = Package( @arguments );
275 This method is provided for you. It will allow a user to C<use> your
276 package and receive a subroutine taking C<@arguments> defining the variant
277 and returning the name of the newly created variant package.
279 The following options can be specified when importing:
285 use Some::Variant::Package as => 'Foo';
286 my $variant_package = Foo( @arguments );
288 Exports the generator subroutine under a different name than the default.
292 =head1 C<Package::Variant> METHODS
294 These methods are available on C<Package::Variant> itself.
296 =head2 build_variation_of
298 my $variant_package = Package::Variant
299 ->build_variation_of( $variable_package, @arguments );
301 This is the dynamic method of creating new variants. It takes the
302 C<$variable_package>, which is a pre-declared variable package, and a set
303 of C<@arguments> passed to the package to generate a new
304 C<$variant_package>, which will be returned.
308 use Package::Variant @options;
310 Sets up the environment in which you declare the variants of your
311 packages. See L</OPTIONS> for details on the available options and
312 L</EXPORTS> for a list of exported subroutines.
316 Additionally to the proxies for subroutines provided in L</subs>, the
317 following exports will be available in your variable package:
321 install( $method_name, $code_reference );
323 Installs a method with the given C<$method_name> into the newly created
324 variant package. The C<$code_reference> will be used as the body for the
331 =item mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
337 Copyright (c) 2010-2011 the C<Package::Stash> L</AUTHOR> as listed above.
341 This library is free software and may be distributed under the same
342 terms as perl itself.