Now, this is still written in MooseX::Declare inspired pseudo-code, so it is not yet a reality, but I am getting more and more convinced that this is something I really need to write. So anyway, here goes.
role COLLAPSER { requires 'pack', 'unpack' }
role FORMATTER { requires 'thaw', 'freeze' }
role IO { requires 'load', 'store' }
role DefaultCollapser with COLLAPSER {
method pack {
Collapser::Engine->new( object => $self )
->collapse_object
}
method unpack ($class:, $data) {
Collapser::Engine->new( class => $class )
->expand_object( $data )
}
}
role JSONFormatter [
Collapser => (does => COLLAPSER)
] with FORMATTER {
method thaw ($class:, $json) {
$class->unpack( JSON::Any->encode( $json ) )
}
method freeze {
JSON::Any->decode( $self->pack )
}
}
role SimpleFile [
Formatter => (does => FORMATTER)
] with IO {
method load ($class:, $filename){
my $fh = IO::File->new( $filename, 'r' );
my $data = do { local $/; <$fh>; };
$class->thaw( $data );
}
method store ($filename) {
my $fh = IO::File->new( $filename, 'w' );
$fh->print( $self->freeze );
}
}
I am obviously punting on a couple of details here to keep things simple for the example, but I think it gets the point across. The nice part, in my opinion, is that the parameterization nicely captures the "levels" of serialization. For instance, here is what a class that does all the options would look like:
class Point
with SimpleFile(
Formatter => JSONFormatter(
Collapser => DefaultCollapser
)
) {
has x => (is => rw, isa => Int, default => 0);
has y => (is => rw, isa => Int, default => 0);
method clear {
$self->x(0);
$self->y(0);
}
}
And here is a class which does not do the load/store but just does the JSON freeze/thaw:
class Point
with JSONFormatter(
Collapser => DefaultCollapser
) {
has x => (is => rw, isa => Int, default => 0);
has y => (is => rw, isa => Int, default => 0);
method clear {
$self->x(0);
$self->y(0);
}
}
And here is a class which does only the simple pack/unpack:
class Point with DefaultCollapser {
has x => (is => rw, isa => Int, default => 0);
has y => (is => rw, isa => Int, default => 0);
method clear {
$self->x(0);
$self->y(0);
}
}
Overall I am quite happy with this, so now it is just a matter of finding the tuits to actually implement it.
No comments:
Post a Comment