The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Moose::Cookbook::Snack::HashRef - Using the HashRef type constraint

SYNOPSIS

    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 );

DESCRIPTION

The HashRef type constraint is used to store a reference to a Perl hash variable as an attribute of a Moose object.

Disclaimer

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.

Assigning hashes to a HashRef attribute

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:

    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:

    $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:

    Attribute (fruit_aisle) does not pass the type constraint (HashRef[Int])

Dumping the contents of the HashRef

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";
    } 

Assigning to a HashRef attribute will overwrite

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 } );

Appending/Deleting key/value pairs to a HashRef

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.

Clearing the HashRef

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.

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( { } );

SEE ALSO

Moose::Cookbook::Snack::Types - Snippets of code for using Types and Type Constraints
Moose::Util::TypeConstraints - Type constraints that Moose can use and the tools to extend them or create your own.
Moose::Autobox - Autoboxed wrappers for Native Perl datatypes
MooseX::AttributeHelpers - Extends attribute interfaces

AUTHOR

Brian Manning <elspicyjack at gmail dot com>

COPYRIGHT AND LICENSE

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.