I frequently use Moose
to make sure my data have suitable default values, like here:
package Bla;
use Moose;
has eins => is => 'ro', isa => 'Int';
has zwei => is => 'ro', isa => 'Int', default => 2;
no Moose; __PACKAGE__->meta->make_immutable;
package main;
use v5.10;
use Data::Dumper;
use URI;
my $bla = Bla->new( eins => 77 );
my $bl2 = Bla->new;
print Dumper $bla, $bl2;
say join "\t", %$bla;
say join "\t", %$bl2;
my $u = URI->new( 'http://www.example.com/ws' );
$u->query_form( %$bla );
say $u;
$u->query_form( %$bl2 );
say $u;
As long as that kind of data container doesn't have any reference members (hence no nesting), would you say it is okay, or recommendable, to just use the object hashtable as in %$object
if you want to get at the raw data, let's say as initializer for serialization via URI->query_form
or similar methods? Or is there a better way to achieve this that's built into Moose?
UPDATE
Looks like I've been leading people on the wrong tracks by dropping the little word serialization in the lines above, and in the title, and even in the tags. Note that I'm not interested in finding serializers. In my example, the URI
module is the serializer. The question is how to get at the data to feed URI->query_form
(or any other serializer I might try). So what I want to know is whether for a given Moose object $object
it is okay to grab the data (keys and values, or, if you prefer, property names and values) by just dereferencing the object reference, as in %$object
? This will work, if my experience hitherto collected is anything to go by, as long as the objects don't contain any reference values (like array references, other objects, etc) and - the thing I'm not sure about - Moose won't use the instance reference to store data of its own, like __MOOSE_WHATNOT => $funky_moose_addon
. So might Moose use the instance reference to store some of its own data, or is that precluded by design?
UPDATE 2
To answer the question in the title:
No, it's not okay to use %$object
to get at the data of a Moose object, even if it doesn't contain any reference values so you'd get a copy of the strings and numbers that make up the $object
. It's not okay because it breaks encapsulation. It might even result in a runtime error because although the hash is the default data structure to form the base of a Moose object, there is no guarantee that it will always be a hash, and it might in fact be something else.
You should use MooseX::Storage
instead, which will provide the object with a pack
method.
As jira has said the canonical way would be to use MooseX::Storage
. The problem with %$object is that while the default storage for a Moose object instance is a blessed hash, Moose makes no formal promises that this is always the case. MooseX::GlobRef, MooseX::NonMoose, MooseX::InsideOut for example all allow for alterative instance structures.
A package like MooseX::Storage uses the MOP to interrogate the instance meta-object and serialize the data structure properly. You can of course do this by hand by crawling the Moose::Meta::Class that is behind every Moose object, but honestly MooseX::Storage
is well written and very stable at this point.
The standard usage would be:
package Class {
use Moose;
use MooseX::Storage;
with Storage();
...
}
my $o = Class->new(...)
my $u = URI->new( 'http://www.example.com/ws' );
$u->query_form( $o->pack );
Moose "native" way would be to use MooseX::Storage set of classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With