- initial commit of new snacks (short documents) for ArrayRef's, HashRef's and
[gitmo/Moose.git] / lib / Moose / Cookbook / Snack / HashRef.pod
1 #!/usr/bin/env perl
2 =pod
3
4 =head1 NAME
5
6 Moose::Cookbook::Snack::HashRef - (Ab)using the HashRef type constraint
7 provided by the L<Moose::Util::TypeConstraint> and/or 
8 L<Moose::Util::TypeConstraints::OptimizedConstraints> classes.
9
10 =head1 SYNOPSIS
11
12     package Fruit;
13     use Moose;
14
15     has q(species) => ( is => q(rw), required => 1 );
16
17     package ProduceStoreHash;
18     use Moose;
19     use Moose::Util::TypeConstraints;
20
21     has q(fruit_aisle) => ( is => q(rw), isa => q(HashRef[Fruit]) );
22
23     sub show_inventory {
24         my $self = shift;
25         foreach my $item ( keys(%{$self->fruit_aisle}) ) {
26             my $fruit = $self->{fruit_aisle}{$item};
27             print qq(Item: $item, type: ) . blessed($fruit)
28                 . q( species: ) . $fruit->species . qq(\n);
29         } # foreach my $item
30     } # sub show_inventory
31
32     package main;
33     use Moose;
34
35     # we need something to put in the fruit aisle
36     my $orange = Fruit->new( species => q(C. sinensis) );
37     my $apple = Fruit->new( species => q(M. domestica) );
38     my %fruit = ( orange => $orange, apple => $apple );
39     my $store = ProduceStoreHash->new( fruit_aisle => \%fruit );
40     print qq(First inventory:\n);
41     $store->show_inventory;
42
43     # this replaces the existing HashRef contents
44     my $grape = Fruit->new( species => q(V. vinifera) );
45     my $tomato = Fruit->new( species => q(S. lycopersicum));
46     $store->fruit_aisle( { grape => $grape, tomato => $tomato } );
47     print qq(Second inventory:\n);
48     $store->show_inventory;
49
50     # this clears the HashRef
51     $store->fruit_aisle( { } );
52     print qq(Third inventory:\n);
53     $store->show_inventory;
54
55 =head1 DESCRIPTION
56
57 The HashRef type constraint is used to store a reference to a Perl hash
58 variable as an attribute of a Moose object.
59
60 =head2 Assigning hashes to a HashRef attribute
61
62 Once a Moose-based object with a C<HashRef> attribute has been created, you
63 can pass a hash (by reference) to that attribute using that attribute's
64 accessor.  This is how we assign the apple and orange to the store's
65 C<fruit_aisle> C<HashRef> attribute, we pass a hash containing both objects by
66 reference to the C<fruit_aisle> attribute:
67
68     my %fruit = ( orange => $orange, apple => $apple );
69     my $store = ProduceStoreHash->new( fruit_aisle => \%fruit );
70
71 Or you can pass an anonymous hash to the C<HashRef> attribute as well.
72 This is shown in the example when the grape and tomato replace the apple
73 and the orange in the store's fruit aisle.
74
75     $store->fruit_aisle( { grape => $grape, tomato => $tomato } );
76
77 Our C<fruit_aisle> C<HashRef> example is parameterized, meaning, that the
78 C<fruit_aisle> C<HashRef> can contain nothing but C<Fruit> objects as hash
79 values.  If you try to pass in a reference to a hash using C<Int> objects as
80 hash values for example, Moose will complain:
81
82     Attribute (fruit_aisle) does not pass the type constraint (HashRef[Int])
83
84 =head2 Assigning to a HashRef attribute will overwrite
85
86 Once you create an object containing a C<HashRef> attribute, if you assign a
87 new hash reference to that attribute, it will replace any existing hash
88 reference:
89
90     print qq(First inventory:\n);
91     $store->show_inventory;
92     # First inventory:
93     # Item: apple, type: Fruit species: M. domestica
94     # Item: orange, type: Fruit species: C. sinensis
95
96
97     # this replaces the existing HashRef contents
98     my $grape = Fruit->new( species => q(V. vinifera) );
99     my $tomato = Fruit->new( species => q(S. lycopersicum));
100     $store->fruit_aisle( { grape => $grape, tomato => $tomato } );
101
102     print qq(Second inventory:\n);
103     $store->show_inventory;
104     # Second inventory:
105     # Item: tomato, type: Fruit species: S. lycopersicum
106     # Item: grape, type: Fruit species: V. vinifera
107
108 =head2 Dumping the contents of the HashRef
109
110 In order to dump the contents of a C<HashRef> object attribute, you must first
111 de-reference the C<HashRef>, and then enumerate over it's keys.  
112
113     foreach my $item ( keys(%{$self->fruit_aisle}) ) {
114         my $fruit = $self->{fruit_aisle}{$item};
115         print qq(Item: $item, type: ) . blessed($fruit)
116             . q( species: ) . $fruit->species . qq(\n);
117     } # foreach my $item
118
119 If the above de-referencing of the C<fruit_aisle> C<HashRef> is a little too
120 noisy, you could create a copy of it, and then enumerate over that copy:
121
122     my %fruit_aisle_copy = %{$self->fruit_aisle};
123     foreach my $item ( keys(%fruit_aisle_copy) ) {
124         my $fruit = $fruit_aisle_copy{$item};
125         # 'print' statement from above example goes here
126     } 
127
128 =head2 Appending/Deleting key/value pairs to a HashRef
129
130 In order to append or delete key/value pairs to the hash referred to by the
131 C<HashRef> attribute, you will need to make a copy of the hash first, add or
132 delete the desired key/value pairs, then assign your modified copy back to the
133 C<HashRef> attribute.  Here's an example of appending new key/value pars:
134
135     my %fruit_aisle_copy = %{$store->fruit_aisle};
136     my $avocado = Fruit->new( species => q(P. americana) );
137     $fruit_aisle_copy{avocado} = $avocado;
138     $store->fruit_aisle( \%fruit_aisle_copy );
139
140 And here's an example of deleting existing key/value pairs:
141
142     # delete an attribute from the HashRef
143     %fruit_aisle_copy = %{$store->fruit_aisle};
144     delete($fruit_aisle_copy{tomato});
145     $store->fruit_aisle( \%fruit_aisle_copy );
146
147 Putting the above code into their own object methods would make appending to
148 and deleting from a C<HashRef> a trivial operation.
149
150 =head2 Clearing the HashRef
151
152 Assigning C<undef> to clear a C<HashRef> will not work because the attribute
153 was originally defined with a type constraint, meaning that attribute must have
154 0 or more of that type of value to be valid.  B<undef> in Perl is not a value,
155 so it won't work for clearing the C<HashRef>.
156
157 If you assign an empty anonymous hash to a C<HashRef> attribute, this will
158 clear out that attribute yet still satisfy the type constraint.
159
160     # this clears the HashRef
161     $store->fruit_aisle( { } );
162
163 =head1 SEE ALSO
164
165 =over 4
166
167 =item L<Moose::Cookbook::Snack::Types> - Snippets of code for using Types and
168 Type Constraints
169
170 =item L<Moose::Util::TypeConstraints> - Type constraints system for Moose
171
172 =back
173
174 =head1 AUTHOR
175
176 Brian Manning <elspicyjack at gmail dot com>
177
178 =head1 COPYRIGHT AND LICENSE
179
180 Copyright (c)2008 by Brian Manning
181
182 This documentation is free software; you can redistribute it and/or modify
183 it under the same terms as Perl itself.
184
185 =cut