24dc9da20a4ee1b0fb4467fd60ea8515cec7f167
[gitmo/Moose.git] / lib / Moose / Cookbook / Extending / Recipe1.pod
1 package Moose::Cookbook::Extending::Recipe1;
2
3 # ABSTRACT: Moose extension overview
4
5 __END__
6
7
8 =pod
9
10 =head1 DESCRIPTION
11
12 Moose provides several ways in which extensions can hook into Moose
13 and change its behavior. Moose also has a lot of behavior that can be
14 changed. This recipe will provide an overview of each extension method
15 and give you some recommendations on what tools to use.
16
17 If you haven't yet read the recipes on metaclasses, go read those
18 first. You can't write Moose extensions without understanding the
19 metaclasses, and those recipes also demonstrate some basic extension
20 mechanisms, such as metaclass subclasses and traits.
21
22 =head2 Playing Nice With Others
23
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 L<Moose::Exporter> and
30 L<Moose::Util::MetaRole>. By using these two modules, you will ensure
31 that your extension works with both the Moose core features and any
32 other CPAN extension using those modules.
33
34 =head1 PARTS OF Moose YOU CAN EXTEND
35
36 The types of things you might want to do in Moose extensions fall into
37 a few broad categories.
38
39 =head2 Metaclass Extensions
40
41 One way of extending Moose is by extending one or more Moose
42 metaclasses. For example, in L<Moose::Cookbook::Meta::Recipe4> we saw
43 a metaclass subclass that added a C<table> attribute to the
44 metaclass. If you were writing an ORM, this would be a logical
45 extension.
46
47 Many of the Moose extensions on CPAN work by providing an attribute
48 metaclass extension. For example, the L<MooseX::AttributeHelpers>
49 distribution provides a new attribute metaclass that lets you delegate
50 behavior to a non-object attribute (a hashref or simple number).
51 (MooseX::AttributeHelpers has been deprecated in favour of
52 L<Moose::Meta::Attribute::Native>, but can still serve as an example).
53
54 A metaclass extension can be packaged as a subclass or a
55 role/trait. If you can, we recommend using traits instead of
56 subclasses, since it's much easier to combine disparate traits than it
57 is to combine a bunch of subclasses.
58
59 When your extensions are implemented as roles, you can apply them with
60 the L<Moose::Util::MetaRole> module.
61
62 =head2 Providing Sugar Functions
63
64 As part of a metaclass extension, you may also want to provide some
65 sugar functions, just like L<Moose.pm|Moose> does. Moose provides a
66 helper module called L<Moose::Exporter> that makes this much
67 simpler. We will be use L<Moose::Exporter> in several of the extension
68 recipes.
69
70 =head2 Object Class Extensions
71
72 Another common Moose extension technique is to change the default
73 object class's behavior. For example, the L<MooseX::Singleton>
74 extension changes the behavior of your objects so that they are
75 singletons. The L<MooseX::StrictConstructor> extension makes the
76 constructor reject arguments which don't match its attributes.
77
78 Object class extensions often include metaclass extensions as well. In
79 particular, if you want your object extension to work when a class is
80 made immutable, you may need to extend some or all of the
81 L<Moose::Meta::Instance>, L<Moose::Meta::Method::Constructor>, and
82 L<Moose::Meta::Method::Destructor> objects.
83
84 The L<Moose::Util::MetaRole> module lets you apply roles to the base
85 object class, as well as the meta classes just mentioned.
86
87 =head2 Providing a Role
88
89 Some extensions come in the form of a role for you to consume. The
90 L<MooseX::Object::Pluggable> extension is a great example of this. In
91 fact, despite the C<MooseX> name, it does not actually change anything
92 about Moose's behavior. Instead, it is just a role that an object
93 which wants to be pluggable can consume.
94
95 If you are implementing this sort of extension, you don't need to do
96 anything special. You simply create a role and document that it should
97 be used via the normal C<with> sugar:
98
99    package MyApp::User;
100
101    use Moose;
102
103    with 'MooseX::My::Role';
104
105 =head2 New Types
106
107 Another common Moose extension is a new type for the Moose type
108 system. In this case, you simply create a type in your module. When
109 people load your module, the type is created, and they can refer to it
110 by name after that. The L<MooseX::Types::URI> and
111 L<MooseX::Types::DateTime> distributions are two good examples of how
112 this works. These both build on top of the L<MooseX::Types> extension.
113
114 =head1 ROLES VS TRAITS VS SUBCLASSES
115
116 It is important to understand that B<roles and traits are the same thing>. A
117 trait is simply a role applied to a instance. The only thing that may
118 distinguish the two is that a trait can be packaged in a way that lets Moose
119 resolve a short name to a class name. In other words, with a trait, the caller
120 can refer to it by a short name like "Big", and Moose will resolve it to a
121 class like C<MooseX::Embiggen::Meta::Attribute::Role::Big>.
122
123 See L<Moose::Cookbook::Meta::Recipe3> and
124 L<Moose::Cookbook::Meta::Recipe5> for examples of traits in action. In
125 particular, both of these recipes demonstrate the trait resolution
126 mechanism.
127
128 Implementing an extension as a (set of) metaclass or base object
129 role(s) will make your extension more cooperative. It is hard for an
130 end-user to effectively combine together multiple metaclass
131 subclasses, but it is very easy to combine roles.
132
133 =head1 USING YOUR EXTENSION
134
135 There are a number of ways in which an extension can be applied. In
136 some cases you can provide multiple ways of consuming your extension.
137
138 =head2 Extensions as Metaclass Traits
139
140 If your extension is available as a trait, you can ask end users to
141 simply specify it in a list of traits. Currently, this only works for
142 (class) metaclass and attribute metaclass traits:
143
144   use Moose -traits => [ 'Big', 'Blue' ];
145
146   has 'animal' => (
147       traits => [ 'Big', 'Blue' ],
148       ...
149   );
150
151 If your extension applies to any other metaclass, or the object base
152 class, you cannot use the trait mechanism.
153
154 The benefit of the trait mechanism is that is very easy to see where a
155 trait is applied in the code, and consumers have fine-grained control
156 over what the trait applies to. This is especially true for attribute
157 traits, where you can apply the trait to just one attribute in a
158 class.
159
160 =head2 Extensions as Metaclass (and Base Object) Subclasses
161
162 Moose does not provide any simple APIs for consumers to use a subclass
163 extension, except for attribute metaclasses. The attribute declaration
164 options include a C<metaclass> option a consumer of your extension can
165 use to specify your subclass.
166
167 This is one reason why implementing an extension as a subclass can be
168 a poor choice. However, you can force the use of certain subclasses at
169 import time by calling C<< Moose->init_meta >> for the caller, and
170 providing an alternate metaclass or base object class.
171
172 If you do want to do this, you should look at using L<Moose::Exporter>
173 to re-export the L<Moose.pm|Moose> sugar function. With
174 L<Moose::Exporter>, if your exporting class has an C<init_meta>
175 method, L<Moose::Exporter> makes sure that this C<init_meta> method
176 gets called when your class is imported.
177
178 Then in your C<init_meta> you can arrange for the caller to use your
179 subclasses:
180
181   package MooseX::Embiggen;
182
183   use Moose ();
184   use Moose::Exporter;
185
186   use MooseX::Embiggen::Meta::Class;
187   use MooseX::Embiggen::Object;
188
189   Moose::Exporter->setup_import_methods( also => 'Moose' );
190
191   sub init_meta {
192       shift;    # just your package name
193       my %options = @_;
194
195       return Moose->init_meta(
196           for_class  => $options{for_class},
197           metaclass  => 'MooseX::Embiggen::Meta::Class',
198           base_class => 'MooseX::Embiggen::Object',
199       );
200   }
201
202 NOTE: Make sure that your C<init_meta> returns the metaclass object, just as
203 C<< Moose->init_meta >> does.
204
205 =head2 Extensions as Metaclass (and Base Object) Roles
206
207 Implementing your extensions as metaclass roles makes your extensions
208 easy to apply, and cooperative with other role-based extensions for
209 metaclasses.
210
211 Just as with a subclass, you will probably want to package your
212 extensions for consumption with a single module that uses
213 L<Moose::Exporter>. However, in this case, you will use
214 L<Moose::Util::MetaRole> to apply all of your roles. The advantage of
215 using this module is that I<it preserves any subclassing or roles
216 already applied to the user's metaclasses>. This means that your
217 extension is cooperative I<by default>, and consumers of your
218 extension can easily use it with other role-based extensions. Most
219 uses of L<Moose::Util::MetaRole> can be handled by L<Moose::Exporter>
220 directly; see the L<Moose::Exporter> docs.
221
222   package MooseX::Embiggen;
223
224   use Moose ();
225   use Moose::Exporter;
226
227   use MooseX::Embiggen::Role::Meta::Class;
228   use MooseX::Embiggen::Role::Meta::Attribute;
229   use MooseX::Embiggen::Role::Meta::Method::Constructor;
230   use MooseX::Embiggen::Role::Object;
231
232   my ( $import, $unimport, $init_meta ) = Moose::Exporter->build_import_methods(
233       also => ['Moose'] metaclass_roles =>
234           ['MooseX::Embiggen::Role::Meta::Class'],
235       attribute_metaclass_roles => ['MooseX::Embiggen::Role::Meta::Attribute'],
236       constructor_class_roles =>
237           ['MooseX::Embiggen::Role::Meta::Method::Constructor'],
238       base_class_roles => ['MooseX::Embiggen::Role::Object'],
239       install          => [qw(import unimport)],
240   );
241
242   sub init_meta {
243       my $package = shift;
244       my %options = @_;
245       Moose->init_meta(%options);
246       return $package->$init_meta(%options);
247   }
248
249 As you can see from this example, you can use L<Moose::Util::MetaRole>
250 to apply roles to any metaclass, as well as the base object class. If
251 some other extension has already applied its own roles, they will be
252 preserved when your extension applies its roles, and vice versa.
253
254 =head2 Providing Sugar
255
256 With L<Moose::Exporter>, you can also export your own sugar functions,
257 as well as those from other modules:
258
259   package MooseX::Embiggen;
260
261   use Moose ();
262   use Moose::Exporter;
263
264   Moose::Exporter->setup_import_methods(
265       with_meta => ['embiggen'],
266       also      => 'Moose',
267   );
268
269   sub embiggen {
270       my $meta = shift;
271       $meta->embiggen(@_);
272   }
273
274 And then the consumer of your extension can use your C<embiggen> sub:
275
276   package Consumer;
277
278   use MooseX::Embiggen;
279
280   extends 'Thing';
281
282   embiggen ...;
283
284 This can be combined with metaclass and base class roles quite easily.
285
286 =head1 LEGACY EXTENSION MECHANISMS
287
288 Before the existence of L<Moose::Exporter> and
289 L<Moose::Util::MetaRole>, there were a number of other ways to extend
290 Moose. In general, these methods were less cooperative, and only
291 worked well with a single extension.
292
293 These methods include L<metaclass.pm|metaclass>, L<Moose::Policy>
294 (which uses L<metaclass.pm|metaclass> under the hood), and various
295 hacks to do what L<Moose::Exporter> does. Please do not use these for
296 your own extensions.
297
298 Note that if you write a cooperative extension, it should cooperate
299 with older extensions, though older extensions generally do not
300 cooperate with each other.
301
302 =head1 CONCLUSION
303
304 If you can write your extension as one or more metaclass and base
305 object roles, please consider doing so. Make sure to read the docs for
306 L<Moose::Exporter> and L<Moose::Util::MetaRole> as well.
307
308 =cut