fix pragmas from "importing" leaking into outer scopes
[p5sagit/Package-Variant.git] / lib / Package / Variant.pm
CommitLineData
236a4386 1package Package::Variant;
2
3use strictures 1;
1bacb018 4use Import::Into;
3c1ca277 5use Module::Runtime qw(require_module);
1bacb018 6use Carp qw(croak);
236a4386 7
9b6aa559 8our $VERSION = '1.001004'; # 1.1.4
eacc208a 9
10$VERSION = eval $VERSION;
11
236a4386 12our %Variable;
13
115c342b 14my $sanitize_importing = sub {
15 my ($me, $spec) = @_;
16 return []
17 unless defined $spec;
203d81fc 18 my @specced =
19 not(ref $spec)
20 ? ($spec)
21 : (ref($spec) eq 'ARRAY')
22 ? (@$spec)
23 : (ref($spec) eq 'HASH')
24 ? (map {
25 croak qq{The import argument list for '$_' is not an array ref}
26 unless ref($spec->{$_}) eq 'ARRAY';
27 ($_ => $spec->{$_});
28 } sort keys %$spec)
29 : croak q{The 'importing' option has to be either a hash or array ref};
115c342b 30 my @imports;
203d81fc 31 my $arg_count = 1;
115c342b 32 while (@specced) {
33 my $key = shift @specced;
203d81fc 34 croak qq{Value $arg_count in 'importing' is not a package string},
35 $arg_count
36 unless defined($key) and not(ref $key);
37 $arg_count++;
38 my $import_args =
39 (not(@specced) or (defined($specced[0]) and not ref($specced[0])))
40 ? []
41 : (ref($specced[0]) eq 'ARRAY')
42 ? do { $arg_count++; shift @specced }
43 : croak(
44 qq{Value $arg_count for package '$key' in 'importing' is not}
45 . qq{ a package string or array ref}
46 );
47 push @imports, [$key, $import_args];
115c342b 48 }
49 return \@imports;
50};
51
ed98a1a0 52my $sub_namer = eval {
53 require Sub::Name; sub { shift if @_ > 2; Sub::Name::subname(@_) }
54} || sub { $_[-1] };
55
236a4386 56sub import {
57 my $target = caller;
58 my $me = shift;
59 my $last = (split '::', $target)[-1];
60 my $anon = 'A000';
61 my $variable = $target;
62 my %args = @_;
63 no strict 'refs';
64 $Variable{$variable} = {
65 anon => $anon,
115c342b 66 args => {
67 %args,
68 importing => $me->$sanitize_importing($args{importing}),
69 },
236a4386 70 subs => {
71 map +($_ => sub {}), @{$args{subs}||[]},
72 },
73 };
74 *{"${target}::import"} = sub {
75 my $target = caller;
0a7db8d2 76 my (undef, %arg) = @_;
77 my $as = defined($arg{as}) ? $arg{as} : $last;
236a4386 78 no strict 'refs';
0a7db8d2 79 *{"${target}::${as}"} = sub {
236a4386 80 $me->build_variant_of($variable, @_);
81 };
82 };
83 my $subs = $Variable{$variable}{subs};
84 foreach my $name (keys %$subs) {
85 *{"${target}::${name}"} = sub {
86 goto &{$subs->{$name}}
87 };
88 }
89 *{"${target}::install"} = sub {
90 goto &{$Variable{$variable}{install}};
91 }
92}
93
94sub build_variant_of {
95 my ($me, $variable, @args) = @_;
96 my $variant_name = "${variable}::_Variant_".++$Variable{$variable}{anon};
1bacb018 97 foreach my $to_import (@{$Variable{$variable}{args}{importing}}) {
98 my ($pkg, $args) = @$to_import;
3c1ca277 99 require_module $pkg;
100 eval q{ BEGIN { $pkg->import::into($variant_name, @{$args}) }; 1; }
101 or die $@;
1bacb018 102 }
236a4386 103 my $subs = $Variable{$variable}{subs};
104 local @{$subs}{keys %$subs} = map $variant_name->can($_), keys %$subs;
105 local $Variable{$variable}{install} = sub {
ed98a1a0 106 my $full_name = "${variant_name}::".shift;
107
108 my $ref = $sub_namer->($full_name, @_);
109
236a4386 110 no strict 'refs';
ed98a1a0 111 *$full_name = $ref;
236a4386 112 };
113 $variable->make_variant($variant_name, @args);
114 return $variant_name;
115}
116
1171;
0c378352 118
119__END__
120
121=head1 NAME
122
123Package::Variant - Parameterizable packages
124
125=head1 SYNOPSIS
126
127 # declaring a variable Moo role
128 package My::Role::ObjectAttr;
129 use strictures 1;
130 use Package::Variant
131 # what modules to 'use'
efaab257 132 importing => ['Moo::Role'],
0c378352 133 # proxied subroutines
2b728d4c 134 subs => [ qw(has around before after with) ],
0c378352 135
136 sub make_variant {
137 my ($class, $target_package, %arguments) = @_;
138 # access arguments
139 my $name = $arguments{name};
140 # use proxied 'has' to add an attribute
141 has $name => (is => 'lazy');
142 # install a builder method
143 install "_build_${name}" => sub {
144 return $arguments{class}->new;
145 };
146 }
147
148 # using the role
149 package My::Class::WithObjectAttr;
150 use strictures 1;
151 use Moo;
152 use My::Role::ObjectAttr;
153
154 with ObjectAttr(name => 'some_obj', class => 'Some::Class');
155
156 # using our class
157 my $obj = My::Class::WithObjectAttr->new;
158 $obj->some_obj; # returns a Some::Class instance
159
160=head1 DESCRIPTION
161
162This module allows you to build packages that return different variations
163depending on what parameters are given.
164
165Users of your package will receive a subroutine able to take parameters
328258e0 166and return the name of a suitable variant package. The implementation does
0c378352 167not care about what kind of package it builds.
168
169=head2 Declaring a variable package
170
171There are two important parts to creating a variable package. You first
172have to give C<Package::Variant> some basic information about what kind of
173package you want to provide, and how. The second part is implementing a
174method receiving the user's arguments and generating your variants.
175
176=head3 Setting up the environment for building variations
177
178When you C<use Package::Variant>, you pass along some arguments that
179describe how you intend to build your variations.
180
181 use Package::Variant
182 importing => { $package => \@import_arguments, ... },
183 subs => [ @proxied_subroutine_names ];
184
efaab257 185The L</importing> option needs to be a hash or array reference with
186package names to be C<use>d as keys, and array references containing the
187import arguments as values. These packages will be imported into every new
0c378352 188variant, and need to set up every declarative subroutine you require to
189build your variable package. The next option will allow you to use these
efaab257 190functions. See L</importing> for more options. You can omit empty import
191argument lists when passing an array reference.
0c378352 192
193The L</subs> option is an array reference of subroutine names that are
194exported by the packages specified with L</importing>. These subroutines
195will be proxied from your declaration package to the variant to be
196generated.
197
198With L</importing> initializing your package and L</subs> declaring what
199subroutines you want to use to build a variant, you can now write a
200L</make_variant> method building your variants.
201
202=head3 Declaring a method to produce variants
203
204Every time a user requests a new variant a method named L</make_variant>
205will be called with the name of the target package and the arguments from
206the user.
207
208It can then use the proxied subroutines declared with L</subs> to
209customize the new package. An L</install> subroutine is exported as well
210allowing you to dynamically install methods into the new package. If these
211options aren't flexible enough, you can use the passed name of the new
212package to do any other kind of customizations.
213
214 sub make_variant {
215 my ($class, $target, @arguments) = @_;
216 # ...
217 # customization goes here
218 # ...
219 }
220
221When the method is finished, the user will receive the name of the new
222package variant you just set up.
223
224=head2 Using variable packages
225
226After your variable package is L<created|/Declaring a variable package>
227your users can get a variant generating subroutine by simply importing
228your package.
229
230 use My::Variant;
2b728d4c 231 my $new_variant_package = Variant(@variant_arguments);
0c378352 232
0a7db8d2 233The package is now fully initialized and used. You can import the
234subroutine under a different name by specifying an C<as> argument.
0c378352 235
236=head2 Dynamic creation of variant packages
237
238For regular uses, the L<normal import|/Using variable packages> provides
239more than enough flexibility. However, if you want to create variations of
cfcf68cb 240dynamically determined packages, you can use the L</build_variant_of>
0c378352 241method.
242
243You can use this to create variations of other packages and pass arguments
244on to them to allow more modular and extensible variations.
245
246=head1 OPTIONS
247
248These are the options that can be passed when importing
249C<Package::Variant>. They describe the environment in which the variants
250are created.
251
252 use Package::Variant
253 importing => { $package => \@import_arguments, ... },
254 subs => [ @proxied_subroutines ];
255
256=head2 importing
257
258This option is a hash reference mapping package names to array references
2b728d4c 259containing import arguments. The packages will be imported with the given
0c378352 260arguments by every variation before the L</make_variant> method is asked
2b728d4c 261to create the package (this is done using L<Import::Into>).
0c378352 262
067e51ad 263If import order is important to you, you can also pass the C<importing>
efaab257 264arguments as a flat array reference:
067e51ad 265
266 use Package::Variant
efaab257 267 importing => [ 'PackageA', 'PackageB' ];
067e51ad 268
efaab257 269 # same as
270 use Package::Variant
271 importing => [ 'PackageA' => [], 'PackageB' => [] ];
272
273 # or
274 use Package::Variant
275 importing => { 'PackageA' => [], 'PackageB' => [] };
276
277The import method will be called even if the list of import arguments is
278empty or not specified,
067e51ad 279
bdc3f3ad 280If you just want to import a single package's default exports, you can
281also pass a string instead:
282
2b728d4c 283 use Package::Variant importing => 'Package';
bdc3f3ad 284
0c378352 285=head2 subs
286
287An array reference of strings listing the names of subroutines that should
288be proxied. These subroutines are expected to be installed into the new
289variant package by the modules imported with L</importing>. Subroutines
328258e0 290with the same name will be available in your declaration package, and will
0c378352 291proxy through to the newly created package when used within
292L</make_variant>.
293
294=head1 VARIABLE PACKAGE METHODS
295
296These are methods on the variable package you declare when you import
297C<Package::Variant>.
298
299=head2 make_variant
300
301 Some::Variant::Package->make_variant( $target, @arguments );
302
303B<You need to provide this method.> This method will be called for every
304new variant of your package. This method should use the subroutines
305declared in L</subs> to customize the new variant package.
306
307This is a class method receiving the C<$target> package and the
308C<@arguments> defining the requested variant.
309
310=head2 import
311
312 use Some::Variant::Package;
313 my $variant_package = Package( @arguments );
314
315This method is provided for you. It will allow a user to C<use> your
316package and receive a subroutine taking C<@arguments> defining the variant
317and returning the name of the newly created variant package.
318
0a7db8d2 319The following options can be specified when importing:
320
321=over
322
323=item * B<as>
324
325 use Some::Variant::Package as => 'Foo';
2b728d4c 326 my $variant_package = Foo(@arguments);
0a7db8d2 327
328Exports the generator subroutine under a different name than the default.
329
330=back
331
0c378352 332=head1 C<Package::Variant> METHODS
333
334These methods are available on C<Package::Variant> itself.
335
cfcf68cb 336=head2 build_variant_of
0c378352 337
338 my $variant_package = Package::Variant
cfcf68cb 339 ->build_variant_of($variable_package, @arguments);
0c378352 340
341This is the dynamic method of creating new variants. It takes the
342C<$variable_package>, which is a pre-declared variable package, and a set
343of C<@arguments> passed to the package to generate a new
344C<$variant_package>, which will be returned.
345
346=head2 import
347
348 use Package::Variant @options;
349
350Sets up the environment in which you declare the variants of your
351packages. See L</OPTIONS> for details on the available options and
352L</EXPORTS> for a list of exported subroutines.
353
354=head1 EXPORTS
355
356Additionally to the proxies for subroutines provided in L</subs>, the
357following exports will be available in your variable package:
358
359=head2 install
360
2b728d4c 361 install($method_name, $code_reference);
0c378352 362
363Installs a method with the given C<$method_name> into the newly created
364variant package. The C<$code_reference> will be used as the body for the
2b728d4c 365method, and if L<Sub::Name> is available the coderef will be named. If you
366want to name it something else, then use:
367
368 install($method_name, $name_to_use, $code_reference);
0c378352 369
370=head1 AUTHOR
371
5b1d922a 372mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
0c378352 373
5b1d922a 374=head1 CONTRIBUTORS
0c378352 375
5b1d922a 376phaylon - Robert Sedlacek (cpan:PHAYLON) <r.sedlacek@shadowcat.co.uk>
0c378352 377
378=head1 COPYRIGHT
379
2b728d4c 380Copyright (c) 2010-2012 the C<Package::Variant> L</AUTHOR> and
57114c43 381L</CONTRIBUTORS> as listed above.
0c378352 382
383=head1 LICENSE
384
385This library is free software and may be distributed under the same
386terms as perl itself.
387
388=cut