bumping version and adding changelog
[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
703d9522 46In the first recipe we showed how to build basic Moose classes
47whose attributes had various accessor schemes and built in
48type constraints. However our objects were very data-oriented,
49and did not have many behavioral aspects to them (i.e. - methods).
50In this recipe, we will expand upon the concepts from the first
51recipe and give a more realistic scenario of more behavior
52oriented classes.
53
54We are using an example of a bank account, which has a standard
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
62Now, onto the code. The first class B<BankAccount> introduces a
63new attribute feature, that of a default value.
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
74should be fairly self explanitory, they are nothing specific to
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
81of Moose, that of class based type-constraints.
82
83 has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');
84
85Up until now, we have only had C<Int> type constraints, which
86(as I said in the first recipe) is a built-in type constraint
87that Moose provides for you. The C<BankAccount> type constraint
88is new, and was actually defined at the moment we created the
89B<BankAccount> class itself. In fact, for every Moose class that
90you define, a corresponding type constraint will be created for
91that class. This means that in the first recipe, a C<Point> and
92C<Point3D> type constraint were created, and in this recipe, both
93a C<BankAccount> and a C<CheckingAccount> type constraint were
e08c54f5 94created. Moose does this as a convenience for you so that your
703d9522 95class model and the type constraint model can both be kept in
96sync with one another. In short, Moose makes sure that it will
97just DWIM (1).
98
99Next, we come to the behavioral part of B<CheckingAccount>, and
100again we see a method modifier, but this time we have a C<before>
101modifier.
102
103 before 'withdraw' => sub {
104 my ($self, $amount) = @_;
105 my $overdraft_amount = $amount - $self->balance();
e9bb8a31 106 if ($self->overdraft_account && $overdraft_amount > 0) {
703d9522 107 $self->overdraft_account->withdraw($overdraft_amount);
108 $self->deposit($overdraft_amount);
109 }
110 };
111
112Just as with the C<after> modifier from the first recipe, Moose
113will handle calling the superclass method (in this case the
114C<BankAccount::withdraw> method). The C<before> modifier shown
115above will run (obviously) I<before> the code from the superclass
116with run. The C<before> modifier here implements the overdraft
117protection by first checking if there are enough available
118funds in the checking account and if not (and if there is an overdraft
119account available), it transfers the appropriate funds into the
120checking account.
121
122As with the method modifier in the first recipe, there is another
123way to accomplish this same thing using the built in C<SUPER::>
124pseudo-package. So the above method is equivalent to the one here.
125
126 sub withdraw {
127 my ($self, $amount) = @_;
128 my $overdraft_amount = $amount - $self->balance();
e9bb8a31 129 if ($self->overdraft_account && $overdraft_amount > 0) {
703d9522 130 $self->overdraft_account->withdraw($overdraft_amount);
131 $self->deposit($overdraft_amount);
132 }
133 $self->SUPER::withdraw($amount);
134 }
135
136The benefits of taking the method modifier approach is that the
137author of the B<BankAccount> subclass does not need to remember
138to call C<SUPER::withdraw> and to pass it the C<$amount> argument.
139Instead the method modifier assures that all arguments make it
140to the superclass method correctly. But this is actually more
e08c54f5 141than just a convenience for forgetful programmers, it also helps
703d9522 142isolate subclasses from changes in the superclasses. For instance,
143if B<BankAccount::withdraw> were to add an additional argument
144of some kind, the version of B<CheckingAccount::withdraw> which
145uses C<SUPER::withdraw> would not pass that extra argument
e08c54f5 146correctly. Whereas the method modifier version would automatically pass
147along all arguments correctly.
703d9522 148
149Just as with the first recipe, object instantiation is a fairly
150normal process, here is an example:
151
152 my $savings_account = BankAccount->new(balance => 250);
153 my $checking_account = CheckingAccount->new(
154 balance => 100,
155 overdraft_account => $savings_account
156 );
157
158And as with the first recipe, a more in-depth example of using
db1ab48d 159these classes can be found in the F<t/002_recipe.t> test file.
703d9522 160
161=head1 CONCLUSION
162
163The aim of this recipe was to take the knowledge learned in the
164first recipe and expand upon it within a more realistic use case.
165I hope that this recipe has accomplished this goal. The next
166recipe will expand even more upon the capabilties of attributes
167in Moose to create a behaviorally sophisticated class almost
168entirely defined by attributes.
169
170=head1 FOOTNOTES
171
172=over 4
173
174=item (1)
175
176Moose does not attempt to encode a class's is-a relationships
177within the type constraint hierarchy. Instead Moose just considers
178the class type constraint to be a subtype of C<Object>, and
179specializes the constraint check to allow for subclasses. This
180means that an instance of B<CheckingAccount> will pass a
181C<BankAccount> type constraint successfully. For more details,
182please refer to the L<Moose::Util::TypeConstraints> documentation.
183
184=back
185
186=head1 SEE ALSO
187
188=over 4
189
190=item Acknowledgement
191
192The BankAccount example in this recipe is directly taken from the
193examples in this chapter of "Practical Common Lisp". A link to that
194can be found here:
195
196L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html>
197
198=back
199
471c4f09 200=head1 AUTHOR
201
202Stevan Little E<lt>stevan@iinteractive.comE<gt>
203
204=head1 COPYRIGHT AND LICENSE
205
b77fdbed 206Copyright 2006, 2007 by Infinity Interactive, Inc.
471c4f09 207
208L<http://www.iinteractive.com>
209
210This library is free software; you can redistribute it and/or modify
211it under the same terms as Perl itself.
212
e08c54f5 213=cut