X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMooseX%2FStorage%2FEngine.pm;h=50294c294196ec9bca0127a496e7a0e178f7ed80;hb=1390c23dd40f71e312351625cf8b5d2d9a9eefa4;hp=4fd310800bea0dd4eb03769590d3e44df25cb669;hpb=3db8f791960a80cc9fa20b5b558d1dda10191551;p=gitmo%2FMooseX-Storage.git diff --git a/lib/MooseX/Storage/Engine.pm b/lib/MooseX/Storage/Engine.pm index 4fd3108..50294c2 100644 --- a/lib/MooseX/Storage/Engine.pm +++ b/lib/MooseX/Storage/Engine.pm @@ -2,8 +2,20 @@ package MooseX::Storage::Engine; use Moose; +our $VERSION = '0.01'; + +# the class marker when +# serializing an object. +our $CLASS_MARKER = '__CLASS__'; + has 'storage' => ( - is => 'rw', + is => 'ro', + isa => 'HashRef', + default => sub {{}} +); + +has 'seen' => ( + is => 'ro', isa => 'HashRef', default => sub {{}} ); @@ -15,13 +27,23 @@ has 'class' => (is => 'rw', isa => 'Str'); sub collapse_object { my $self = shift; + + # NOTE: + # mark the root object as seen ... + $self->seen->{$self->object} = undef; + $self->map_attributes('collapse_attribute'); - $self->storage->{'__class__'} = $self->object->meta->name; + $self->storage->{$CLASS_MARKER} = $self->object->meta->name; return $self->storage; } sub expand_object { my ($self, $data) = @_; + + # NOTE: + # mark the root object as seen ... + $self->seen->{$data} = undef; + $self->map_attributes('expand_attribute', $data); return $self->storage; } @@ -41,6 +63,14 @@ sub expand_attribute { sub collapse_attribute_value { my ($self, $attr) = @_; my $value = $attr->get_value($self->object); + + # NOTE: + # this might not be enough, we might + # need to make it possible for the + # cycle checker to return the value + $self->check_for_cycle_in_collapse($value) + if ref $value; + if (defined $value && $attr->has_type_constraint) { my $type_converter = $self->find_type_handler($attr->type_constraint); (defined $type_converter) @@ -52,6 +82,12 @@ sub collapse_attribute_value { sub expand_attribute_value { my ($self, $attr, $value) = @_; + + # NOTE: + # (see comment in method above ^^) + $self->check_for_cycle_in_expansion($value) + if ref $value; + if (defined $value && $attr->has_type_constraint) { my $type_converter = $self->find_type_handler($attr->type_constraint); $value = $type_converter->{expand}->($value); @@ -59,12 +95,36 @@ sub expand_attribute_value { return $value; } +# NOTE: +# possibly these two methods will +# be used by a cycle supporting +# engine. However, I am not sure +# if I can make a cycle one work +# anyway. + +sub check_for_cycle_in_collapse { + my ($self, $value) = @_; + (!exists $self->seen->{$value}) + || confess "Basic Engine does not support cycles"; + $self->seen->{$value} = undef; +} + +sub check_for_cycle_in_expansion { + my ($self, $value) = @_; + (!exists $self->seen->{$value}) + || confess "Basic Engine does not support cycles"; + $self->seen->{$value} = undef; +} + # util methods ... sub map_attributes { my ($self, $method_name, @args) = @_; map { $self->$method_name($_, @args) + } grep { + # Skip our special skip attribute :) + !$_->isa('MooseX::Storage::Meta::Attribute::DoNotSerialize') } ($self->object || $self->class)->meta->compute_all_applicable_attributes; } @@ -81,9 +141,9 @@ sub map_attributes { my %OBJECT_HANDLERS = ( expand => sub { my $data = shift; - (exists $data->{'__class__'}) + (exists $data->{$CLASS_MARKER}) || confess "Serialized item has no class marker"; - $data->{'__class__'}->unpack($data); + $data->{$CLASS_MARKER}->unpack($data); }, collapse => sub { my $obj = shift; @@ -115,7 +175,7 @@ my %TYPES = ( my $array = shift; foreach my $i (0 .. $#{$array}) { next unless ref($array->[$i]) eq 'HASH' - && exists $array->[$i]->{'__class__'}; + && exists $array->[$i]->{$CLASS_MARKER}; $array->[$i] = $OBJECT_HANDLERS{expand}->($array->[$i]) } $array; @@ -138,7 +198,7 @@ my %TYPES = ( my $hash = shift; foreach my $k (keys %$hash) { next unless ref($hash->{$k}) eq 'HASH' - && exists $hash->{$k}->{'__class__'}; + && exists $hash->{$k}->{$CLASS_MARKER}; $hash->{$k} = $OBJECT_HANDLERS{expand}->($hash->{$k}) } $hash; @@ -150,7 +210,7 @@ my %TYPES = ( # otherwise it will affect the # other real version. +{ map { - blessed($_) + blessed($hash->{$_}) ? ($_ => $OBJECT_HANDLERS{collapse}->($hash->{$_})) : ($_ => $hash->{$_}) } keys %$hash } @@ -164,7 +224,7 @@ my %TYPES = ( #'CodeRef' => { # expand => sub {}, # use eval ... # collapse => sub {}, # use B::Deparse ... - #} + #} ); sub add_custom_type_handler { @@ -227,12 +287,12 @@ __END__ =head1 NAME -MooseX::Storage::Engine - -=head1 SYNOPSIS +MooseX::Storage::Engine - The meta-engine to handle collapsing and expanding objects =head1 DESCRIPTION +No user serviceable parts inside. If you really want to know, read the source :) + =head1 METHODS =head2 Accessors @@ -245,6 +305,8 @@ MooseX::Storage::Engine =item B +=item B + =back =head2 API @@ -269,6 +331,10 @@ MooseX::Storage::Engine =item B +=item B + +=item B + =item B =back