fixed the test for method modifiers
[gitmo/Moose.git] / lib / Moose / Cookbook / Recipe2.pod
CommitLineData
471c4f09 1
2=pod
3
4=head1 NAME
5
3824830b 6Moose::Cookbook::Recipe2 - A simple B<BankAccount> example
471c4f09 7
8=head1 SYNOPSIS
9
10 package BankAccount;
471c4f09 11 use Moose;
12
13 has 'balance' => (isa => 'Int', is => 'rw', default => 0);
14
15 sub deposit {
16 my ($self, $amount) = @_;
17 $self->balance($self->balance + $amount);
18 }
19
20 sub withdraw {
21 my ($self, $amount) = @_;
22 my $current_balance = $self->balance();
23 ($current_balance >= $amount)
24 || confess "Account overdrawn";
25 $self->balance($current_balance - $amount);
26 }
27
28 package CheckingAccount;
471c4f09 29 use Moose;
30
31 extends 'BankAccount';
32
33 has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');
34
35 before 'withdraw' => sub {
cdcae970 36 my ($self, $amount) = @_;
37 my $overdraft_amount = $amount - $self->balance();
e9bb8a31 38 if ($self->overdraft_account && $overdraft_amount > 0) {
cdcae970 39 $self->overdraft_account->withdraw($overdraft_amount);
40 $self->deposit($overdraft_amount);
41 }
471c4f09 42 };
43
44=head1 DESCRIPTION
45
c6182301 46In the first recipe we demonstrated the construction of basic
47Moose classes whose attributes had various accessor schemes and
48builtin type constraints. However, our objects were very data-
49oriented, and did not have many behavioral aspects (i.e. methods)
50to them. In this recipe, we will expand upon the concepts from
51the first recipe and give a more realistic scenario of more
52behavior oriented classes.
53
54We are using the example of a bank account, which has a standard
703d9522 55account (you can deposit money, withdraw money and check your
56current balance), and a checking account which has optional
57overdraft protection. The overdraft protection will protect the
58owner of the checking account by automatically withdrawing the
59needed funds from the overdraft account to ensure that a check
60will not bounce.
61
c6182301 62Now, onto the code. The first class, B<BankAccount>, introduces a
63new attribute feature: a default value.
703d9522 64
65 has 'balance' => (isa => 'Int', is => 'rw', default => 0);
66
e08c54f5 67This tells us that a B<BankAccount> has a C<balance> attribute,
68which has the C<Int> type constraint, a read/write accessor,
703d9522 69and a default value of C<0>. This means that every instance of
e08c54f5 70B<BankAccount> that is created will have its C<balance> slot
703d9522 71initialized to C<0>. Very simple really :)
72
73Next come the methods. The C<deposit> and C<withdraw> methods
c6182301 74should be fairly self-explanatory; they are nothing specific to
703d9522 75Moose, just your standard Perl 5 OO.
76
77Now, onto the B<CheckingAccount> class. As you know from the
78first recipe, the keyword C<extends> sets a class's superclass
79relationship. Here we see that B<CheckingAccount> is a
80B<BankAccount>. The next line introduces yet another new aspect
c6182301 81of Moose, that of class-based type-constraints:
703d9522 82
83 has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');
84
85Up until now, we have only had C<Int> type constraints, which
c6182301 86(as I said in the first recipe) is a builtin type constraint
703d9522 87that Moose provides for you. The C<BankAccount> type constraint
c6182301 88is new, and was actually defined the moment we created the
76c9c428 89B<BankAccount> class itself. In fact, for every class in
90your program, a corresponding type constraint will be created. This
c6182301 91means that in the first recipe, both C<Point> and C<Point3D> type
92constraints were created, and in this recipe, both C<BankAccount>
93and C<CheckingAccount> type constraints were created. Moose does
94this as a convenience so that your class model and the type
95constraint model can be kept in sync with one another. In short,
96Moose makes sure that it will just DWIM (1).
703d9522 97
98Next, we come to the behavioral part of B<CheckingAccount>, and
c6182301 99again we see a method modifier, but this time it is a C<before>
703d9522 100modifier.
101
102 before 'withdraw' => sub {
103 my ($self, $amount) = @_;
104 my $overdraft_amount = $amount - $self->balance();
e9bb8a31 105 if ($self->overdraft_account && $overdraft_amount > 0) {
703d9522 106 $self->overdraft_account->withdraw($overdraft_amount);
107 $self->deposit($overdraft_amount);
108 }
109 };
110
111Just as with the C<after> modifier from the first recipe, Moose
112will handle calling the superclass method (in this case the
113C<BankAccount::withdraw> method). The C<before> modifier shown
114above will run (obviously) I<before> the code from the superclass
115with run. The C<before> modifier here implements the overdraft
116protection by first checking if there are enough available
117funds in the checking account and if not (and if there is an overdraft
118account available), it transfers the appropriate funds into the
119checking account.
120
121As with the method modifier in the first recipe, there is another
122way to accomplish this same thing using the built in C<SUPER::>
123pseudo-package. So the above method is equivalent to the one here.
124
125 sub withdraw {
126 my ($self, $amount) = @_;
127 my $overdraft_amount = $amount - $self->balance();
e9bb8a31 128 if ($self->overdraft_account && $overdraft_amount > 0) {
703d9522 129 $self->overdraft_account->withdraw($overdraft_amount);
130 $self->deposit($overdraft_amount);
131 }
132 $self->SUPER::withdraw($amount);
133 }
134
135The benefits of taking the method modifier approach is that the
136author of the B<BankAccount> subclass does not need to remember
137to call C<SUPER::withdraw> and to pass it the C<$amount> argument.
c6182301 138Instead the method modifier ensures that all arguments make it
703d9522 139to the superclass method correctly. But this is actually more
e08c54f5 140than just a convenience for forgetful programmers, it also helps
703d9522 141isolate subclasses from changes in the superclasses. For instance,
142if B<BankAccount::withdraw> were to add an additional argument
143of some kind, the version of B<CheckingAccount::withdraw> which
144uses C<SUPER::withdraw> would not pass that extra argument
c6182301 145correctly, whereas the method modifier version would automatically
146pass along all arguments correctly.
703d9522 147
148Just as with the first recipe, object instantiation is a fairly
149normal process, here is an example:
150
151 my $savings_account = BankAccount->new(balance => 250);
152 my $checking_account = CheckingAccount->new(
153 balance => 100,
154 overdraft_account => $savings_account
155 );
156
157And as with the first recipe, a more in-depth example of using
aa670b9c 158these classes can be found in the F<t/000_recipes/002_recipe.t> test file.
703d9522 159
160=head1 CONCLUSION
161
c6182301 162The aim of this recipe was to take the knowledge gained in the
163first recipe and expand upon it with a more realistic use case. I
164hope that this recipe has accomplished this goal. The next recipe
165will expand even more upon the capabilities of attributes in Moose
166to create a behaviorally sophisticated class almost entirely
167defined by attributes.
703d9522 168
169=head1 FOOTNOTES
170
171=over 4
172
173=item (1)
174
175Moose does not attempt to encode a class's is-a relationships
c6182301 176within the type constraint hierarchy. Instead, Moose just
177considers the class type constraint to be a subtype of C<Object>,
178and specializes the constraint check to allow for subclasses. This
703d9522 179means that an instance of B<CheckingAccount> will pass a
180C<BankAccount> type constraint successfully. For more details,
181please refer to the L<Moose::Util::TypeConstraints> documentation.
182
183=back
184
185=head1 SEE ALSO
186
187=over 4
188
4711f5f7 189=item Acknowledgment
703d9522 190
191The BankAccount example in this recipe is directly taken from the
c6182301 192examples in this chapter of "Practical Common Lisp":
703d9522 193
194L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html>
195
196=back
197
471c4f09 198=head1 AUTHOR
199
200Stevan Little E<lt>stevan@iinteractive.comE<gt>
201
202=head1 COPYRIGHT AND LICENSE
203
778db3ac 204Copyright 2006-2008 by Infinity Interactive, Inc.
471c4f09 205
206L<http://www.iinteractive.com>
207
208This library is free software; you can redistribute it and/or modify
209it under the same terms as Perl itself.
210
e08c54f5 211=cut