One more little Moose Trick
Well had another good day with Moose as I solved a little problem I was having when trying to write a serializer for my AD&D Character class.
Well the gist of it is I was starting to set up a little JSON web service nothing fancy just give the current character values when requested. Of course creating JSON is easy just express what you want as a hash ref and then use good old JSON::to_json to make it into a JSON string.
Well that was simple enough but then I ran into the problem that I did not always want all of the class to be sent down the pipe I just wanted the current Character Attribute levels not all the tombstone and historic data unless I asked for them.
Well I started out with a silly thing looking like this;
sub as_hash {
my $self = shift;
return {Character=>{Strength =>$self->strength,
...
}}
}
Well yes that approach works but it rather time consuming and boring to hand make the hash-ref in this way.
Well I though there must be a better way and there is thanks to 'MooseX::MetaDescription' and its underlings there is. You may remember this post where I used a 'trait' (a role by another name) to record the change history of an attribute for me.
So what I did was to use the 'MooseX::MetaDescription::Meta::Attribute' and add in a 'description' trait to each of my attributes that I can use to identify what type of attribute it is. For example if I go back to my old standby 'strength' I added this
has 'strength' =>(
is =>'rw',
isa =>'Int',
default=>0,
traits =>['MooseX::MetaDescription::Meta::Trait'],
description => {
serialize => 'tombstone',
},
);
I did the same to the other 'tombstone' values so now I have a way to identify them when I am going to convert them to a hash. So this opens up yet another possibility
where I can take advantage of Moose's built in meta data and create a very generic routine I could use almost anywhere. Like this
sub as_hash {
use Data::Dumper;
my $self = shift;
my ($serialize_on) = @_;
my $return_hash;
my @attributes = $self->meta->get_attribute_list();
foreach my $attr (@attributes){
my $field = $self->meta->get_attribute($attr);
next
unless ($field->does("MooseX::MetaDescription::Meta::Trait"));
next
unless ($field->description->{serialize} eq $serialize_on );
my $value = $self->$attr();
$return_hash->{$attr}=$value;
}
return $return_hash;
}
And that works out fine. Well what did I do in the above? Well I first get all the names of the Moose attributes of the present class with the "$self->meta->get_attribute_list()" and then simply iterate over them and with the ' $self->meta->get_attribute($attr)' I get the 'class' of the attribute in question. I then first check to see if it 'does' the 'MetaDescription' trait I am interested in, this way I quickly ignore any attributes that will not be serialized and I do not get any unwanted errors when I try to call the 'description' method on an attribute that may not have it.
Next I check if this attribute's 'description->{serialize}' matches the one I am searching for and if it does I just add that as a key value pair to my return hash.
This is just so useful. I am really saving myself allot of typing with this little one and my code seem so squeaky clean.
Leave a comment