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.

article-2325996-19D4908A000005DC-959_634x501.jpg

Leave a comment

About byterock

user-pic Long time Perl guy, a few CPAN mods allot of work on DBD::Oracle and a few YAPC presentations