1Moose::Cookbook::ExtendUisnegr::CEoxnttMeroniosbsiueot:ne:OdCvoePorekvrbiloeowDk(o:3c:)uEmxetnetnadtiinogn::ExtensionOverview(3)
2
3
4

NAME

6       Moose::Cookbook::Extending::ExtensionOverview - Moose extension
7       overview
8

VERSION

10       version 2.2201
11

DESCRIPTION

13       Moose provides several ways in which extensions can hook into Moose and
14       change its behavior. Moose also has a lot of behavior that can be
15       changed. This recipe will provide an overview of each extension method
16       and give you some recommendations on what tools to use.
17
18       If you haven't yet read the recipes on metaclasses, go read those
19       first. You can't write Moose extensions without understanding the
20       metaclasses, and those recipes also demonstrate some basic extension
21       mechanisms, such as metaclass subclasses and traits.
22
23   Playing Nice With Others
24       One of the goals of this overview is to help you build extensions that
25       cooperate well with other extensions. This is especially important if
26       you plan to release your extension to CPAN.
27
28       Moose comes with several modules that exist to help your write
29       cooperative extensions. These are Moose::Exporter and
30       Moose::Util::MetaRole. By using these two modules, you will ensure that
31       your extension works with both the Moose core features and any other
32       CPAN extension using those modules.
33

PARTS OF Moose YOU CAN EXTEND

35       The types of things you might want to do in Moose extensions fall into
36       a few broad categories.
37
38   Metaclass Extensions
39       One way of extending Moose is by extending one or more Moose
40       metaclasses. For example, in
41       Moose::Cookbook::Meta::Table_MetaclassTrait we saw a metaclass role
42       that added a "table" attribute to the metaclass. If you were writing an
43       ORM, this would be a logical extension.
44
45       Many of the Moose extensions on CPAN work by providing an attribute
46       metaclass role. For example, the MooseX::Aliases module provides an
47       attribute metaclass trait that lets you specify aliases to install for
48       methods and attribute accessors.
49
50       A metaclass extension can be packaged as a role/trait or a subclass. If
51       you can, we recommend using traits instead of subclasses, since it's
52       much easier to combine disparate traits than it is to combine a bunch
53       of subclasses.
54
55       When your extensions are implemented as roles, you can apply them with
56       the Moose::Util::MetaRole module.
57
58   Providing Sugar Functions
59       As part of a metaclass extension, you may also want to provide some
60       sugar functions, just like Moose.pm does. Moose provides a helper
61       module called Moose::Exporter that makes this much simpler. We will be
62       use Moose::Exporter in several of the extension recipes.
63
64   Object Class Extensions
65       Another common Moose extension technique is to change the default
66       object class's behavior. As with metaclass extensions, this can be done
67       with a role/trait or with a subclass. For example,
68       MooseX::StrictConstructor extension applies a trait that makes the
69       constructor reject arguments which don't match its attributes.
70
71       Object class extensions often include metaclass extensions as well. In
72       particular, if you want your object extension to work when a class is
73       made immutable, you may need to modify the behavior of some or all of
74       the Moose::Meta::Instance, Moose::Meta::Method::Constructor, and
75       Moose::Meta::Method::Destructor objects.
76
77       The Moose::Util::MetaRole module lets you apply roles to the base
78       object class, as well as the meta classes just mentioned.
79
80   Providing a Role
81       Some extensions come in the form of a role for you to consume. The
82       MooseX::Object::Pluggable extension is a great example of this. In
83       fact, despite the "MooseX" name, it does not actually change anything
84       about Moose's behavior. Instead, it is just a role that an object which
85       wants to be pluggable can consume.
86
87       If you are implementing this sort of extension, you don't need to do
88       anything special. You simply create a role and document that it should
89       be used via the normal "with" sugar:
90
91          package MyApp::User;
92
93          use Moose;
94
95          with 'My::Role';
96
97       Don't use "MooseX" in the name for such packages.
98
99   New Types
100       Another common Moose extension is a new type for the Moose type system.
101       In this case, you simply create a type in your module. When people load
102       your module, the type is created, and they can refer to it by name
103       after that. The MooseX::Types::URI and MooseX::Types::DateTime
104       distributions are two good examples of how this works. These both build
105       on top of the MooseX::Types extension.
106

ROLES VS TRAITS VS SUBCLASSES

