=pod

=encoding utf-8

=head1 NAME

Zydeco::Manual::06_MethodModifiers - Method modifiers to easily wrap or override inherited methods

=head1 SYNOPSIS

  package MyApp {
    use Zydeco;
    
    class Event {
      has date;
      method occur () {
        ...;
      }
    }
    
    class Wedding extends Event {
      before occur {
        say "Speak now or forever hold your peace";
      }
      after occur {
        say "You may kiss the bride";
      }
    }
  }

=head1 MANUAL

Zydeco allows subclasses to modify the methods they inherit from their
parents, allow roles to modify the methods in the classes that consume
them, and allow classes to modify the methods they consume from roles.

=head2 C<< before >> and C<< after >> modifiers.

A C<before> modifier executes before the original method is called.
Its return value is ignored. If it throws an exception, this will
prevent the original method from being called.

An C<after> modifier executes after the original method is called.
Its return value is also ignored.

Both of these modifiers may see the parameters passed to the original
method.

  role Event {
    method set_host (Person $host) {
      ...;
    }
  }
  
  class LegalIssue with Throwable;
  
  class Wedding with Event {
    before set_host (Person $host) {
      $host->has_licence or LegalIssue->throw;
    }
  }

Like with method definitions, C<< $self >> and C<< $class >> are available.

Note that signatures are checked separately by the modifier and the
original method. So it will be checked twice that C<< $host >> is a
Person object. Because checking is performed at run-time, for
performance you may wish to simplify the signature in your modifiers.

  role Event {
    method set_host (Person $host) {
      ...;
    }
  }
  
  class LegalIssue with Throwable;
  
  class Wedding with Event {
    before set_host ($host) {
      $host->has_licence or LegalIssue->throw;
    }
  }

This is especially true for C<after> modifiers, where the modifiers can
be confident that the parameters have already passed the original method's
signature checks.

=head2 C<< around >> modifiers.

Unlike C<before> and C<after> modifiers, C<around> modifiers can modify
the arguments passed to the original method, can change the return value,
and can even prevent the original method from being called. They allow
you to wrap the original method in arbitrary ways.

Here's an example:

  package MyApp;
  use Zydeco;
  
  class PriceAdder {
    method add_prices ( ArrayRef[Num] $prices ) {
      my $sum = 0;
      $sum += $_ for @$prices;
      return $sum;
    }
  }
  
  class PriceAdder::WithCommission extends PriceAdder {
    has commission = 0;  # percent
    
    around add_prices ( $prices ) {
      my $sum = $self->$next( $prices );
      return $sum * ( 1 + ($self->commission/100) );
    }
  }
  
  my $adder = MyApp->new_priceadder_withcommission( commission => 5 );
  say $adder->add_prices( [ 100, 400, 500 ] );   # ==> 1050

Like with method definitions, C<< $self >> and C<< $class >> are available.
C<< $next >> is also defined which contains a coderef for the next method
to call. This may be the original method itself, but it may be another
wrapper.

If no signature is given, C<< $next >> is passed as part of C<< @_ >>
before the invocant.

=head1 KEYWORDS

In this chapter, we looked at the following keywords:

=over

=item C<< before >>

=item C<< after >>

=item C<< around >>

=back

=head1 NEXT STEPS

TODO.

=head1 AUTHOR

Toby Inkster E<lt>tobyink@cpan.orgE<gt>.

=head1 COPYRIGHT AND LICENCE

This software is copyright (c) 2020-2022 by Toby Inkster.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=head1 DISCLAIMER OF WARRANTIES

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

