1 package Package::Variant;
5 use Module::Runtime qw(require_module);
8 our $VERSION = '1.002002';
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_package_name {
98 my ($me, $variable, @args) = @_;
99 if ($variable->can('make_variant_package_name')) {
100 return $variable->make_variant_package_name(@args);
102 return "${variable}::_Variant_".++$Variable{$variable}{anon};
105 sub build_variant_of {
106 my ($me, $variable, @args) = @_;
107 my $variant_name = $me->build_variant_package_name($variable, @args);
108 foreach my $to_import (@{$Variable{$variable}{args}{importing}}) {
109 my ($pkg, $args) = @$to_import;
111 eval q{ BEGIN { $pkg->import::into($variant_name, @{$args}) }; 1; }
114 my $subs = $Variable{$variable}{subs};
115 local @{$subs}{keys %$subs} = map $variant_name->can($_), keys %$subs;
116 local $Variable{$variable}{install} = sub {
117 my $full_name = "${variant_name}::".shift;
119 my $ref = $sub_namer->($full_name, @_);
124 $variable->make_variant($variant_name, @args);
125 return $variant_name;
134 Package::Variant - Parameterizable packages
138 # declaring a variable Moo role
139 package My::VariableRole::ObjectAttr;
142 # what modules to 'use'
143 importing => ['Moo::Role'],
144 # proxied subroutines
145 subs => [ qw(has around before after with) ];
148 my ($class, $target_package, %arguments) = @_;
150 my $name = $arguments{name};
151 # use proxied 'has' to add an attribute
152 has $name => (is => 'lazy');
153 # install a builder method
154 install "_build_${name}" => sub {
155 return $arguments{class}->new;
160 package My::Class::WithObjectAttr;
163 use My::VariableRole::ObjectAttr;
165 with ObjectAttr(name => 'some_obj', class => 'Some::Class');
168 my $obj = My::Class::WithObjectAttr->new;
169 $obj->some_obj; # returns a Some::Class instance
173 This module allows you to build a variable package that contains a package
174 template and can use it to build variant packages at runtime.
176 Your variable package will export a subroutine which will build a variant
177 package, combining its arguments with the template, and return the name of the
180 The implementation does not care about what kind of packages it builds, be they
181 simple function exporters, classes, singletons or something entirely different.
183 =head2 Declaring a variable package
185 There are two important parts to creating a variable package. You first
186 have to give C<Package::Variant> some basic information about what kind of
187 variant packages you want to provide, and how. The second part is implementing a
188 method which builds the components of the variant packages that use the user's
189 arguments or cannot be provided with a static import.
191 =head3 Setting up the environment for building variants
193 When you C<use Package::Variant>, you pass along some arguments that
194 describe how you intend to build your variants.
197 importing => { $package => \@import_arguments, ... },
198 subs => [ @proxied_subroutine_names ];
200 The L</importing> option needs to be a hash or array reference with
201 package names to be C<use>d as keys, and array references containing the
202 import arguments as values. These packages will be imported into every new
203 variant package, to provide static functionality of the variant packages and to
204 set up every declarative subroutine you require to build variants package
205 components. The next option will allow you to use these functions. See
206 L</importing> for more options. You can omit empty import argument lists when
207 passing an array reference.
209 The L</subs> option is an array reference of subroutine names that are
210 exported by the packages specified with L</importing>. These subroutines
211 will be proxied from your variable package to the variant to be
214 With L</importing> initializing your package and L</subs> declaring what
215 subroutines you want to use to build a variant, you can now write a
216 L</make_variant> method building your variants.
218 =head3 Declaring a method to produce variants
220 Every time a user requests a new variant, a method named L</make_variant>
221 will be called with the name of the target package and the arguments from
224 It can then use the proxied subroutines declared with L</subs> to
225 customize the variant package. An L</install> subroutine is exported as well
226 allowing you to dynamically install methods into the variant package. If these
227 options aren't flexible enough, you can use the passed name of the variant
228 package to do any other kind of customizations.
231 my ($class, $target, @arguments) = @_;
233 # customization goes here
237 When the method is finished, the user will receive the name of the new variant
238 package you just set up.
240 =head2 Using variable packages
242 After your variable package is L<created|/Declaring a variable package>
243 your users can get a variant generator subroutine by simply importing
247 my $new_variant_package = Variant(@variant_arguments);
248 # the variant package is now fully initialized and used
250 You can import the subroutine under a different name by specifying an C<as>
253 =head2 Dynamic creation of variant packages
255 For regular uses, the L<normal import|/Using variable packages> provides
256 more than enough flexibility. However, if you want to create variants of
257 dynamically determined packages, you can use the L</build_variant_of>
260 You can use this to create variants of other packages and pass arguments
261 on to them to allow more modular and extensible variants.
265 These are the options that can be passed when importing
266 C<Package::Variant>. They describe the environment in which the variants
270 importing => { $package => \@import_arguments, ... },
271 subs => [ @proxied_subroutines ];
275 This option is a hash reference mapping package names to array references
276 containing import arguments. The packages will be imported with the given
277 arguments by every variant before the L</make_variant> method is asked
278 to create the package (this is done using L<Import::Into>).
280 If import order is important to you, you can also pass the C<importing>
281 arguments as a flat array reference:
284 importing => [ 'PackageA', 'PackageB' ];
288 importing => [ 'PackageA' => [], 'PackageB' => [] ];
292 importing => { 'PackageA' => [], 'PackageB' => [] };
294 The import method will be called even if the list of import arguments is
295 empty or not specified,
297 If you just want to import a single package's default exports, you can
298 also pass a string instead:
300 use Package::Variant importing => 'Package';
304 An array reference of strings listing the names of subroutines that should
305 be proxied. These subroutines are expected to be installed into the new
306 variant package by the modules imported with L</importing>. Subroutines
307 with the same name will be available in your variable package, and will
308 proxy through to the newly created package when used within
311 =head1 VARIABLE PACKAGE METHODS
313 These are methods on the variable package you declare when you import
318 Some::Variant::Package->make_variant( $target, @arguments );
320 B<You need to provide this method.> This method will be called for every
321 new variant of your package. This method should use the subroutines
322 declared in L</subs> to customize the new variant package.
324 This is a class method receiving the C<$target> package and the
325 C<@arguments> defining the requested variant.
327 =head2 make_variant_package_name
329 Some::Variant::Package->make_variant_package_name( @arguments );
331 B<You may optionally provide this method.> If present, this method will be
332 used to determine the package name for a particular variant being constructed.
334 If you do not implement it, a unique package name something like
336 Some::Variant::Package::_Variant_A003
338 will be created for you.
342 use Some::Variant::Package;
343 my $variant_package = Package( @arguments );
345 This method is provided for you. It will allow a user to C<use> your
346 package and receive a subroutine taking C<@arguments> defining the variant
347 and returning the name of the newly created variant package.
349 The following options can be specified when importing:
355 use Some::Variant::Package as => 'Foo';
356 my $variant_package = Foo(@arguments);
358 Exports the generator subroutine under a different name than the default.
364 use Some::Variant::Package ();
365 my $variant_package = Some::Variant::Package->build_variant( @arguments );
367 This method is provided for you. It will generate a variant package
368 and return its name, just like the generator sub provided by
369 L</import>. This allows you to avoid importing anything into the
372 =head1 C<Package::Variant> METHODS
374 These methods are available on C<Package::Variant> itself.
376 =head2 build_variant_of
378 my $variant_package = Package::Variant
379 ->build_variant_of($variable_package, @arguments);
381 This is the dynamic method of creating new variants. It takes the
382 C<$variable_package>, which is a pre-declared variable package, and a set
383 of C<@arguments> passed to the package to generate a new
384 C<$variant_package>, which will be returned.
388 use Package::Variant @options;
390 Sets up the environment in which you declare the variants of your
391 packages. See L</OPTIONS> for details on the available options and
392 L</EXPORTS> for a list of exported subroutines.
396 Additionally to the proxies for subroutines provided in L</subs>, the
397 following exports will be available in your variable package:
401 install($method_name, $code_reference);
403 Installs a method with the given C<$method_name> into the newly created
404 variant package. The C<$code_reference> will be used as the body for the
405 method, and if L<Sub::Name> is available the coderef will be named. If you
406 want to name it something else, then use:
408 install($method_name, $name_to_use, $code_reference);
412 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
416 phaylon - Robert Sedlacek (cpan:PHAYLON) <r.sedlacek@shadowcat.co.uk>
418 haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
422 Copyright (c) 2010-2012 the C<Package::Variant> L</AUTHOR> and
423 L</CONTRIBUTORS> as listed above.
427 This library is free software and may be distributed under the same
428 terms as perl itself.