more-cookin
[gitmo/Moose.git] / lib / Moose.pm
CommitLineData
fcd84ca9 1
2package Moose;
3
4use strict;
5use warnings;
6
8339fae2 7our $VERSION = '0.03';
fcd84ca9 8
cc65ead0 9use Scalar::Util 'blessed', 'reftype';
fcd84ca9 10use Carp 'confess';
bc1e29b5 11use Sub::Name 'subname';
fcd84ca9 12
7f18097c 13use UNIVERSAL::require;
14
ef1d5f4b 15use Class::MOP;
16
c0e30cf5 17use Moose::Meta::Class;
18use Moose::Meta::Attribute;
7415b2cb 19use Moose::Meta::TypeConstraint;
7c13858b 20use Moose::Meta::TypeCoercion;
c0e30cf5 21
fcd84ca9 22use Moose::Object;
7415b2cb 23use Moose::Util::TypeConstraints;
a15dff8d 24
fcd84ca9 25sub import {
26 shift;
27 my $pkg = caller();
28
fc5609d2 29 # we should never export to main
30 return if $pkg eq 'main';
31
a15dff8d 32 Moose::Util::TypeConstraints->import($pkg);
182134e8 33
34 # make a subtype for each Moose class
7415b2cb 35 subtype $pkg
36 => as Object
37 => where { $_->isa($pkg) };
5569c072 38
fcd84ca9 39 my $meta;
40 if ($pkg->can('meta')) {
41 $meta = $pkg->meta();
42 (blessed($meta) && $meta->isa('Class::MOP::Class'))
43 || confess "Whoops, not møøsey enough";
44 }
45 else {
c0e30cf5 46 $meta = Moose::Meta::Class->initialize($pkg => (
47 ':attribute_metaclass' => 'Moose::Meta::Attribute'
e522431d 48 ));
49 $meta->add_method('meta' => sub {
50 # re-initialize so it inherits properly
51 Moose::Meta::Class->initialize($pkg => (
52 ':attribute_metaclass' => 'Moose::Meta::Attribute'
53 ));
54 })
fcd84ca9 55 }
ad1ac1bd 56
bc1e29b5 57 # NOTE:
58 # &alias_method will install the method, but it
59 # will not name it with
60
61 # handle superclasses
7f18097c 62 $meta->alias_method('extends' => subname 'Moose::extends' => sub {
d7f17ebb 63 foreach my $super (@_) {
64 # see if this is already
65 # loaded in the symbol table
66 next if _is_class_already_loaded($super);
67 # otherwise require it ...
68 ($super->require)
69 || confess "Could not load superclass '$super' because : " . $UNIVERSAL::require::ERROR;
70 }
7f18097c 71 $meta->superclasses(@_)
5e030bec 72 });
505c6fac 73
c0e30cf5 74 # handle attributes
29db16a9 75 $meta->alias_method('has' => subname 'Moose::has' => sub {
76 my ($name, %options) = @_;
77 if (exists $options{is}) {
cc65ead0 78 if ($options{is} eq 'ro') {
79 $options{reader} = $name;
80 }
81 elsif ($options{is} eq 'rw') {
82 $options{accessor} = $name;
83 }
29db16a9 84 }
cc65ead0 85 if (exists $options{isa}) {
e90c03d0 86 # allow for anon-subtypes here ...
66811d63 87 if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
88 $options{type_constraint} = $options{isa};
cc65ead0 89 }
90 else {
e90c03d0 91 # otherwise assume it is a constraint
7c13858b 92 my $constraint = find_type_constraint($options{isa});
e90c03d0 93 # if the constraing it not found ....
94 unless (defined $constraint) {
95 # assume it is a foreign class, and make
96 # an anon constraint for it
66811d63 97 $constraint = subtype Object => where { $_->isa($options{isa}) };
7415b2cb 98 }
e90c03d0 99 $options{type_constraint} = $constraint;
cc65ead0 100 }
29db16a9 101 }
102 $meta->add_attribute($name, %options)
103 });
3c7278fb 104
c0e30cf5 105 # handle method modifers
bc1e29b5 106 $meta->alias_method('before' => subname 'Moose::before' => sub {
e5ebe4ce 107 my $code = pop @_;
108 $meta->add_before_method_modifier($_, $code) for @_;
109 });
bc1e29b5 110 $meta->alias_method('after' => subname 'Moose::after' => sub {
e5ebe4ce 111 my $code = pop @_;
fc5609d2 112 $meta->add_after_method_modifier($_, $code) for @_;
e5ebe4ce 113 });
bc1e29b5 114 $meta->alias_method('around' => subname 'Moose::around' => sub {
c0e30cf5 115 my $code = pop @_;
fc5609d2 116 $meta->add_around_method_modifier($_, $code) for @_;
c0e30cf5 117 });
b6fe348f 118
119 $meta->alias_method('super' => subname 'Moose::super' => sub {});
120 $meta->alias_method('override' => subname 'Moose::override' => sub {
121 my ($name, $method) = @_;
122 my $super = $meta->find_next_method_by_name($name);
123 (defined $super)
124 || confess "You cannot override '$name' because it has no super method";
125 $meta->add_method($name => sub {
126 my @args = @_;
127 no strict 'refs';
128 no warnings 'redefine';
129 local *{$meta->name . '::super'} = sub { $super->(@args) };
130 return $method->(@args);
131 });
132 });
133
134 $meta->alias_method('inner' => subname 'Moose::inner' => sub {});
135 $meta->alias_method('augment' => subname 'Moose::augment' => sub {
136 my ($name, $method) = @_;
137 my $super = $meta->find_next_method_by_name($name);
138 (defined $super)
139 || confess "You cannot augment '$name' because it has no super method";
140 $meta->add_method($name => sub {
141 my @args = @_;
142 no strict 'refs';
143 no warnings 'redefine';
144 local *{$super->package_name . '::inner'} = sub { $method->(@args) };
145 return $super->(@args);
146 });
147 });
5569c072 148
c0e30cf5 149 # make sure they inherit from Moose::Object
5569c072 150 $meta->superclasses('Moose::Object')
151 unless $meta->superclasses();
ad1ac1bd 152
c0e30cf5 153 # we recommend using these things
154 # so export them for them
5569c072 155 $meta->alias_method('confess' => \&Carp::confess);
156 $meta->alias_method('blessed' => \&Scalar::Util::blessed);
fcd84ca9 157}
158
d7f17ebb 159sub _is_class_already_loaded {
160 my $name = shift;
161 no strict 'refs';
162 return 1 if defined ${"${name}::VERSION"} || defined @{"${name}::ISA"};
163 foreach (keys %{"${name}::"}) {
164 next if substr($_, -2, 2) eq '::';
165 return 1 if defined &{"${name}::$_"};
166 }
167 return 0;
168}
169
fcd84ca9 1701;
171
172__END__
173
174=pod
175
176=head1 NAME
177
e522431d 178Moose - Moose, it's the new Camel
fcd84ca9 179
180=head1 SYNOPSIS
e522431d 181
182 package Point;
183 use Moose;
184
182134e8 185 has 'x' => (isa => 'Int', is => 'rw');
186 has 'y' => (isa => 'Int', is => 'rw');
e522431d 187
188 sub clear {
189 my $self = shift;
190 $self->x(0);
191 $self->y(0);
192 }
193
194 package Point3D;
195 use Moose;
196
197 extends 'Point';
09fdc1dc 198
182134e8 199 has 'z' => (isa => 'Int');
e522431d 200
201 after 'clear' => sub {
202 my $self = shift;
203 $self->{z} = 0;
204 };
205
206=head1 CAVEAT
207
208This is a B<very> early release of this module, it still needs
209some fine tuning and B<lots> more documentation. I am adopting
210the I<release early and release often> approach with this module,
211so keep an eye on your favorite CPAN mirror!
212
fcd84ca9 213=head1 DESCRIPTION
214
e522431d 215Moose is an extension of the Perl 5 object system.
216
217=head2 Another object system!?!?
fcd84ca9 218
e522431d 219Yes, I know there has been an explosion recently of new ways to
220build object's in Perl 5, most of them based on inside-out objects,
221and other such things. Moose is different because it is not a new
222object system for Perl 5, but instead an extension of the existing
223object system.
3c7278fb 224
e522431d 225Moose is built on top of L<Class::MOP>, which is a metaclass system
226for Perl 5. This means that Moose not only makes building normal
505c6fac 227Perl 5 objects better, but it also provides the power of metaclass
228programming.
e522431d 229
230=head2 What does Moose stand for??
231
232Moose doesn't stand for one thing in particular, however, if you
233want, here are a few of my favorites, feel free to contribute
234more :)
235
236=over 4
237
5569c072 238=item Make Other Object Systems Envious
e522431d 239
240=item Makes Object Orientation So Easy
241
5569c072 242=item Makes Object Orientation Spiffy- Er (sorry ingy)
505c6fac 243
5569c072 244=item Most Other Object Systems Emasculate
505c6fac 245
246=item My Overcraft Overfilled (with) Some Eels
247
248=item Moose Often Ovulate Sorta Early
249
505c6fac 250=item Many Overloaded Object Systems Exists
251
252=item Moose Offers Often Super Extensions
253
e522431d 254=back
3c7278fb 255
6ba6d68c 256=head1 BUILDING CLASSES WITH MOOSE
257
258Moose makes every attempt to provide as much convience during class
259construction/definition, but still stay out of your way if you want
260it to. Here are some of the features Moose provides:
261
262Unless specified with C<extends>, any class which uses Moose will
263inherit from L<Moose::Object>.
264
265Moose will also manage all attributes (including inherited ones) that
266are defined with C<has>. And assuming that you call C<new> which is
267inherited from L<Moose::Object>, then this includes properly initializing
268all instance slots, setting defaults where approprtiate and performing any
269type constraint checking or coercion.
270
271=head1 EXPORTED FUNCTIONS
272
273Moose will export a number of functions into the class's namespace, which
274can then be used to set up the class. These functions all work directly
275on the current class.
276
277=over 4
278
279=item B<meta>
280
281This is a method which provides access to the current class's metaclass.
282
283=item B<extends (@superclasses)>
284
285This function will set the superclass(es) for the current class.
286
287This approach is recommended instead of C<use base>, because C<use base>
288actually C<push>es onto the class's C<@ISA>, whereas C<extends> will
289replace it. This is important to ensure that classes which do not have
290superclasses properly inherit from L<Moose::Object>.
291
292=item B<has ($name, %options)>
293
294This will install an attribute of a given C<$name> into the current class.
295The list of C<%options> are the same as those provided by both
296L<Class::MOP::Attribute> and L<Moose::Meta::Attribute>, in addition to a
297few convience ones provided by Moose which are listed below:
298
299=over 4
300
076c81ed 301=item I<is =E<gt> 'rw'|'ro'>
6ba6d68c 302
303The I<is> option accepts either I<rw> (for read/write) or I<ro> (for read
304only). These will create either a read/write accessor or a read-only
305accessor respectively, using the same name as the C<$name> of the attribute.
306
307If you need more control over how your accessors are named, you can use the
308I<reader>, I<writer> and I<accessor> options inherited from L<Moose::Meta::Attribute>.
309
076c81ed 310=item I<isa =E<gt> $type_name>
6ba6d68c 311
312The I<isa> option uses Moose's type constraint facilities to set up runtime
313type checking for this attribute. Moose will perform the checks during class
314construction, and within any accessors. The C<$type_name> argument must be a
315string. The string can be either a class name, or a type defined using
316Moose's type defintion features.
317
318=back
319
076c81ed 320=item B<before $name|@names =E<gt> sub { ... }>
6ba6d68c 321
076c81ed 322=item B<after $name|@names =E<gt> sub { ... }>
6ba6d68c 323
076c81ed 324=item B<around $name|@names =E<gt> sub { ... }>
6ba6d68c 325
326This three items are syntactic sugar for the before, after and around method
327modifier features that L<Class::MOP> provides. More information on these can
328be found in the L<Class::MOP> documentation for now.
329
159da176 330=item B<super>
331
332The keyword C<super> is a noop when called outside of an C<override> method. In
333the context of an C<override> method, it will call the next most appropriate
334superclass method with the same arguments as the original method.
335
336=item B<override ($name, &sub)>
337
338An C<override> method, is a way of explictly saying "I am overriding this
339method from my superclass". You can call C<super> within this method, and
340it will work as expected. The same thing I<can> be accomplished with a normal
341method call and the C<SUPER::> pseudo-package, it is really your choice.
342
343=item B<inner>
344
345The keyword C<inner>, much like C<super>, is a no-op outside of the context of
346an C<augment> method. You can think of C<inner> as being the inverse of
347C<super>, the details of how C<inner> and C<augment> work is best described in
348the L<Moose::Cookbook>.
349
350=item B<augment ($name, &sub)>
351
352An C<augment> method, is a way of explictly saying "I am augmenting this
353method from my superclass". Once again, the details of how C<inner> and
354C<augment> work is best described in the L<Moose::Cookbook>.
355
6ba6d68c 356=item B<confess>
357
358This is the C<Carp::confess> function, and exported here beause I use it
359all the time. This feature may change in the future, so you have been warned.
360
361=item B<blessed>
362
363This is the C<Scalar::Uti::blessed> function, it is exported here beause I
364use it all the time. It is highly recommended that this is used instead of
365C<ref> anywhere you need to test for an object's class name.
366
367=back
368
5569c072 369=head1 ACKNOWLEDGEMENTS
370
371=over 4
372
54c189df 373=item I blame Sam Vilain for introducing me to the insanity that is meta-models.
5569c072 374
54c189df 375=item I blame Audrey Tang for then encouraging my meta-model habit in #perl6.
5569c072 376
076c81ed 377=item Without Yuval "nothingmuch" Kogman this module would not be possible,
54c189df 378and it certainly wouldn't have this name ;P
5569c072 379
380=item The basis of the TypeContraints module was Rob Kinyon's idea
381originally, I just ran with it.
382
076c81ed 383=item Thanks to mst & chansen and the whole #moose poose for all the
d46a48f3 384ideas/feature-requests/encouragement
385
5569c072 386=back
387
e90c03d0 388=head1 SEE ALSO
389
390=over 4
391
6ba6d68c 392=item L<Class::MOP> documentation
393
394=item The #moose channel on irc.perl.org
395
e90c03d0 396=item L<http://forum2.org/moose/>
397
159da176 398=item L<http://www.cs.utah.edu/plt/publications/oopsla04-gff.pdf>
399
400This paper (suggested by lbr on #moose) was what lead to the implementation
401of the C<super>/C<overrride> and C<inner>/C<augment> features. If you really
402want to understand this feature, I suggest you read this.
403
e90c03d0 404=back
405
fcd84ca9 406=head1 BUGS
407
408All complex software has bugs lurking in it, and this module is no
409exception. If you find a bug please either email me, or add the bug
410to cpan-RT.
411
fcd84ca9 412=head1 AUTHOR
413
414Stevan Little E<lt>stevan@iinteractive.comE<gt>
415
416=head1 COPYRIGHT AND LICENSE
417
418Copyright 2006 by Infinity Interactive, Inc.
419
420L<http://www.iinteractive.com>
421
422This library is free software; you can redistribute it and/or modify
423it under the same terms as Perl itself.
424
425=cut