108       It is important to understand that roles and traits are the same thing.
109       A trait is simply a role applied to a instance. The only thing that may
110       distinguish the two is that a trait can be packaged in a way that lets
111       Moose resolve a short name to a class name. In other words, with a
112       trait, the caller can refer to it by a short name like "Big", and Moose
113       will resolve it to a class like
114       "MooseX::Embiggen::Meta::Attribute::Role::Big".
115
116       See Moose::Cookbook::Meta::Labeled_AttributeTrait and
117       Moose::Cookbook::Meta::Table_MetaclassTrait for examples of traits in
118       action. In particular, both of these recipes demonstrate the trait
119       resolution mechanism.
120
121       Implementing an extension as a (set of) metaclass or base object
122       role(s) will make your extension more cooperative. It is hard for an
123       end-user to effectively combine together multiple metaclass subclasses,
124       but it is very easy to combine roles.
125

USING YOUR EXTENSION

127       There are a number of ways in which an extension can be applied. In
128       some cases you can provide multiple ways of consuming your extension.
129
130   Extensions as Metaclass Traits
131       If your extension is available as a trait, you can ask end users to
132       simply specify it in a list of traits. Currently, this only works for
133       (class) metaclass and attribute metaclass traits:
134
135         use Moose -traits => [ 'Big', 'Blue' ];
136
137         has 'animal' => (
138             traits => [ 'Big', 'Blue' ],
139             ...
140         );
141
142       If your extension applies to any other metaclass, or the object base
143       class, you cannot use the trait mechanism.
144
145       The benefit of the trait mechanism is that is very easy to see where a
146       trait is applied in the code, and consumers have fine-grained control
147       over what the trait applies to. This is especially true for attribute
148       traits, where you can apply the trait to just one attribute in a class.
149
150   Extensions as Metaclass (and Base Object) Roles
151       Implementing your extensions as metaclass roles makes your extensions
152       easy to apply, and cooperative with other role-based extensions for
153       metaclasses.
154
155       Just as with a subclass, you will probably want to package your
156       extensions for consumption with a single module that uses
157       Moose::Exporter. However, in this case, you will use
158       Moose::Util::MetaRole to apply all of your roles. The advantage of
159       using this module is that it preserves any subclassing or roles already
160       applied to the user's metaclasses. This means that your extension is
161       cooperative by default, and consumers of your extension can easily use
162       it with other role-based extensions. Most uses of Moose::Util::MetaRole
163       can be handled by Moose::Exporter directly; see the Moose::Exporter
164       docs.
165
166         package MooseX::Embiggen;
167
168         use Moose::Exporter;
169
170         use MooseX::Embiggen::Role::Meta::Class;
171         use MooseX::Embiggen::Role::Meta::Attribute;
172         use MooseX::Embiggen::Role::Meta::Method::Constructor;
173         use MooseX::Embiggen::Role::Object;
174
175         Moose::Exporter->setup_import_methods(
176             class_metaroles => {
177                 class     => ['MooseX::Embiggen::Role::Meta::Class'],
178                 attribute => ['MooseX::Embiggen::Role::Meta::Attribute'],
179                 constructor =>
180                     ['MooseX::Embiggen::Role::Meta::Method::Constructor'],
181             },
182             base_class_roles => ['MooseX::Embiggen::Role::Object'],
183         );
184
185       As you can see from this example, you can use Moose::Util::MetaRole to
186       apply roles to any metaclass, as well as the base object class. If some
187       other extension has already applied its own roles, they will be
188       preserved when your extension applies its roles, and vice versa.
189
190   Providing Sugar
191       With Moose::Exporter, you can also export your own sugar functions:
192
193         package MooseX::Embiggen;
194
195         use Moose::Exporter;
196
197         Moose::Exporter->setup_import_methods(
198             with_meta       => ['embiggen'],
199             class_metaroles => {
200                 class => ['MooseX::Embiggen::Role::Meta::Class'],
201             },
202         );
203
204         sub embiggen {
205             my $meta = shift;
206             $meta->embiggen(@_);
207         }
208
209       And then the consumer of your extension can use your "embiggen" sub:
210
211         package Consumer;
212
213         use Moose;
214         use MooseX::Embiggen;
215
216         extends 'Thing';
217
218         embiggen ...;
219
220       This can be combined with metaclass and base class roles quite easily.
221
222   More advanced extensions
223       Providing your extension simply as a set of traits that gets applied to
224       the appropriate metaobjects is easy, but sometimes not sufficient. For
225       instance, sometimes you need to supply not just a base object role, but
226       an actual base object class (due to needing to interact with existing
227       systems that only provide a base class). To write extensions like this,
228       you will need to provide a custom "init_meta" method in your exporter.
229       For instance:
230
231         package MooseX::Embiggen;
232
233         use Moose::Exporter;
234
235         my ($import, $unimport, $init_meta) = Moose::Exporter->build_import_methods(
236             install         => ['import', 'unimport'],
237             with_meta       => ['embiggen'],
238             class_metaroles => {
239                 class => ['MooseX::Embiggen::Role::Meta::Class'],
240             },
241         );
242
243         sub embiggen {
244             my $meta = shift;
245             $meta->embiggen(@_);
246         }
247
248         sub init_meta {
249             my $package = shift;
250             my %options = @_;
251             if (my $meta = Class::MOP::class_of($options{for_class})) {
252                 if ($meta->isa('Class::MOP::Class')) {
253                     my @supers = $meta->superclasses;
254                     $meta->superclasses('MooseX::Embiggen::Base::Class')
255                         if @supers == 1 && $supers[0] eq 'Moose::Object';
256                 }
257             }
258             $package->$init_meta(%options);
259         }
260
261       In the previous examples, "init_meta" was generated for you, but here
262       you must override it in order to add additional functionality. Some
263       differences to note:
264
265       "build_import_methods" instead of "setup_import_methods"
266           "build_import_methods" simply returns the "import", "unimport", and
267           "init_meta" methods, rather than installing them under the
268           appropriate names.  This way, you can write your own methods which
269           wrap the functionality provided by Moose::Exporter.  The
270           "build_import_methods" sub also takes an additional "install"
271           parameter, which tells it to just go ahead and install these
272           methods (since we don't need to modify them).
273
274       "sub init_meta"
275           Next, we must write our "init_meta" wrapper. The important things
276           to remember are that it is called as a method, and that %options
277           needs to be passed through to the existing implementation. We call
278           the base implementation by using the $init_meta subroutine
279           reference that was returned by "build_import_methods" earlier.
280
281       Additional implementation
282           This extension sets a different default base object class. To do
283           so, it first checks to see if it's being applied to a class, and
284           then checks to see if Moose::Object is that class's only
285           superclass, and if so, replaces that with the superclass that this
286           extension requires.
287
288           Note that two extensions that do this same thing will not work
289           together properly (the second extension to be loaded won't see
290           Moose::Object as the base object, since it has already been
291           overridden). This is why using a base object role is recommended
292           for the general case.
293
294           This "init_meta" also works defensively, by only applying its
295           functionality if a metaclass already exists. This makes sure it
296           doesn't break with legacy extensions which override the metaclass
297           directly (and so must be the first extension to initialize the
298           metaclass). This is likely not necessary, since almost no
299           extensions work this way anymore, but just provides an additional
300           level of protection. The common case of "use Moose; use
301           MooseX::Embiggen;" is not affected regardless.
302
303       This is just one example of what can be done with a custom "init_meta"
304       method.  It can also be used for preventing an extension from being
305       applied to a role, doing other kinds of validation on the class being
306       applied to, or pretty much anything that would otherwise be done in an
307       "import" method.
308

LEGACY EXTENSION MECHANISMS

310       Before the existence of Moose::Exporter and Moose::Util::MetaRole,
311       there were a number of other ways to extend Moose. In general, these
312       methods were less cooperative, and only worked well with a single
313       extension.
314
315       These methods include metaclass.pm, Moose::Policy (which uses
316       metaclass.pm under the hood), and various hacks to do what
317       Moose::Exporter does. Please do not use these for your own extensions.
318
319       Note that if you write a cooperative extension, it should cooperate
320       with older extensions, though older extensions generally do not
321       cooperate with each other.
322

CONCLUSION

324       If you can write your extension as one or more metaclass and base
325       object roles, please consider doing so. Make sure to read the docs for
326       Moose::Exporter and Moose::Util::MetaRole as well.
327

AUTHORS

329       •   Stevan Little <stevan@cpan.org>
330
331       •   Dave Rolsky <autarch@urth.org>
332
333       •   Jesse Luehrs <doy@cpan.org>
334
335       •   Shawn M Moore <sartak@cpan.org>
336
337       •   יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
338
339       •   Karen Etheridge <ether@cpan.org>
340
341       •   Florian Ragwitz <rafl@debian.org>
342
343       •   Hans Dieter Pearcey <hdp@cpan.org>
344
345       •   Chris Prather <chris@prather.org>
346
347       •   Matt S Trout <mstrout@cpan.org>
348
350       This software is copyright (c) 2006 by Infinity Interactive, Inc.
351
352       This is free software; you can redistribute it and/or modify it under
353       the same terms as the Perl 5 programming language system itself.
354
355
356
357perl v5.34.0                  Moos2e0:2:2C-o0o1k-b2o1ok::Extending::ExtensionOverview(3)
Impressum