• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

lib/Package/H25-Jul-2015-477117

maint/H25-Jul-2015-75

t/H25-Jul-2015-277223

ChangesH A D25-Jul-20151.2 KiB4532

MANIFESTH A D25-Jul-2015432 1413

META.jsonH A D25-Jul-20151.4 KiB5756

META.ymlH A D25-Jul-2015741 3029

Makefile.PLH A D25-Jul-20152.5 KiB7864

READMEH A D25-Jul-201511.6 KiB317242

README

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