Moose::Cookbook::Snack::HashRef - Using the HashRef type constraint
package Fruit; use Moose; has 'species' => ( is => 'rw', required => 1 ); package ProduceStore; use Moose; use Moose::Util::TypeConstraints; has 'fruit_aisle' => ( is => 'rw', isa => 'HashRef[Fruit]' ); package main; use Moose; # we need something to put in the fruit aisle my $orange = Fruit->new( species => 'C. sinensis' ); my $apple = Fruit->new( species => 'M. domestica' ); my %fruit = ( orange => $orange, apple => $apple ); my $store = ProduceStore->new( fruit_aisle => \%fruit );
The HashRef type constraint is used to store a reference to a Perl hash variable as an attribute of a Moose object.
The code in this document will work on Moose as advertised, but the developers strongly recommend using something like Moose::Autobox or MooseX::AttributeHelpers when working with hash references in order to help keep your Moose objects nice and encapsulated. The reason why this POD exists is to show potential users of Moose that Moose objects are just like Plain Ol' Perl Objects (POPO), albeit with some extra metadata syntatic sugar.
Once a Moose-based object with a HashRef attribute has been created, you can pass a hash (by reference) to that attribute using that attribute's accessor. This is how we assign the apple and orange to the store's fruit_aisle HashRef attribute, we pass a hash containing both objects by reference to the fruit_aisle attribute:
HashRef
fruit_aisle
my %fruit = ( orange => $orange, apple => $apple ); my $store = ProduceStore->new( fruit_aisle => \%fruit );
Or you can pass an anonymous hash to the HashRef attribute as well. If you created two new objects, $grape and $tomato, and assigned them to the HashRef, they would replace the apple and the orange in the store's fruit aisle:
$grape
$tomato
$store->fruit_aisle( { grape => $grape, tomato => $tomato } );
Our fruit_aisle HashRef example is parameterized, meaning, that the fruit_aisle HashRef can contain nothing but Fruit objects as hash values. If you try to pass in a reference to a hash using Int objects as hash values for example, Moose will complain:
Fruit
Int
Attribute (fruit_aisle) does not pass the type constraint (HashRef[Int])
In order to dump the contents of a HashRef object attribute, you must first de-reference the HashRef, and then enumerate over it's keys.
foreach my $item ( keys(%{$self->fruit_aisle}) ) { my $fruit = $self->{fruit_aisle}{$item}; print "Item: $item, type: " . $fruit->meta->name . " species: " . $fruit->species . "\n"; }
If the above de-referencing of the fruit_aisle HashRef is a little too noisy, you could create a copy of it, and then enumerate over that copy:
my %fruit_aisle_copy = %{$self->fruit_aisle}; foreach my $item ( keys(%fruit_aisle_copy) ) { my $fruit = $fruit_aisle_copy{$item}; print "Item: $item, type: " . $fruit->meta->name . " species: " . $fruit->species . "\n"; }
Once you create an object containing a HashRef attribute, if you assign a new hash reference to that attribute, it will replace any existing hash reference:
# this replaces the existing HashRef contents my $grape = Fruit->new( species => 'V. vinifera' ); my $tomato = Fruit->new( species => 'S. lycopersicum'); $store->fruit_aisle( { grape => $grape, tomato => $tomato } );
In order to append or delete key/value pairs to the hash referred to by the HashRef attribute, you will need to make a copy of the hash first, add or delete the desired key/value pairs, then assign your modified copy back to the HashRef attribute. Here's an example of appending new key/value pars:
my %fruit_aisle_copy = %{$store->fruit_aisle}; my $avocado = Fruit->new( species => 'P. americana' ); $fruit_aisle_copy{avocado} = $avocado; $store->fruit_aisle( \%fruit_aisle_copy ); $store->fruit_aisle->{avocado};
And here's an example of deleting existing key/value pairs:
# delete an attribute from the HashRef %fruit_aisle_copy = %{$store->fruit_aisle}; delete($fruit_aisle_copy{tomato}); $store->fruit_aisle( \%fruit_aisle_copy ); delete $mooseObj->hashref->{foo};
Putting the above code into their own object methods would make appending to and deleting from a HashRef a trivial operation.
Assigning undef to clear a HashRef will not work because the attribute was originally defined with a type constraint, meaning that attribute must have 0 or more of that type of value to be valid. undef in Perl is not a value, so it won't work for clearing the HashRef.
undef
If you assign an empty anonymous hash to a HashRef attribute, this will clear out that attribute yet still satisfy the type constraint.
# this clears the HashRef $store->fruit_aisle( { } );
Brian Manning <elspicyjack at gmail dot com>
Copyright 2006-2008 by Infinity Interactive, Inc.
http://www.iinteractive.com
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Moose, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Moose
CPAN shell
perl -MCPAN -e shell install Moose
For more information on module installation, please visit the detailed CPAN module installation guide.