1Moose::Cookbook::ExtendUisnegr::CEoxnttMeroniosbsiueot:ne:OdCvoePorekvrbiloeowDk(o:3c:)uEmxetnetnadtiinogn::ExtensionOverview(3)
2
3
4
6 Moose::Cookbook::Extending::ExtensionOverview - Moose extension
7 overview
8
10 version 2.2203
11
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
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
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
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
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
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
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.36.0 Moos2e0:2:3C-o0o2k-b0o6ok::Extending::ExtensionOverview(3)