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