NAME
MooseX::Attribute::Deflator - Deflate and inflate Moose attribute values
VERSION
version 2.2.1
SYNOPSIS
package MySynopsis;
use Moose;
use DateTime;
use MooseX::Attribute::Deflator;
deflate 'DateTime',
via { $_->epoch },
inline_as { '$value->epoch' }; # optional
inflate 'DateTime',
via { DateTime->from_epoch( epoch => $_ ) },
inline_as { 'DateTime->from_epoch( epoch => $value )' }; # optional
no MooseX::Attribute::Deflator;
# import default deflators and inflators for Moose types
use MooseX::Attribute::Deflator::Moose;
has now => ( is => 'rw',
isa => 'DateTime',
default => sub { DateTime->now },
traits => ['Deflator'] );
has hash => ( is => 'rw',
isa => 'HashRef',
default => sub { { foo => 'bar' } },
traits => ['Deflator'] );
package main;
use Test::More;
my $obj = MySynopsis->new;
{
my $attr = $obj->meta->get_attribute('now');
my $deflated = $attr->deflate($obj);
like($deflated, qr/^\d+$/);
my $inflated = $attr->inflate($obj, $deflated);
isa_ok($inflated, 'DateTime');
}
{
my $attr = $obj->meta->get_attribute('hash');
my $deflated = $attr->deflate($obj);
is($deflated, '{"foo":"bar"}');
my $inflated = $attr->inflate($obj, $deflated);
is_deeply($inflated, {foo => 'bar'})
}
done_testing;
DESCRIPTION
This module consists of a a registry (MooseX::Attribute::Deflator::Registry) an attribute trait MooseX::Attribute::Deflator::Meta::Role::Attribute and predefined deflators and inflators for Moose MooseX::Attribute::Deflator::Moose and MooseX::Types::Strutured MooseX::Attribute::Deflator::Structured. This class is just sugar to set the inflators and deflators.
You can deflate to whatever data structure you want. Loading MooseX::Attribute::Deflator::Moose will cause HashRefs and ArrayRefs to be encoded as JSON strings. However, you can simply overwrite those deflators (and inflators) to deflate to something different like Storable.
Unlike coerce
, you don't need to create a deflator and inflator for every type. Instead this module will bubble up the type hierarchy and use the first deflator or inflator it finds.
This comes at a cost: Union types are not supported.
For extra speed, inflators and deflators can be inlined. All in/deflators that come with this module have an inlined version as well. Whenever you implment custom type in/deflators, you should consider writing the inlining code as well. The performance boost is immense. You can check whether an deflator has been inlined by calling:
$attr->is_deflator_inlined;
Inlining works in Moose >= 1.9 only.
FUNCTIONS
- deflate
- inflate
-
deflate 'DateTime', via { $_->epoch }, inline_as { '$value->epoch' }; # optional inflate 'DateTime', via { DateTime->from_epoch( epoch => $_ ) }, inline_as { 'DateTime->from_epoch( epoch => $value )' }; # optional
Defines a deflator or inflator for a given type constraint. This can also be a type constraint defined via MooseX::Types and parameterized types.
The function supplied to
via
is called with$_
set to the attribute's value and with the following arguments:$attr
-
The attribute on which this deflator/inflator has been called
$constraint
-
The type constraint attached to the attribute
$deflate/$inflate
-
A code reference to the deflate or inflate function. E.g. this is handy if you want to call the type's parent's parent inflate or deflate method:
deflate 'MySubSubType', via { my ($attr, $constraint, $deflate) = @_; return $deflate->($_, $constraint->parent->parent); };
$instance
-
The object instance on which this deflator/inflator has been called.
@_
-
Any other arguments added to "inflate" in MooseX::Attribute::Deflator::Meta::Role::Attribute or "deflate" in MooseX::Attribute::Deflator::Meta::Role::Attribute.
For
inline
, the parameters are handled a bit differently. The code generating subroutine is called with the following parameters:$constraint
-
The type constraint attached to the attribute.
$attr
-
The attribute on which this deflator/inflator has been called.
$registry
-
my $parent = $registry->($constraint->parent); my $code = $parent->($constraint->parent, $attr, $registry, @_);
To get the code generator of a type constraint, call this function.
The
inline
function is expected to return a string. The generated code has access to a number of variables:$value
-
Most important, the value that should be de- or inflated is stored in
$value
. $type_constraint
For some more advanced examples, have a look at the source of MooseX::Attribute::Deflator::Moose and MooseX::Attribute::Deflator::Structured.
DEFLATE AN OBJECT INSTANCE
Usually, you want to deflate certain attributes of a class, but this module only works on a per attribute basis. In order to deflate an instance with all of its attributes, you can use the following code:
sub deflate {
my $self = shift;
# you probably want to deflate only those that are required or have a value
my @attributes = grep { $_->has_value($self) || $_->is_required }
$self->meta->get_all_attributes;
# works only if all attributes have the 'Deflator' trait applied
return { map { $_->name => $_->deflate($self) } @attributes };
}
If you are using MooseX::Attribute::LazyInflator, throw in a call to "is_inflated" in MooseX::Attribute::LazyInflator::Meta::Role::Attribute to make sure that you don't deflate an already deflated attribute. Instead, you can just use "get_raw_value" in Moose::Meta::Attribute to get the deflated value.
PERFORMANCE
The overhead for having custom deflators or inflators per attribute is minimal. The file benchmark.pl
tests three ways of deflating the value of a HashRef attribute to a json encoded string (using JSON).
my $obj = MyBenchmark->new( hashref => { foo => 'bar' } );
my $attr = MyBenchmark->meta->get_attribute('hashref');
- deflate
-
$attr->deflate($obj);
Using the deflate attribute method, supplied by this module.
- accessor
-
JSON::encode_json($obj->hashref);
If the attribute comes with an accessor, you can use this method, to deflate its value. However, you need to know the name of the accessor in order to use this method.
- get_value
-
JSON::encode_json($attr->get_value($obj, 'hashref'));
This solves the mentioned problem with not knowing the accessor name.
The results clearly states that using the deflate
method adds only minimal overhead to deflating the attribute value manually.
Rate get_value deflate accessor
get_value 69832/s -- -87% -88%
deflate 543478/s 678% -- -4%
accessor 564972/s 709% 4% --
AUTHOR
Moritz Onken
COPYRIGHT AND LICENSE
This software is Copyright (c) 2012 by Moritz Onken.
This is free software, licensed under:
The (three-clause) BSD License