rewrite nonMoo detection
[gitmo/Moo.git] / lib / Moo.pm
CommitLineData
b1eebd55 1package Moo;
6c74d087 2
3use strictures 1;
b1eebd55 4use Moo::_Utils;
6c74d087 5
d6276203 6our $VERSION = '0.009004'; # 0.9.4
6d71fae7 7$VERSION = eval $VERSION;
8
14f32032 9our %MAKERS;
10
6c74d087 11sub import {
12 my $target = caller;
a16d301e 13 my $class = shift;
de3d4906 14 strictures->import;
1ba11455 15 return if $MAKERS{$target}; # already exported into this package
6c74d087 16 *{_getglob("${target}::extends")} = sub {
fb5074f6 17 _load_module($_) for @_;
786e5ba0 18 # Can't do *{...} = \@_ or 5.10.0's mro.pm stops seeing @ISA
19 @{*{_getglob("${target}::ISA")}{ARRAY}} = @_;
6c74d087 20 };
21 *{_getglob("${target}::with")} = sub {
b1eebd55 22 require Moo::Role;
6c74d087 23 die "Only one role supported at a time by with" if @_ > 1;
369a4c50 24 Moo::Role->apply_role_to_package($target, $_[0]);
6c74d087 25 };
a16d301e 26 $MAKERS{$target} = {};
14f32032 27 *{_getglob("${target}::has")} = sub {
28 my ($name, %spec) = @_;
29 ($MAKERS{$target}{accessor} ||= do {
30 require Method::Generate::Accessor;
31 Method::Generate::Accessor->new
32 })->generate_method($target, $name, \%spec);
a16d301e 33 $class->_constructor_maker_for($target)
34 ->register_attribute_specs($name, \%spec);
14f32032 35 };
6c74d087 36 foreach my $type (qw(before after around)) {
37 *{_getglob "${target}::${type}"} = sub {
dccea57d 38 require Class::Method::Modifiers;
6c74d087 39 _install_modifier($target, $type, @_);
40 };
41 }
42 {
43 no strict 'refs';
44 @{"${target}::ISA"} = do {
b1eebd55 45 require Moo::Object; ('Moo::Object');
6c74d087 46 } unless @{"${target}::ISA"};
47 }
48}
49
a16d301e 50sub _constructor_maker_for {
c4570291 51 my ($class, $target, $select_super) = @_;
a16d301e 52 return unless $MAKERS{$target};
53 $MAKERS{$target}{constructor} ||= do {
54 require Method::Generate::Constructor;
c4570291 55 require Sub::Defer;
56 my ($moo_constructor, $con);
de5c0e53 57
c4570291 58 if ($select_super && $MAKERS{$select_super}) {
59 $moo_constructor = 1;
60 $con = $MAKERS{$select_super}{constructor};
61 } else {
de5c0e53 62 my $t_new = $target->can('new');
c4570291 63 if ($t_new) {
64 if ($t_new == Moo::Object->can('new')) {
65 $moo_constructor = 1;
66 } elsif (my $defer_target = (Sub::Defer::defer_info($t_new)||[])->[0]) {
67 my ($pkg) = ($defer_target =~ /^(.*)::[^:]+$/);
68 if ($MAKERS{$pkg}) {
69 $moo_constructor = 1;
70 $con = $MAKERS{$pkg}{constructor};
71 }
72 }
73 } else {
74 $moo_constructor = 1; # no other constructor, make a Moo one
75 }
de5c0e53 76 };
77 require Moo::_mro unless $moo_constructor;
a16d301e 78 Method::Generate::Constructor
79 ->new(
80 package => $target,
81 accessor_generator => do {
82 require Method::Generate::Accessor;
83 Method::Generate::Accessor->new;
de5c0e53 84 },
85 ($moo_constructor ? ()
86 : (construction_string => '$class->next::method(@_)'))
a16d301e 87 )
88 ->install_delayed
de5c0e53 89 ->register_attribute_specs(%{$con?$con->all_attribute_specs:{}})
a16d301e 90 }
91}
92
6c74d087 931;
8146585e 94
505f8b7a 95=head1 NAME
96
97Moo - Minimalist Object Orientation (with Moose compatiblity)
98
5ef50c4d 99=head1 WARNING WARNING WARNING
100
101This is a 0.9 release because we're fairly sure it works. For us. Until it's
102tested in the wild, we make no guarantees it also works for you.
103
104If this module does something unexpected, please submit a failing test.
105
106But if it eats your cat, sleeps with your boyfriend, or pushes grandma down
107the stairs to save her from the terrible secret of space, it's not our fault.
108
8146585e 109=head1 SYNOPSIS
110
111 package Cat::Food;
112
113 use Moo;
114 use Sub::Quote;
115
116 sub feed_lion {
117 my $self = shift;
118 my $amount = shift || 1;
119
120 $self->pounds( $self->pounds - $amount );
121 }
122
123 has taste => (
124 is => 'ro',
125 );
126
127 has brand => (
128 is => 'ro',
129 isa => sub {
130 die "Only SWEET-TREATZ supported!" unless $_[0] eq 'SWEET-TREATZ'
131 },
132);
133
134 has pounds => (
135 is => 'rw',
136 isa => quote_sub q{ die "$_[0] is too much cat food!" unless $_[0] < 15 },
137 );
138
139 1;
140
141and else where
142
143 my $full = Cat::Food->new(
144 taste => 'DELICIOUS.',
145 brand => 'SWEET-TREATZ',
146 pounds => 10,
147 );
148
149 $full->feed_lion;
150
151 say $full->pounds;
152
153=head1 DESCRIPTION
154
155This module is an extremely light-weight, high-performance L<Moose> replacement.
156It also avoids depending on any XS modules to allow simple deployments. The
157name C<Moo> is based on the idea that it provides almost -but not quite- two
158thirds of L<Moose>.
159
160Unlike C<Mouse> this module does not aim at full L<Moose> compatibility. See
161L</INCOMPATIBILITIES> for more details.
162
5d5bb71d 163=head1 WHY MOO EXISTS
164
165If you want a full object system with a rich Metaprotocol, L<Moose> is
166already wonderful.
167
168I've tried several times to use L<Mouse> but it's 3x the size of Moo and
169takes longer to load than most of my Moo based CGI scripts take to run.
170
171If you don't want L<Moose>, you don't want "less metaprotocol" like L<Mouse>,
172you want "as little as possible" - which means "no metaprotocol", which is
173what Moo provides.
174
175By Moo 1.0 I intend to have Moo's equivalent of L<Any::Moose> built in -
176if Moose gets loaded, any Moo class or role will act as a Moose equivalent
177if treated as such.
178
179Hence - Moo exists as its name - Minimal Object Orientation - with a pledge
180to make it smooth to upgrade to L<Moose> when you need more than minimal
181features.
182
8146585e 183=head1 IMPORTED METHODS
184
185=head2 new
186
187 Foo::Bar->new( attr1 => 3 );
188
189or
190
191 Foo::Bar->new({ attr1 => 3 });
192
2e575bcd 193=head2 BUILDARGS
194
195This feature from Moose is not yet supported.
196
8146585e 197=head2 BUILDALL
198
199Don't override (or probably even call) this method. Instead, you can define
200a C<BUILD> method on your class and the constructor will automatically call the
201C<BUILD> method from parent down to child after the object has been
202instantiated. Typically this is used for object validation or possibly logging.
203
204=head2 does
205
206 if ($foo->does('Some::Role1')) {
207 ...
208 }
209
210Returns true if the object composes in the passed role.
211
212=head1 IMPORTED SUBROUTINES
213
214=head2 extends
215
216 extends 'Parent::Class';
217
2e575bcd 218Declares base class. Multiple superclasses can be passed for multiple
219inheritance (but please use roles instead).
220
221Calling extends more than once will REPLACE your superclasses, not add to
222them like 'use base' would.
8146585e 223
224=head2 with
225
226 with 'Some::Role1';
227 with 'Some::Role2';
228
229Composes a L<Role::Tiny> into current class. Only one role may be composed in
230at a time to allow the code to remain as simple as possible.
231
232=head2 has
233
234 has attr => (
235 is => 'ro',
236 );
237
238Declares an attribute for the class.
239
240The options for C<has> are as follows:
241
242=over 2
243
244=item * is
245
246B<required>, must be C<ro> or C<rw>. Unsurprisingly, C<ro> generates an
0654a8fa 247accessor that will not respond to arguments; to be clear: a getter only. C<rw>
8146585e 248will create a perlish getter/setter.
249
250=item * isa
251
252Takes a coderef which is meant to validate the attribute. Unlike L<Moose> Moo
253does not include a basic type system, so instead of doing C<< isa => 'Num' >>,
254one should do
255
256 isa => quote_sub q{
257 die "$_[0] is not a number!" unless looks_like_number $_[0]
258 },
259
260L<Sub::Quote aware|/SUB QUOTE AWARE>
261
262=item * coerce
263
2e575bcd 264This Moose feature is not yet supported
265
266=begin hide
267
8146585e 268Takes a coderef which is meant to coerce the attribute. The basic idea is to
269do something like the following:
270
271 coerce => quote_sub q{
272 $_[0] + 1 unless $_[0] % 2
273 },
274
275L<Sub::Quote aware|/SUB QUOTE AWARE>
276
2e575bcd 277=end hide
278
8146585e 279=item * trigger
280
281Takes a coderef which will get called any time the attribute is set. Coderef
282will be invoked against the object with the new value as an argument.
283
2e575bcd 284Note that Moose also passes the old value, if any; this feature is not yet
285supported.
286
8146585e 287L<Sub::Quote aware|/SUB QUOTE AWARE>
288
289=item * default
290
2e575bcd 291Takes a coderef which will get called with $self as its only argument
292to populate an attribute if no value is supplied to the constructor - or
293if the attribute is lazy, when the attribute is first retrieved if no
294value has yet been provided.
295
296Note that if your default is fired during new() there is no guarantee that
297other attributes have been populated yet so you should not rely on their
298existence.
8146585e 299
300L<Sub::Quote aware|/SUB QUOTE AWARE>
301
302=item * predicate
303
2e575bcd 304Takes a method name which will return true if an attribute has a value.
8146585e 305
306A common example of this would be to call it C<has_$foo>, implying that the
307object has a C<$foo> set.
308
309=item * builder
310
2e575bcd 311Takes a method name which will be called to create the attribute - functions
312exactly like default except that instead of calling
313
314 $default->($self);
315
316Moo will call
317
318 $self->$builder;
8146585e 319
320=item * clearer
321
322Takes a method name which will clear the attribute.
323
324=item * lazy
325
326B<Boolean>. Set this if you want values for the attribute to be grabbed
327lazily. This is usually a good idea if you have a L</builder> which requires
328another attribute to be set.
329
330=item * required
331
332B<Boolean>. Set this if the attribute must be passed on instantiation.
333
334=item * weak_ref
335
336B<Boolean>. Set this if you want the reference that the attribute contains to
337be weakened; use this when circular references are possible, which will cause
338leaks.
339
340=item * init_arg
341
342Takes the name of the key to look for at instantiation time of the object. A
343common use of this is to make an underscored attribute have a non-underscored
344initialization name. C<undef> means that passing the value in on instantiation
345
346=back
347
348=head2 before
349
350 before foo => sub { ... };
351
352See L<< Class::Method::Modifiers/before method(s) => sub { ... } >> for full
353documentation.
354
355=head2 around
356
357 around foo => sub { ... };
358
359See L<< Class::Method::Modifiers/around method(s) => sub { ... } >> for full
360documentation.
361
362=head2 after
363
364 after foo => sub { ... };
365
366See L<< Class::Method::Modifiers/after method(s) => sub { ... } >> for full
367documentation.
368
8146585e 369=head1 SUB QUOTE AWARE
370
371L<Sub::Quote/quote_sub> allows us to create coderefs that are "inlineable,"
372giving us a handy, XS-free speed boost. Any option that is L<Sub::Quote>
373aware can take advantage of this.
374
2e575bcd 375=head1 INCOMPATIBILITIES WITH MOOSE
8146585e 376
377You can only compose one role at a time. If your application is large or
378complex enough to warrant complex composition, you wanted L<Moose>.
379
380There is no complex type system. C<isa> is verified with a coderef, if you
381need complex types, just make a library of coderefs, or better yet, functions
382that return quoted subs.
383
2e575bcd 384C<initializer> is not supported in core since the author considers it to be a
385bad idea but may be supported by an extension in future.
8146585e 386
387There is no meta object. If you need this level of complexity you wanted
2e575bcd 388L<Moose> - Moo succeeds at being small because it explicitly does not
389provide a metaprotocol.
8146585e 390
2e575bcd 391No support for C<super>, C<override>, C<inner>, or C<augment> - override can
392be handled by around albeit with a little more typing, and the author considers
393augment to be a bad idea.
8146585e 394
395L</default> only supports coderefs, because doing otherwise is usually a
396mistake anyway.
397
398C<lazy_build> is not supported per se, but of course it will work if you
399manually set all the options it implies.
400
2e575bcd 401C<auto_deref> is not supported since the author considers it a bad idea.
8146585e 402
2e575bcd 403C<documentation> is not supported since it's a very poor replacement for POD.