1Package::Variant(3)   User Contributed Perl Documentation  Package::Variant(3)
2
3
4

NAME

6       Package::Variant - Parameterizable packages
7

SYNOPSIS

9       Creation of anonymous variants:
10
11         # declaring a variable Moo role
12         package My::VariableRole::ObjectAttr;
13         use strictures 2;
14         use Package::Variant
15           # what modules to 'use'
16           importing => ['Moo::Role'],
17           # proxied subroutines
18           subs => [ qw(has around before after with) ];
19
20         sub make_variant {
21           my ($class, $target_package, %arguments) = @_;
22           # access arguments
23           my $name = $arguments{name};
24           # use proxied 'has' to add an attribute
25           has $name => (is => 'lazy');
26           # install a builder method
27           install "_build_${name}" => sub {
28             return $arguments{class}->new;
29           };
30         }
31
32         # using the role
33         package My::Class::WithObjectAttr;
34         use strictures 2;
35         use Moo;
36         use My::VariableRole::ObjectAttr;
37
38         with ObjectAttr(name => 'some_obj', class => 'Some::Class');
39
40         # using our class
41         my $obj = My::Class::WithObjectAttr->new;
42         $obj->some_obj; # returns a Some::Class instance
43
44       And the same thing, only with named variants:
45
46         # declaring a variable Moo role that can be named
47         package My::VariableRole::ObjectAttrNamed;
48         use strictures 2;
49         use Package::Variant importing => ['Moo::Role'],
50           subs => [ qw(has around before after with) ];
51         use Module::Runtime 'module_notional_filename'; # only if you need protection
52
53         # this method is run at variant creation time to determine its custom
54         # package name. it can use the arguments or do something entirely else.
55         sub make_variant_package_name {
56           my ($class, $package, %arguments) = @_;
57           $package = "Private::$package"; # you can munge the input here if you like
58           # only if you *need* protection
59           die "Won't clobber $package" if $INC{module_notional_filename $package};
60           return $package;
61         }
62
63         # same as in the example above, except for the argument list. in this example
64         # $package is the user input, and
65         # $target_package is the actual package in which the variant gets installed
66         sub make_variant {
67           my ($class, $target_package, $package, %arguments) = @_;
68           my $name = $arguments{name};
69           has $name => (is => 'lazy');
70           install "_build_${name}" => sub {return $arguments{class}->new};
71         }
72
73         # using the role
74         package My::Class::WithObjectAttr;
75         use strictures 2;
76         use Moo;
77         use My::VariableRole::ObjectAttrNamed;
78
79         # create the role under a specific name
80         ObjectAttrNamed "My::Role" => (name => 'some_obj', class => 'Some::Class');
81         # and use it
82         with "Private::My::Role";
83
84         # using our class
85         my $obj = My::Class::WithObjectAttr->new;
86         $obj->some_obj; # returns a Some::Class instance
87

DESCRIPTION

89       This module allows you to build a variable package that contains a
90       package template and can use it to build variant packages at runtime.
91
92       Your variable package will export a subroutine which will build a
93       variant package, combining its arguments with the template, and return
94       the name of the new variant package.
95
96       The implementation does not care about what kind of packages it builds,
97       be they simple function exporters, classes, singletons or something
98       entirely different.
99
100   Declaring a variable package
101       There are two important parts to creating a variable package. You first
102       have to give "Package::Variant" some basic information about what kind
103       of variant packages you want to provide, and how. The second part is
104       implementing a method which builds the components of the variant
105       packages that use the user's arguments or cannot be provided with a
106       static import.
107
108       Setting up the environment for building variants
109
110       When you "use Package::Variant", you pass along some arguments that
111       describe how you intend to build your variants.
112
113         use Package::Variant
114           importing => { $package => \@import_arguments, ... },
115           subs      => [ @proxied_subroutine_names ];
116
117       The "importing" option needs to be a hash or array reference with
118       package names to be "use"d as keys, and array references containing the
119       import arguments as values. These packages will be imported into every
120       new variant package, to provide static functionality of the variant
121       packages and to set up every declarative subroutine you require to
122       build variants package components. The next option will allow you to
123       use these functions. See "importing" for more options. You can omit
124       empty import argument lists when passing an array reference.
125
126       The "subs" option is an array reference of subroutine names that are
127       exported by the packages specified with "importing". These subroutines
128       will be proxied from your variable package to the variant to be
129       generated.
130
131       With "importing" initializing your package and "subs" declaring what
132       subroutines you want to use to build a variant, you can now write a
133       "make_variant" method building your variants.
134
135       Declaring a method to produce variants
136
137       Every time a user requests a new variant, a method named "make_variant"
138       will be called with the name of the target package and the arguments
139       from the user.
140
141       It can then use the proxied subroutines declared with "subs" to
142       customize the variant package. An "install" subroutine is exported as
143       well allowing you to dynamically install methods into the variant
144       package. If these options aren't flexible enough, you can use the
145       passed name of the variant package to do any other kind of
146       customizations.
147
148         sub make_variant {
149           my ($class, $target, @arguments) = @_;
150           # ...
151           # customization goes here
152           # ...
153         }
154
155       When the method is finished, the user will receive the name of the new
156       variant package you just set up.
157
158   Using variable packages
159       After your variable package is created your users can get a variant
160       generator subroutine by simply importing your package.
161
162         use My::Variant;
163         my $new_variant_package = Variant(@variant_arguments);
164         # the variant package is now fully initialized and used
165
166       You can import the subroutine under a different name by specifying an
167       "as" argument.
168
169   Dynamic creation of variant packages
170       For regular uses, the normal import provides more than enough
171       flexibility. However, if you want to create variants of dynamically
172       determined packages, you can use the "build_variant_of" method.
173
174       You can use this to create variants of other packages and pass
175       arguments on to them to allow more modular and extensible variants.
176

