1 package Package::Variant;
5 use Module::Runtime qw(require_module);
8 our $VERSION = '1.002000';
10 $VERSION = eval $VERSION;
14 my $sanitize_importing = sub {
21 : (ref($spec) eq 'ARRAY')
23 : (ref($spec) eq 'HASH')
25 croak qq{The import argument list for '$_' is not an array ref}
26 unless ref($spec->{$_}) eq 'ARRAY';
29 : croak q{The 'importing' option has to be either a hash or array ref};
33 my $key = shift @specced;
34 croak qq{Value $arg_count in 'importing' is not a package string},
36 unless defined($key) and not(ref $key);
39 (not(@specced) or (defined($specced[0]) and not ref($specced[0])))
41 : (ref($specced[0]) eq 'ARRAY')
42 ? do { $arg_count++; shift @specced }
44 qq{Value $arg_count for package '$key' in 'importing' is not}
45 . qq{ a package string or array ref}
47 push @imports, [$key, $import_args];
52 my $sub_namer = eval {
53 require Sub::Name; sub { shift if @_ > 2; Sub::Name::subname(@_) }
57 my $variable = caller;
59 my $last = (split '::', $variable)[-1];
63 $Variable{$variable} = {
67 importing => $me->$sanitize_importing($args{importing}),
70 map +($_ => sub {}), @{$args{subs}||[]},
73 *{"${variable}::import"} = sub {
75 my (undef, %arg) = @_;
76 my $as = defined($arg{as}) ? $arg{as} : $last;
78 *{"${target}::${as}"} = sub {
79 $me->build_variant_of($variable, @_);
82 my $subs = $Variable{$variable}{subs};
83 foreach my $name (keys %$subs) {
84 *{"${variable}::${name}"} = sub {
85 goto &{$subs->{$name}}
88 *{"${variable}::install"} = sub {
89 goto &{$Variable{$variable}{install}};
91 *{"${variable}::build_variant"} = sub {
93 $me->build_variant_of($variable, @_);
97 sub build_variant_of {
98 my ($me, $variable, @args) = @_;
99 my $variant_name = "${variable}::_Variant_".++$Variable{$variable}{anon};
100 foreach my $to_import (@{$Variable{$variable}{args}{importing}}) {
101 my ($pkg, $args) = @$to_import;
103 eval q{ BEGIN { $pkg->import::into($variant_name, @{$args}) }; 1; }
106 my $subs = $Variable{$variable}{subs};
107 local @{$subs}{keys %$subs} = map $variant_name->can($_), keys %$subs;
108 local $Variable{$variable}{install} = sub {
109 my $full_name = "${variant_name}::".shift;
111 my $ref = $sub_namer->($full_name, @_);
116 $variable->make_variant($variant_name, @args);
117 return $variant_name;
126 Package::Variant - Parameterizable packages
130 # declaring a variable Moo role
131 package My::VariableRole::ObjectAttr;
134 # what modules to 'use'
135 importing => ['Moo::Role'],
136 # proxied subroutines
137 subs => [ qw(has around before after with) ];
140 my ($class, $target_package, %arguments) = @_;
142 my $name = $arguments{name};
143 # use proxied 'has' to add an attribute
144 has $name => (is => 'lazy');
145 # install a builder method
146 install "_build_${name}" => sub {
147 return $arguments{class}->new;
152 package My::Class::WithObjectAttr;
155 use My::VariableRole::ObjectAttr;
157 with ObjectAttr(name => 'some_obj', class => 'Some::Class');
160 my $obj = My::Class::WithObjectAttr->new;
161 $obj->some_obj; # returns a Some::Class instance
165 This module allows you to build a variable package that returns different
166 variant packages depending on what parameters are given.
168 Users of your variable package will receive a subroutine able to take parameters
169 and return the name of a suitable variant package. The implementation does
170 not care about what kind of variant package it builds.
172 =head2 Declaring a variable package
174 There are two important parts to creating a variable package. You first
175 have to give C<Package::Variant> some basic information about what kind of
176 variant packages you want to provide, and how. The second part is implementing a
177 method receiving the user's arguments and generating your variant packages.
179 =head3 Setting up the environment for building variants
181 When you C<use Package::Variant>, you pass along some arguments that
182 describe how you intend to build your variants.
185 importing => { $package => \@import_arguments, ... },
186 subs => [ @proxied_subroutine_names ];
188 The L</importing> option needs to be a hash or array reference with
189 package names to be C<use>d as keys, and array references containing the
190 import arguments as values. These packages will be imported into every new
191 variant package, and need to set up every declarative subroutine you require to
192 build your variable package. The next option will allow you to use these
193 functions. See L</importing> for more options. You can omit empty import
194 argument lists when passing an array reference.
196 The L</subs> option is an array reference of subroutine names that are
197 exported by the packages specified with L</importing>. These subroutines
198 will be proxied from your variable package to the variant to be
201 With L</importing> initializing your package and L</subs> declaring what
202 subroutines you want to use to build a variant, you can now write a
203 L</make_variant> method building your variants.
205 =head3 Declaring a method to produce variants
207 Every time a user requests a new variant a method named L</make_variant>
208 will be called with the name of the target package and the arguments from
211 It can then use the proxied subroutines declared with L</subs> to
212 customize the variant package. An L</install> subroutine is exported as well
213 allowing you to dynamically install methods into the variant package. If these
214 options aren't flexible enough, you can use the passed name of the variant
215 package to do any other kind of customizations.
218 my ($class, $target, @arguments) = @_;
220 # customization goes here
224 When the method is finished, the user will receive the name of the new variant
225 package you just set up.
227 =head2 Using variable packages
229 After your variable package is L<created|/Declaring a variable package>
230 your users can get a variant generating subroutine by simply importing
234 my $new_variant_package = Variant(@variant_arguments);
235 # the variant package is now fully initialized and used
237 You can import the subroutine under a different name by specifying an C<as>
240 =head2 Dynamic creation of variant packages
242 For regular uses, the L<normal import|/Using variable packages> provides
243 more than enough flexibility. However, if you want to create variants of
244 dynamically determined packages, you can use the L</build_variant_of>
247 You can use this to create variants of other packages and pass arguments
248 on to them to allow more modular and extensible variants.
252 These are the options that can be passed when importing
253 C<Package::Variant>. They describe the environment in which the variants
257 importing => { $package => \@import_arguments, ... },
258 subs => [ @proxied_subroutines ];
262 This option is a hash reference mapping package names to array references
263 containing import arguments. The packages will be imported with the given
264 arguments by every variant before the L</make_variant> method is asked
265 to create the package (this is done using L<Import::Into>).
267 If import order is important to you, you can also pass the C<importing>
268 arguments as a flat array reference:
271 importing => [ 'PackageA', 'PackageB' ];
275 importing => [ 'PackageA' => [], 'PackageB' => [] ];
279 importing => { 'PackageA' => [], 'PackageB' => [] };
281 The import method will be called even if the list of import arguments is
282 empty or not specified,
284 If you just want to import a single package's default exports, you can
285 also pass a string instead:
287 use Package::Variant importing => 'Package';
291 An array reference of strings listing the names of subroutines that should
292 be proxied. These subroutines are expected to be installed into the new
293 variant package by the modules imported with L</importing>. Subroutines
294 with the same name will be available in your variable package, and will
295 proxy through to the newly created package when used within
298 =head1 VARIABLE PACKAGE METHODS
300 These are methods on the variable package you declare when you import
305 Some::Variant::Package->make_variant( $target, @arguments );
307 B<You need to provide this method.> This method will be called for every
308 new variant of your package. This method should use the subroutines
309 declared in L</subs> to customize the new variant package.
311 This is a class method receiving the C<$target> package and the
312 C<@arguments> defining the requested variant.
316 use Some::Variant::Package;
317 my $variant_package = Package( @arguments );
319 This method is provided for you. It will allow a user to C<use> your
320 package and receive a subroutine taking C<@arguments> defining the variant
321 and returning the name of the newly created variant package.
323 The following options can be specified when importing:
329 use Some::Variant::Package as => 'Foo';
330 my $variant_package = Foo(@arguments);
332 Exports the generator subroutine under a different name than the default.
338 use Some::Variant::Package ();
339 my $variant_package = Some::Variant::Package->build_variant( @arguments );
341 This method is provided for you. It will generate a variant package
342 and return its name, just like the generator sub provided by
343 L</import>. This allows you to avoid importing anything into the
346 =head1 C<Package::Variant> METHODS
348 These methods are available on C<Package::Variant> itself.
350 =head2 build_variant_of
352 my $variant_package = Package::Variant
353 ->build_variant_of($variable_package, @arguments);
355 This is the dynamic method of creating new variants. It takes the
356 C<$variable_package>, which is a pre-declared variable package, and a set
357 of C<@arguments> passed to the package to generate a new
358 C<$variant_package>, which will be returned.
362 use Package::Variant @options;
364 Sets up the environment in which you declare the variants of your
365 packages. See L</OPTIONS> for details on the available options and
366 L</EXPORTS> for a list of exported subroutines.
370 Additionally to the proxies for subroutines provided in L</subs>, the
371 following exports will be available in your variable package:
375 install($method_name, $code_reference);
377 Installs a method with the given C<$method_name> into the newly created
378 variant package. The C<$code_reference> will be used as the body for the
379 method, and if L<Sub::Name> is available the coderef will be named. If you
380 want to name it something else, then use:
382 install($method_name, $name_to_use, $code_reference);
386 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
390 phaylon - Robert Sedlacek (cpan:PHAYLON) <r.sedlacek@shadowcat.co.uk>
392 haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
396 Copyright (c) 2010-2012 the C<Package::Variant> L</AUTHOR> and
397 L</CONTRIBUTORS> as listed above.
401 This library is free software and may be distributed under the same
402 terms as perl itself.