1NAME
2 Package::Variant - Parameterizable packages
3
4SYNOPSIS
5 Creation of anonymous variants:
6
7 # declaring a variable Moo role
8 package My::VariableRole::ObjectAttr;
9 use strictures 2;
10 use Package::Variant
11 # what modules to 'use'
12 importing => ['Moo::Role'],
13 # proxied subroutines
14 subs => [ qw(has around before after with) ];
15
16 sub make_variant {
17 my ($class, $target_package, %arguments) = @_;
18 # access arguments
19 my $name = $arguments{name};
20 # use proxied 'has' to add an attribute
21 has $name => (is => 'lazy');
22 # install a builder method
23 install "_build_${name}" => sub {
24 return $arguments{class}->new;
25 };
26 }
27
28 # using the role
29 package My::Class::WithObjectAttr;
30 use strictures 2;
31 use Moo;
32 use My::VariableRole::ObjectAttr;
33
34 with ObjectAttr(name => 'some_obj', class => 'Some::Class');
35
36 # using our class
37 my $obj = My::Class::WithObjectAttr->new;
38 $obj->some_obj; # returns a Some::Class instance
39
40 And the same thing, only with named variants:
41
42 # declaring a variable Moo role that can be named
43 package My::VariableRole::ObjectAttrNamed;
44 use strictures 2;
45 use Package::Variant importing => ['Moo::Role'],
46 subs => [ qw(has around before after with) ];
47 use Module::Runtime 'module_notional_filename'; # only if you need protection
48
49 # this method is run at variant creation time to determine its custom
50 # package name. it can use the arguments or do something entirely else.
51 sub make_variant_package_name {
52 my ($class, $package, %arguments) = @_;
53 $package = "Private::$package"; # you can munge the input here if you like
54 # only if you *need* protection
55 die "Won't clobber $package" if $INC{module_notional_filename $package};
56 return $package;
57 }
58
59 # same as in the example above, except for the argument list. in this example
60 # $package is the user input, and
61 # $target_package is the actual package in which the variant gets installed
62 sub make_variant {
63 my ($class, $target_package, $package, %arguments) = @_;
64 my $name = $arguments{name};
65 has $name => (is => 'lazy');
66 install "_build_${name}" => sub {return $arguments{class}->new};
67 }
68
69 # using the role
70 package My::Class::WithObjectAttr;
71 use strictures 2;
72 use Moo;
73 use My::VariableRole::ObjectAttrNamed;
74
75 # create the role under a specific name
76 ObjectAttrNamed "My::Role" => (name => 'some_obj', class => 'Some::Class');
77 # and use it
78 with "Private::My::Role";
79
80 # using our class
81 my $obj = My::Class::WithObjectAttr->new;
82 $obj->some_obj; # returns a Some::Class instance
83
84DESCRIPTION
85 This module allows you to build a variable package that contains a
86 package template and can use it to build variant packages at runtime.
87
88 Your variable package will export a subroutine which will build a
89 variant package, combining its arguments with the template, and return
90 the name of the new variant package.
91
92 The implementation does not care about what kind of packages it builds,
93 be they simple function exporters, classes, singletons or something
94 entirely different.
95
96 Declaring a variable package
97 There are two important parts to creating a variable package. You first
98 have to give "Package::Variant" some basic information about what kind
99 of variant packages you want to provide, and how. The second part is
100 implementing a method which builds the components of the variant
101 packages that use the user's arguments or cannot be provided with a
102 static import.
103
104 Setting up the environment for building variants
105 When you "use Package::Variant", you pass along some arguments that
106 describe how you intend to build your variants.
107
108 use Package::Variant
109 importing => { $package => \@import_arguments, ... },
110 subs => [ @proxied_subroutine_names ];
111
112 The "importing" option needs to be a hash or array reference with
113 package names to be "use"d as keys, and array references containing the
114 import arguments as values. These packages will be imported into every
115 new variant package, to provide static functionality of the variant
116 packages and to set up every declarative subroutine you require to build
117 variants package components. The next option will allow you to use these
118 functions. See "importing" for more options. You can omit empty import
119 argument lists when passing an array reference.
120
121 The "subs" option is an array reference of subroutine names that are
122 exported by the packages specified with "importing". These subroutines
123 will be proxied from your variable package to the variant to be
124 generated.
125
126 With "importing" initializing your package and "subs" declaring what
127 subroutines you want to use to build a variant, you can now write a
128 "make_variant" method building your variants.
129
130 Declaring a method to produce variants
131 Every time a user requests a new variant, a method named "make_variant"
132 will be called with the name of the target package and the arguments
133 from the user.
134
135 It can then use the proxied subroutines declared with "subs" to
136 customize the variant package. An "install" subroutine is exported as
137 well allowing you to dynamically install methods into the variant
138 package. If these options aren't flexible enough, you can use the passed
139 name of the variant package to do any other kind of customizations.
140
141 sub make_variant {
142 my ($class, $target, @arguments) = @_;
143 # ...
144 # customization goes here
145 # ...
146 }
147
148 When the method is finished, the user will receive the name of the new
149 variant package you just set up.
150
151 Using variable packages
152 After your variable package is created your users can get a variant
153 generator subroutine by simply importing your package.
154
155 use My::Variant;
156 my $new_variant_package = Variant(@variant_arguments);
157 # the variant package is now fully initialized and used
158
159 You can import the subroutine under a different name by specifying an
160 "as" argument.
161
162 Dynamic creation of variant packages
163 For regular uses, the normal import provides more than enough
164 flexibility. However, if you want to create variants of dynamically
165 determined packages, you can use the "build_variant_of" method.
166
167 You can use this to create variants of other packages and pass arguments
168 on to them to allow more modular and extensible variants.
169
170OPTIONS
171 These are the options that can be passed when importing
172 "Package::Variant". They describe the environment in which the variants
173 are created.
174
175 use Package::Variant
176 importing => { $package => \@import_arguments, ... },
177 subs => [ @proxied_subroutines ];
178
179 importing
180 This option is a hash reference mapping package names to array
181 references containing import arguments. The packages will be imported
182 with the given arguments by every variant before the "make_variant"
183 method is asked to create the package (this is done using Import::Into).
184
185 If import order is important to you, you can also pass the "importing"
186 arguments as a flat array reference:
187
188 use Package::Variant
189 importing => [ 'PackageA', 'PackageB' ];
190
191 # same as
192 use Package::Variant
193 importing => [ 'PackageA' => [], 'PackageB' => [] ];
194
195 # or
196 use Package::Variant
197 importing => { 'PackageA' => [], 'PackageB' => [] };
198
199 The import method will be called even if the list of import arguments is
200 empty or not specified,
201
202 If you just want to import a single package's default exports, you can
203 also pass a string instead:
204
205 use Package::Variant importing => 'Package';
206
207 subs
208 An array reference of strings listing the names of subroutines that
209 should be proxied. These subroutines are expected to be installed into
210 the new variant package by the modules imported with "importing".
211 Subroutines with the same name will be available in your variable
212 package, and will proxy through to the newly created package when used
213 within "make_variant".
214
215VARIABLE PACKAGE METHODS
216 These are methods on the variable package you declare when you import
217 "Package::Variant".
218
219 make_variant
220 Some::Variant::Package->make_variant( $target, @arguments );
221
222 You need to provide this method. This method will be called for every
223 new variant of your package. This method should use the subroutines
224 declared in "subs" to customize the new variant package.
225
226 This is a class method receiving the $target package and the @arguments
227 defining the requested variant.
228
229 make_variant_package_name
230 Some::Variant::Package->make_variant_package_name( @arguments );
231
232 You may optionally provide this method. If present, this method will be
233 used to determine the package name for a particular variant being
234 constructed.
235
236 If you do not implement it, a unique package name something like
237
238 Some::Variant::Package::_Variant_A003
239
240 will be created for you.
241
242 import
243 use Some::Variant::Package;
244 my $variant_package = Package( @arguments );
245
246 This method is provided for you. It will allow a user to "use" your
247 package and receive a subroutine taking @arguments defining the variant
248 and returning the name of the newly created variant package.
249
250 The following options can be specified when importing:
251
252 * as
253
254 use Some::Variant::Package as => 'Foo';
255 my $variant_package = Foo(@arguments);
256
257 Exports the generator subroutine under a different name than the
258 default.
259
260 build_variant
261 use Some::Variant::Package ();
262 my $variant_package = Some::Variant::Package->build_variant( @arguments );
263
264 This method is provided for you. It will generate a variant package and
265 return its name, just like the generator sub provided by "import". This
266 allows you to avoid importing anything into the consuming package.
267
268"Package::Variant" METHODS
269 These methods are available on "Package::Variant" itself.
270
271 build_variant_of
272 my $variant_package = Package::Variant
273 ->build_variant_of($variable_package, @arguments);
274
275 This is the dynamic method of creating new variants. It takes the
276 $variable_package, which is a pre-declared variable package, and a set
277 of @arguments passed to the package to generate a new $variant_package,
278 which will be returned.
279
280 import
281 use Package::Variant @options;
282
283 Sets up the environment in which you declare the variants of your
284 packages. See "OPTIONS" for details on the available options and
285 "EXPORTS" for a list of exported subroutines.
286
287EXPORTS
288 Additionally to the proxies for subroutines provided in "subs", the
289 following exports will be available in your variable package:
290
291 install
292 install($method_name, $code_reference);
293
294 Installs a method with the given $method_name into the newly created
295 variant package. The $code_reference will be used as the body for the
296 method, and if Sub::Name is available the coderef will be named. If you
297 want to name it something else, then use:
298
299 install($method_name, $name_to_use, $code_reference);
300
301AUTHOR
302 mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
303
304CONTRIBUTORS
305 phaylon - Robert Sedlacek (cpan:PHAYLON) <r.sedlacek@shadowcat.co.uk>
306
307 haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
308
309COPYRIGHT
310 Copyright (c) 2010-2012 the "Package::Variant" "AUTHOR" and
311 "CONTRIBUTORS" as listed above.
312
313LICENSE
314 This library is free software and may be distributed under the same
315 terms as perl itself.
316
317