Moose::Cookbook::Recipe1 - The B<Point> example. |
Moose::Cookbook::Recipe1 - The (always classic) Point example.
package Point; use Moose; has 'x' => (isa => 'Int', is => 'ro'); has 'y' => (isa => 'Int', is => 'rw'); sub clear { my $self = shift; $self->{x} = 0; $self->y(0); } package Point3D; use Moose; extends 'Point'; has 'z' => (isa => 'Int'); after 'clear' => sub { my $self = shift; $self->{z} = 0; };
This is the classic Point example. This one in particular I took from the Perl 6 Apocalypse 12 document, but it is similar to the example found in the classic K&R C book as well, and many other places. And now, onto the code:
As with all Perl 5 classes, a Moose class is defined in a package.
Moose now handles turning on strict
and warnings
for you, so
all you need to do is say use Moose
, and no kittens will die.
By loading Moose, we are enabling the loading of the Moose ``environment'' into our package. This means that we import some functions which serve as Moose ``keywords''. These aren't anything fancy, just plain old exported functions.
Another important thing happens at this stage as well. Moose will automatically set your package's superclass to be the Moose::Object manpage. The reason we do this, is so that we can be sure that your class will inherit from the Moose::Object manpage and get the benefits that provides (see the Moose::Object manpage for details). However, you don't actually have to inherit from the Moose::Object manpage if you don't want to. All Moose features will still be accessible to you.
Now, onto the keywords. The first one we see here is has
, which
defines an instance attribute in your class:
has 'x' => (isa => 'Int', is => 'ro');
This will create an attribute named x
, which will expect the
value stored in the attribute to pass the type constraint Int
(1),
and the accessor generated for this attribute will be read-only
(abbreviated as ro
).
The next has
line is very similar, with only one difference:
has 'y' => (isa => 'Int', is => 'rw');
A read/write (abbreviated as rw
) accessor will be generated for
the y
attribute.
At this point the attributes have been defined, and it is time to
define our methods. In Moose, as with regular Perl 5 OO, a method
is just a subroutine defined within the package. So here we create
the clear
method.
sub clear { my $self = shift; $self->{x} = 0; $self->y(0); }
It is pretty standard, the only thing to note is that we are directly
accessing the x
slot in the instance (2). This is because the
value was created with a read-only accessor. This also shows that Moose
objects are not anything out of the ordinary, but just regular old
blessed HASH references. This means they are very compatible with
other Perl 5 (non-Moose) classes as well.
The next part of the code to review is the Point subclass,
Point3D. The first item you might notice is that we do not use
the standard use base
declaration here. Instead we use the Moose
keyword extends
like so:
extends 'Point';
This keyword will function very much like use base
does in that
it will make an attempt to load your class if it has not already been
loaded. However, it differs on one important point. The extends
keyword will overwrite any previous values in your package's @ISA
,
where use base
will push
values onto the package's @ISA
. It
is my opinion that the behavior of extends
is more intuitive in
that it is more explicit about defining the superclass relationship.
A small digression here: both Moose and extends
support multiple
inheritance. You simply pass all the superclasses to extends
,
like so:
extends 'Foo', 'Bar', 'Baz'; Now, back to our B<Point3D> class. The next thing we do is to create a new attribute for B<Point3D> called C<z>.
has 'z' => (isa => 'Int');
As with Point's x
and y
attributes, this attribute has a
type constraint of Int
, but it differs in that it does not
ask for any autogenerated accessors. The result being (aside from
broken object encapsulation) that z
is a private attribute.
Next comes another Moose feature which we call method ``modifiers''
(or method ``advice'' for the AOP inclined). The modifier used here
is the after
modifier, and looks like this:
after 'clear' => sub { my $self = shift; $self->{z} = 0; };
This modifier tells Moose to install a clear
method for
Point3D that will first run the clear
method for the
superclass (in this case Point::clear
), and then run this
method after it (passing in the same arguments as the original
method).
Now, of course using the after
modifier is not the only way to
accomplish this. I mean, after all, this is Perl right? You
would get the same results with this code:
sub clear { my $self = shift; $self->SUPER::clear(); $self->{z} = 0; }
You could also use another Moose method modifier, override
here,
and get the same results again. Here is how that would look:
override 'clear' => sub { my $self = shift; super(); $self->{z} = 0; }; The C<override> modifier allows you to use the C<super> keyword within it to dispatch to the superclass's method in a very Ruby-ish style.
Now, of course, what use is a class if you can't instantiate objects
with it? Since Point inherits from the Moose::Object manpage, it will also
inherit the default the Moose::Object manpage constructor: new
. Here
are two examples of how that is used:
my $point = Point->new(x => 1, y => 2); my $point3d = Point3D->new(x => 1, y => 2, z => 3);
As you can see, new
accepts named argument pairs for any of the
attributes. It does not require that you pass in the all the
attributes, and it will politely ignore any named arguments it does
not recognize.
From here on, you can use $point
and $point3d
just as you would
any other Perl 5 object. For a more detailed example of what can be
done, you can refer to the t/001_recipe.t test file.
I hope this recipe has given you some explanation of how to use Moose to build your Perl 5 classes. The next recipe will build upon the basics shown here with more complex attributes and methods. Please read on :)
Int
is one. For more information on the builtin type constraints
and the type constraint system in general, see the
the Moose::Util::TypeConstraints manpage documentation.
http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html
Stevan Little <stevan@iinteractive.com>
Copyright 2006-2008 by Infinity Interactive, Inc.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Moose::Cookbook::Recipe1 - The B<Point> example. |