OPTIONS

178       These are the options that can be passed when importing
179       "Package::Variant". They describe the environment in which the variants
180       are created.
181
182         use Package::Variant
183           importing => { $package => \@import_arguments, ... },
184           subs      => [ @proxied_subroutines ];
185
186   importing
187       This option is a hash reference mapping package names to array
188       references containing import arguments. The packages will be imported
189       with the given arguments by every variant before the "make_variant"
190       method is asked to create the package (this is done using
191       Import::Into).
192
193       If import order is important to you, you can also pass the "importing"
194       arguments as a flat array reference:
195
196         use Package::Variant
197           importing => [ 'PackageA', 'PackageB' ];
198
199         # same as
200         use Package::Variant
201           importing => [ 'PackageA' => [], 'PackageB' => [] ];
202
203         # or
204         use Package::Variant
205           importing => { 'PackageA' => [], 'PackageB' => [] };
206
207       The import method will be called even if the list of import arguments
208       is empty or not specified,
209
210       If you just want to import a single package's default exports, you can
211       also pass a string instead:
212
213         use Package::Variant importing => 'Package';
214
215   subs
216       An array reference of strings listing the names of subroutines that
217       should be proxied. These subroutines are expected to be installed into
218       the new variant package by the modules imported with "importing".
219       Subroutines with the same name will be available in your variable
220       package, and will proxy through to the newly created package when used
221       within "make_variant".
222

VARIABLE PACKAGE METHODS

224       These are methods on the variable package you declare when you import
225       "Package::Variant".
226
227   make_variant
228         Some::Variant::Package->make_variant( $target, @arguments );
229
230       You need to provide this method. This method will be called for every
231       new variant of your package. This method should use the subroutines
232       declared in "subs" to customize the new variant package.
233
234       This is a class method receiving the $target package and the @arguments
235       defining the requested variant.
236
237   make_variant_package_name
238         Some::Variant::Package->make_variant_package_name( @arguments );
239
240       You may optionally provide this method. If present, this method will be
241       used to determine the package name for a particular variant being
242       constructed.
243
244       If you do not implement it, a unique package name something like
245
246         Some::Variant::Package::_Variant_A003
247
248       will be created for you.
249
250   import
251         use Some::Variant::Package;
252         my $variant_package = Package( @arguments );
253
254       This method is provided for you. It will allow a user to "use" your
255       package and receive a subroutine taking @arguments defining the variant
256       and returning the name of the newly created variant package.
257
258       The following options can be specified when importing:
259
260as
261
262             use Some::Variant::Package as => 'Foo';
263             my $variant_package = Foo(@arguments);
264
265           Exports the generator subroutine under a different name than the
266           default.
267
268   build_variant
269         use Some::Variant::Package ();
270         my $variant_package = Some::Variant::Package->build_variant( @arguments );
271
272       This method is provided for you.  It will generate a variant package
273       and return its name, just like the generator sub provided by "import".
274       This allows you to avoid importing anything into the consuming package.
275

"Package::Variant" METHODS

277       These methods are available on "Package::Variant" itself.
278
279   build_variant_of
280         my $variant_package = Package::Variant
281           ->build_variant_of($variable_package, @arguments);
282
283       This is the dynamic method of creating new variants. It takes the
284       $variable_package, which is a pre-declared variable package, and a set
285       of @arguments passed to the package to generate a new $variant_package,
286       which will be returned.
287
288   import
289         use Package::Variant @options;
290
291       Sets up the environment in which you declare the variants of your
292       packages. See "OPTIONS" for details on the available options and
293       "EXPORTS" for a list of exported subroutines.
294

EXPORTS

296       Additionally to the proxies for subroutines provided in "subs", the
297       following exports will be available in your variable package:
298
299   install
300         install($method_name, $code_reference);
301
302       Installs a method with the given $method_name into the newly created
303       variant package. The $code_reference will be used as the body for the
304       method, and if Sub::Name is available the coderef will be named. If you
305       want to name it something else, then use:
306
307         install($method_name, $name_to_use, $code_reference);
308

AUTHOR

310       mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
311

CONTRIBUTORS

313       phaylon - Robert Sedlacek (cpan:PHAYLON) <r.sedlacek@shadowcat.co.uk>
314
315       haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
316
318       Copyright (c) 2010-2012 the "Package::Variant" "AUTHOR" and
319       "CONTRIBUTORS" as listed above.
320

LICENSE

322       This library is free software and may be distributed under the same
323       terms as perl itself.
324
325
326
327perl v5.34.0                      2022-01-21               Package::Variant(3)
Impressum