The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

=pod

=head1 NAME

Moose::Cookbook::Recipe2 - A simple B<BankAccount> example

=head1 SYNOPSIS

  package BankAccount;
  use Moose;
  
  has 'balance' => (isa => 'Int', is => 'rw', default => 0);
  
  sub deposit {
      my ($self, $amount) = @_;
      $self->balance($self->balance + $amount);
  }
  
  sub withdraw {
      my ($self, $amount) = @_;
      my $current_balance = $self->balance();
      ($current_balance >= $amount)
          || confess "Account overdrawn";
      $self->balance($current_balance - $amount);
  }
  
  package CheckingAccount;
  use Moose;
  
  extends 'BankAccount';
  
  has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');	
  
  before 'withdraw' => sub {
      my ($self, $amount) = @_;
      my $overdraft_amount = $amount - $self->balance();
      if ($self->overdraft_account && $overdraft_amount > 0) {
          $self->overdraft_account->withdraw($overdraft_amount);
          $self->deposit($overdraft_amount);
      }
  };

=head1 DESCRIPTION

In the first recipe we demonstrated the construction of basic
Moose classes whose attributes had various accessor schemes and
builtin type constraints. However, our objects were very data-
oriented, and did not have many behavioral aspects (i.e. methods)
to them. In this recipe, we will expand upon the concepts from
the first recipe and give a more realistic scenario of more
behavior oriented classes.  

We are using the example of a bank account, which has a standard 
account (you can deposit money, withdraw money and check your 
current balance), and a checking account which has optional 
overdraft protection. The overdraft protection will protect the 
owner of the checking account by automatically withdrawing the 
needed funds from the overdraft account to ensure that a check 
will not bounce. 

Now, onto the code. The first class, B<BankAccount>, introduces a 
new attribute feature: a default value. 

  has 'balance' => (isa => 'Int', is => 'rw', default => 0);

This tells us that a B<BankAccount> has a C<balance> attribute, 
which has the C<Int> type constraint, a read/write accessor, 
and a default value of C<0>. This means that every instance of 
B<BankAccount> that is created will have its C<balance> slot 
initialized to C<0>. Very simple really :)

Next come the methods. The C<deposit> and C<withdraw> methods 
should be fairly self-explanatory; they are nothing specific to 
Moose, just your standard Perl 5 OO.

Now, onto the B<CheckingAccount> class. As you know from the 
first recipe, the keyword C<extends> sets a class's superclass 
relationship. Here we see that B<CheckingAccount> is a 
B<BankAccount>. The next line introduces yet another new aspect 
of Moose, that of class-based type-constraints:

  has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');

Up until now, we have only had C<Int> type constraints, which 
(as I said in the first recipe) is a builtin type constraint 
that Moose provides for you. The C<BankAccount> type constraint 
is new, and was actually defined the moment we created the 
B<BankAccount> class itself. In fact, for every class in 
your program, a corresponding type constraint will be created. This
means that in the first recipe, both C<Point> and C<Point3D> type
constraints were created, and in this recipe, both C<BankAccount>
and C<CheckingAccount> type constraints were created. Moose does
this as a convenience so that your class model and the type
constraint model can be kept in sync with one another. In short,
Moose makes sure that it will just DWIM (1).

Next, we come to the behavioral part of B<CheckingAccount>, and 
again we see a method modifier, but this time it is a C<before> 
modifier.

  before 'withdraw' => sub {
      my ($self, $amount) = @_;
      my $overdraft_amount = $amount - $self->balance();
      if ($self->overdraft_account && $overdraft_amount > 0) {
          $self->overdraft_account->withdraw($overdraft_amount);
          $self->deposit($overdraft_amount);
      }
  };

Just as with the C<after> modifier from the first recipe, Moose 
will handle calling the superclass method (in this case the 
C<BankAccount::withdraw> method). The C<before> modifier shown 
above will run (obviously) I<before> the code from the superclass 
with run. The C<before> modifier here implements the overdraft 
protection by first checking if there are enough available 
funds in the checking account and if not (and if there is an overdraft 
account available), it transfers the appropriate funds into the 
checking account.

As with the method modifier in the first recipe, there is another 
way to accomplish this same thing using the built in C<SUPER::> 
pseudo-package. So the above method is equivalent to the one here.

  sub withdraw {
      my ($self, $amount) = @_;
      my $overdraft_amount = $amount - $self->balance();
      if ($self->overdraft_account && $overdraft_amount > 0) {
          $self->overdraft_account->withdraw($overdraft_amount);
          $self->deposit($overdraft_amount);
      }
      $self->SUPER::withdraw($amount);
  }

The benefits of taking the method modifier approach is that the 
author of the B<BankAccount> subclass does not need to remember 
to call C<SUPER::withdraw> and to pass it the C<$amount> argument. 
Instead the method modifier ensures that all arguments make it 
to the superclass method correctly. But this is actually more 
than just a convenience for forgetful programmers, it also helps 
isolate subclasses from changes in the superclasses. For instance, 
if B<BankAccount::withdraw> were to add an additional argument 
of some kind, the version of B<CheckingAccount::withdraw> which 
uses C<SUPER::withdraw> would not pass that extra argument 
correctly, whereas the method modifier version would automatically
pass along all arguments correctly.

Just as with the first recipe, object instantiation is a fairly 
normal process, here is an example:
  
  my $savings_account  = BankAccount->new(balance => 250);
  my $checking_account = CheckingAccount->new(
  					         balance => 100,
  					         overdraft_account => $savings_account
  					     );

And as with the first recipe, a more in-depth example of using 
these classes can be found in the F<t/000_recipes/002_recipe.t> test file.

=head1 CONCLUSION

The aim of this recipe was to take the knowledge gained in the 
first recipe and expand upon it with a more realistic use case. I
hope that this recipe has accomplished this goal. The next recipe
will expand even more upon the capabilities of attributes in Moose
to create a behaviorally sophisticated class almost entirely
defined by attributes.

=head1 FOOTNOTES

=over 4

=item (1)

Moose does not attempt to encode a class's is-a relationships 
within the type constraint hierarchy. Instead, Moose just
considers the class type constraint to be a subtype of C<Object>,
and specializes the constraint check to allow for subclasses. This 
means that an instance of B<CheckingAccount> will pass a 
C<BankAccount> type constraint successfully. For more details, 
please refer to the L<Moose::Util::TypeConstraints> documentation.

=back

=head1 SEE ALSO

=over 4

=item Acknowledgment

The BankAccount example in this recipe is directly taken from the 
examples in this chapter of "Practical Common Lisp":

L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html>

=back

=head1 AUTHOR

Stevan Little E<lt>stevan@iinteractive.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright 2006-2008 by Infinity Interactive, Inc.

L<http://www.iinteractive.com>

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

=cut