summaryrefslogtreecommitdiff
path: root/lib/Moose/Manual/MethodModifiers.pod
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Moose/Manual/MethodModifiers.pod')
-rw-r--r--lib/Moose/Manual/MethodModifiers.pod432
1 files changed, 432 insertions, 0 deletions
diff --git a/lib/Moose/Manual/MethodModifiers.pod b/lib/Moose/Manual/MethodModifiers.pod
new file mode 100644
index 0000000..671a250
--- /dev/null
+++ b/lib/Moose/Manual/MethodModifiers.pod
@@ -0,0 +1,432 @@
+# PODNAME: Moose::Manual::MethodModifiers
+# ABSTRACT: Moose's method modifiers
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Moose::Manual::MethodModifiers - Moose's method modifiers
+
+=head1 VERSION
+
+version 2.1405
+
+=head1 WHAT IS A METHOD MODIFIER?
+
+Moose provides a feature called "method modifiers". You can also think
+of these as "hooks" or "advice".
+
+It's probably easiest to understand this feature with a few examples:
+
+ package Example;
+
+ use Moose;
+
+ sub foo {
+ print " foo\n";
+ }
+
+ before 'foo' => sub { print "about to call foo\n"; };
+ after 'foo' => sub { print "just called foo\n"; };
+
+ around 'foo' => sub {
+ my $orig = shift;
+ my $self = shift;
+
+ print " I'm around foo\n";
+
+ $self->$orig(@_);
+
+ print " I'm still around foo\n";
+ };
+
+Now if I call C<< Example->new->foo >> I'll get the following output:
+
+ about to call foo
+ I'm around foo
+ foo
+ I'm still around foo
+ just called foo
+
+You probably could have figured that out from the names "before",
+"after", and "around".
+
+Also, as you can see, the before modifiers come before around
+modifiers, and after modifiers come last.
+
+When there are multiple modifiers of the same type, the before and
+around modifiers run from the last added to the first, and after
+modifiers run from first added to last:
+
+ before 2
+ before 1
+ around 2
+ around 1
+ primary
+ around 1
+ around 2
+ after 1
+ after 2
+
+=head1 WHY USE THEM?
+
+Method modifiers have many uses. They are often used in roles to alter the
+behavior of methods in the classes that consume the role. See
+L<Moose::Manual::Roles> for more information about roles.
+
+Since modifiers are mostly useful in roles, some of the examples below
+are a bit artificial. They're intended to give you an idea of how
+modifiers work, but may not be the most natural usage.
+
+=head1 BEFORE, AFTER, AND AROUND
+
+Method modifiers can be used to add behavior to methods without modifying the definition of those methods.
+
+=head2 Before and after Modifiers
+
+Method modifiers can be used to add behavior to a method that Moose
+generates for you, such as an attribute accessor:
+
+ has 'size' => ( is => 'rw' );
+
+ before 'size' => sub {
+ my $self = shift;
+
+ if (@_) {
+ Carp::cluck('Someone is setting size');
+ }
+ };
+
+Another use for the before modifier would be to do some sort of
+prechecking on a method call. For example:
+
+ before 'size' => sub {
+ my $self = shift;
+
+ die 'Cannot set size while the person is growing'
+ if @_ && $self->is_growing;
+ };
+
+This lets us implement logical checks that don't make sense as type
+constraints. In particular, they're useful for defining logical rules
+about an object's state changes.
+
+Similarly, an after modifier could be used for logging an action that
+was taken.
+
+Note that the return values of both before and after modifiers are
+ignored.
+
+=head2 Around modifiers
+
+An around modifier is more powerful than either a before or
+after modifier. It can modify the arguments being passed to the
+original method, and you can even decide to simply not call the
+original method at all. You can also modify the return value with an
+around modifier.
+
+An around modifier receives the original method as its first argument,
+I<then> the object, and finally any arguments passed to the method.
+
+ around 'size' => sub {
+ my $orig = shift;
+ my $self = shift;
+
+ return $self->$orig()
+ unless @_;
+
+ my $size = shift;
+ $size = $size / 2
+ if $self->likes_small_things();
+
+ return $self->$orig($size);
+ };
+
+=head2 Wrapping multiple methods at once
+
+C<before>, C<after>, and C<around> can also modify multiple methods
+at once. The simplest example of this is passing them as a list:
+
+ before [qw(foo bar baz)] => sub {
+ warn "something is being called!";
+ };
+
+This will add a C<before> modifier to each of the C<foo>, C<bar>,
+and C<baz> methods in the current class, just as though a separate
+call to C<before> was made for each of them. The list can be passed
+either as a bare list, or as an arrayref. Note that the name of the
+function being modified isn't passed in in any way; this syntax is
+only intended for cases where the function being modified doesn't
+actually matter. If the function name does matter, use something like this:
+
+ for my $func (qw(foo bar baz)) {
+ before $func => sub {
+ warn "$func was called!";
+ };
+ }
+
+=head2 Using regular expressions to select methods to wrap
+
+In addition, you can specify a regular expression to indicate the
+methods to wrap, like so:
+
+ after qr/^command_/ => sub {
+ warn "got a command";
+ };
+
+This will match the regular expression against each method name
+returned by L<Class::MOP::Class/get_method_list>, and add a modifier
+to each one that matches. The same caveats apply as above.
+
+Using regular expressions to determine methods to wrap is quite a bit more
+powerful than the previous alternatives, but it's also quite a bit more
+dangerous. Bear in mind that if your regular expression matches certain Perl
+and Moose reserved method names with a special meaning to Moose or Perl, such
+as C<meta>, C<new>, C<BUILD>, C<DESTROY>, C<AUTOLOAD>, etc, this could cause
+unintended (and hard to debug) problems and is best avoided.
+
+=head2 Execution order of method modifiers and inheritance
+
+When both a superclass and an inheriting class have the same method modifiers,
+the method modifiers of the inheriting class are wrapped around the method
+modifiers of the superclass, as the following example illustrates:
+
+Here is the parent class:
+
+ package Parent;
+ use Moose;
+ sub rant { printf " RANTING!\n" }
+ before 'rant' => sub { printf " In %s before\n", __PACKAGE__ };
+ after 'rant' => sub { printf " In %s after\n", __PACKAGE__ };
+ around 'rant' => sub {
+ my $orig = shift;
+ my $self = shift;
+ printf " In %s around before calling original\n", __PACKAGE__;
+ $self->$orig;
+ printf " In %s around after calling original\n", __PACKAGE__;
+ };
+ 1;
+
+And the child class:
+
+ package Child;
+ use Moose;
+ extends 'Parent';
+ before 'rant' => sub { printf "In %s before\n", __PACKAGE__ };
+ after 'rant' => sub { printf "In %s after\n", __PACKAGE__ };
+ around 'rant' => sub {
+ my $orig = shift;
+ my $self = shift;
+ printf " In %s around before calling original\n", __PACKAGE__;
+ $self->$orig;
+ printf " In %s around after calling original\n", __PACKAGE__;
+ };
+ 1;
+
+And here's the output when we call the wrapped method (C<< Child->rant >>):
+
+ % perl -MChild -e 'Child->new->rant'
+
+ In Child before
+ In Child around before calling original
+ In Parent before
+ In Parent around before calling original
+ RANTING!
+ In Parent around after calling original
+ In Parent after
+ In Child around after calling original
+ In Child after
+
+=head1 INNER AND AUGMENT
+
+Augment and inner are two halves of the same feature. The augment
+modifier provides a sort of inverted subclassing. You provide part of
+the implementation in a superclass, and then document that subclasses
+are expected to provide the rest.
+
+The superclass calls C<inner()>, which then calls the C<augment>
+modifier in the subclass:
+
+ package Document;
+
+ use Moose;
+
+ sub as_xml {
+ my $self = shift;
+
+ my $xml = "<document>\n";
+ $xml .= inner();
+ $xml .= "</document>\n";
+
+ return $xml;
+ }
+
+Using C<inner()> in this method makes it possible for one or more
+subclasses to then augment this method with their own specific
+implementation:
+
+ package Report;
+
+ use Moose;
+
+ extends 'Document';
+
+ augment 'as_xml' => sub {
+ my $self = shift;
+
+ my $xml = " <report>\n";
+ $xml .= inner();
+ $xml .= " </report>\n";
+
+ return $xml;
+ };
+
+When we call C<as_xml> on a Report object, we get something like this:
+
+ <document>
+ <report>
+ </report>
+ </document>
+
+But we also called C<inner()> in C<Report>, so we can continue
+subclassing and adding more content inside the document:
+
+ package Report::IncomeAndExpenses;
+
+ use Moose;
+
+ extends 'Report';
+
+ augment 'as_xml' => sub {
+ my $self = shift;
+
+ my $xml = ' <income>' . $self->income . '</income>';
+ $xml .= "\n";
+ $xml .= ' <expenses>' . $self->expenses . '</expenses>';
+ $xml .= "\n";
+
+ $xml .= inner() || q{};
+
+ return $xml;
+ };
+
+Now our report has some content:
+
+ <document>
+ <report>
+ <income>$10</income>
+ <expenses>$8</expenses>
+ </report>
+ </document>
+
+What makes this combination of C<augment> and C<inner()> special is
+that it allows us to have methods which are called from parent (least
+specific) to child (most specific). This inverts the normal
+inheritance pattern.
+
+Note that in C<Report::IncomeAndExpenses> we call C<inner()> again. If the
+object is an instance of C<Report::IncomeAndExpenses> then this call is a
+no-op, and just returns false. It's a good idea to always call C<inner()> to
+allow for future subclassing.
+
+=head1 OVERRIDE AND SUPER
+
+Finally, Moose provides some simple sugar for Perl's built-in method
+overriding scheme. If you want to override a method from a parent
+class, you can do this with C<override>:
+
+ package Employee;
+
+ use Moose;
+
+ extends 'Person';
+
+ has 'job_title' => ( is => 'rw' );
+
+ override 'display_name' => sub {
+ my $self = shift;
+
+ return super() . q{, } . $self->title();
+ };
+
+The call to C<super()> is almost the same as calling C<<
+$self->SUPER::display_name >>. The difference is that the arguments
+passed to the superclass's method will always be the same as the ones
+passed to the method modifier, and cannot be changed.
+
+All arguments passed to C<super()> are ignored, as are any changes
+made to C<@_> before C<super()> is called.
+
+=head1 SEMI-COLONS
+
+Because all of these method modifiers are implemented as Perl
+functions, you must always end the modifier declaration with a
+semi-colon:
+
+ after 'foo' => sub { };
+
+=head1 CAVEATS
+
+These method modification features do not work well with multiple inheritance,
+due to how method resolution is performed in Perl. Experiment with a test
+program to ensure your class hierarchy works as expected, or more preferably,
+don't use multiple inheritance (roles can help with this)!
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Stevan Little <stevan.little@iinteractive.com>
+
+=item *
+
+Dave Rolsky <autarch@urth.org>
+
+=item *
+
+Jesse Luehrs <doy@tozt.net>
+
+=item *
+
+Shawn M Moore <code@sartak.org>
+
+=item *
+
+יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
+
+=item *
+
+Karen Etheridge <ether@cpan.org>
+
+=item *
+
+Florian Ragwitz <rafl@debian.org>
+
+=item *
+
+Hans Dieter Pearcey <hdp@weftsoar.net>
+
+=item *
+
+Chris Prather <chris@prather.org>
+
+=item *
+
+Matt S Trout <mst@shadowcat.co.uk>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2006 by Infinity Interactive, Inc..
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut