Commit | Line | Data |
686a7f09 |
1 | #!/usr/bin/env perl |
2 | =pod |
3 | |
4 | =head1 NAME |
5 | |
6 | Moose::Cookbook::Snack::ArrayRef - (Ab)using the ArrayRef 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 | |
6bf6edf6 |
15 | has 'name' => (is => 'rw', required => 1); |
16 | has 'species' => (is => 'rw', required => 1); |
686a7f09 |
17 | |
18 | package ProduceStoreArray; |
19 | use Moose; |
20 | use Moose::Util::TypeConstraints; |
21 | |
6bf6edf6 |
22 | has 'fruit_aisle' => (isa => 'ArrayRef[Fruit]', is => 'rw'); |
686a7f09 |
23 | |
24 | package main; |
25 | |
26 | # we need something to put in the fruit aisle |
6bf6edf6 |
27 | my $orange = Fruit->new(name => 'orange', species => 'C. sinensis'); |
28 | my $apple = Fruit->new(name => 'apple', species => 'M. domestica'); |
29 | my @fruit = ($apple, $orange); |
fbde43ee |
30 | my $store = ProduceStoreArray->new(fruit_aisle => \@fruit); |
686a7f09 |
31 | |
32 | =head1 DESCRIPTION |
33 | |
34 | The ArrayRef type constraint is used to store a reference to a Perl list or |
35 | array variable as an attribute of a Moose object. |
36 | |
6bf6edf6 |
37 | =head2 Disclaimer |
38 | |
39 | The code in this document will work on Moose as advertised, but the developers |
40 | strongly recommend using something like L<Moose::Autobox> or |
41 | L<MooseX::AttributeHelpers> when working with array references in order to |
42 | help keep your Moose objects nice and encapsulated. |
43 | |
686a7f09 |
44 | =head2 Assigning arrays to an ArrayRef attribute |
45 | |
46 | Once a Moose-based object with an C<ArrayRef> attribute has been created, you |
47 | can pass an array (by reference) to that object attribute using that |
48 | attribute's accessor. This is how we assign the apple and orange to the |
49 | store's C<fruit_aisle> C<ArrayRef> attribute, we pass an array containing both |
50 | objects by reference to the C<fruit_aisle> attribute: |
51 | |
6bf6edf6 |
52 | my @fruit = ($apple, $orange); |
fbde43ee |
53 | my $store = ProduceStoreArray->new(fruit_aisle => \@fruit); |
686a7f09 |
54 | |
6bf6edf6 |
55 | Or you can pass an anonymous array to the C<ArrayRef> attribute as well. If |
56 | you created two new objects, C<$grape> and C<$tomato>, and assigned them to |
57 | the C<ArrayRef>, they would replace the apple and the orange in the store's |
58 | fruit aisle: |
686a7f09 |
59 | |
6bf6edf6 |
60 | $store->fruit_aisle( [$grape, $tomato] ); |
686a7f09 |
61 | |
62 | Our C<fruit_aisle> C<ArrayRef> is parameterized, meaning, that the |
63 | C<fruit_aisle> C<ArrayRef> can contain nothing but C<Fruit> objects as array |
64 | values. If you try to pass in a reference to a array using C<Str> objects as |
65 | array values for example, Moose will complain: |
66 | |
67 | Attribute (fruit_aisle) does not pass the type constraint (ArrayRef[Str]) |
68 | |
69 | =head2 Dumping the contents of an ArrayRef |
70 | |
71 | In order to dump the contents of a C<ArrayRef> object attribute, you must first |
72 | de-reference the C<ArrayRef>, and then enumerate over it's keys. You can add |
73 | this method for showing the store's inventory to the C<ProduceStoreArray> |
74 | object shown in the SYNOPSIS: |
75 | |
76 | sub show_inventory { |
77 | my $self = shift; |
78 | foreach my $item ( @{$self->fruit_aisle} ) { |
79 | # access each Fruit object |
80 | } # foreach my $item ( @{$self->fruit_aisle} ) |
81 | } |
82 | |
83 | =head2 Assigning arrays to an ArrayRef will overwrite existing arrays |
84 | |
85 | Once you create an object containing a C<ArrayRef> attribute, if you assign a |
86 | new array reference to that attribute, it will replace any existing array |
87 | reference: |
88 | |
89 | # replace existing inventory |
6bf6edf6 |
90 | my $grape = Fruit->new(name => 'grape', species => 'V. vinifera'); |
91 | my $tomato = Fruit->new(name => 'tomato', species => 'S. lycopersicum'); |
92 | $store->fruit_aisle( [$grape, $tomato] ); |
686a7f09 |
93 | |
94 | =head2 Appending/Deleting values to/from an ArrayRef |
95 | |
96 | In order to append new elements to an array referred to by the C<ArrayRef> |
97 | attribute, you will need to make a copy of the array first, add your new array |
98 | elements, then assign your modified copy back to the C<ArrayRef> attribute: |
99 | |
100 | my @fruit_aisle_copy = @{$store->fruit_aisle}; |
6bf6edf6 |
101 | my $avocado = Fruit->new(name => 'avocado', species => 'P. americana'); |
686a7f09 |
102 | push(@fruit_aisle_copy, $avocado); |
103 | $store->fruit_aisle( \@fruit_aisle_copy ); |
104 | |
105 | And here's an example of deleting an object stored in an ArrayRef: |
106 | |
107 | my @fruit_aisle_copy = @{$store->fruit_aisle}; |
108 | # new array to hold the fruit objects that won't be deleted |
109 | my @reworked_fruit_aisle; |
110 | for my $fruit_obj ( @fruit_aisle_copy ) { |
6bf6edf6 |
111 | if ( $fruit_obj->name ne 'tomato' ) { |
686a7f09 |
112 | push(@reworked_fruit_aisle, $fruit_obj); |
6bf6edf6 |
113 | } # if ( $fruit_obj->name ne 'tomato' ) |
686a7f09 |
114 | } # for my $fruit_obj ( @fruit_aisle_copy ) |
115 | $store->fruit_aisle( \@reworked_fruit_aisle ); |
116 | |
117 | Putting the above code into their own object methods would make appending to or deleting from an C<ArrayRef> a trivial operation. |
118 | |
119 | =head2 Clearing an ArrayRef |
120 | |
121 | Assigning C<undef> to clear an C<ArrayRef> will not work because the attribute |
122 | was originally defined with a type constraint, meaning that attribute must have |
123 | 0 or more of that type of value to be valid. C<undef> in Perl is not a value, |
124 | so it won't work for clearing the C<ArrayRef>. |
125 | |
126 | If you assign an empty anonymous hash to a C<ArrayRef> attribute, this will |
127 | clear out that attribute yet still satisfy the type constraint. |
128 | |
129 | # this clears the ArrayRef |
130 | $store->fruit_aisle( [ ] ); |
131 | |
132 | =head1 SEE ALSO |
133 | |
134 | =over 4 |
135 | |
136 | =item L<Moose::Cookbook::Recipe4> - Subtypes, and modeling a simple Company |
137 | class hierarchy |
138 | |
139 | =item L<Moose::Cookbook::Snack::Types> - Snippets of code for using Types and |
140 | Type Constraints |
141 | |
142 | =item L<Moose::Util::TypeConstraints> - Type constraints that Moose can use |
143 | |
6bf6edf6 |
144 | =item L<Moose::Autobox> - Autoboxed wrappers for Native Perl datatypes |
145 | |
146 | =item L<MooseX::AttributeHelpers> - Extends attribute interfaces |
147 | |
686a7f09 |
148 | =back |
149 | |
150 | =head1 AUTHOR |
151 | |
152 | Brian Manning <elspicyjack at gmail dot com> |
153 | |
154 | =head1 COPYRIGHT AND LICENSE |
155 | |
6bf6edf6 |
156 | Copyright (c)2008 by Infinity Interactive, Inc., Brian Manning |
686a7f09 |
157 | |
158 | This documentation is free software; you can redistribute it and/or modify |
159 | it under the same terms as Perl itself. |
160 | |
161 | =cut |