-
package MooseX::Storage;
use Moose qw(confess);
use MooseX::Storage::Meta::Attribute::DoNotSerialize;
use String::RewritePrefix ();
-our $VERSION = '0.21';
-our $AUTHORITY = 'cpan:STEVAN';
-
sub import {
my $pkg = caller();
$pkg->meta->add_method('Storage' => __PACKAGE__->meta->find_method_by_name('_injected_storage_role_generator'));
}
-sub __expand_role {
- my ($base, $value) = @_;
+my %HORRIBLE_GC_AVOIDANCE_HACK;
+
+sub _rewrite_role_name {
+ my ($self, $base, $string) = @_;
+
+ my $role_name = scalar String::RewritePrefix->rewrite(
+ {
+ '' => "MooseX::Storage::$base\::",
+ '=' => '',
+ },
+ $string,
+ );
+}
+
+sub _expand_role {
+ my ($self, $base, $value) = @_;
return unless defined $value;
if (ref $value) {
- confess "references for roles are not yet handled";
+ confess "too many args in arrayref role declaration" if @$value > 2;
+ my ($class, $param) = @$value;
+
+ $class = $self->_rewrite_role_name($base => $class);
+ Class::MOP::load_class($class);
+
+ my $role = $class->meta->generate_role(parameters => $param);
+
+ $HORRIBLE_GC_AVOIDANCE_HACK{ $role->name } = $role;
+ return $role->name;
} else {
- return scalar String::RewritePrefix->rewrite(
- {
- '' => "MooseX::Storage::$base\::",
- '=' => '',
- },
- $value,
- );
+ my $class = $self->_rewrite_role_name($base, $value);
+ Class::MOP::load_class($class);
+
+ my $role = $class;
+
+ if ($class->meta->isa(
+ 'MooseX::Role::Parameterized::Meta::Role::Parameterizable'
+ )) {
+ $role = $class->meta->generate_role(parameters => undef);
+ $HORRIBLE_GC_AVOIDANCE_HACK{ $role->name } = $role;
+ return $role->name;
+ }
+
+ return $class;
}
}
$params{base} = '=MooseX::Storage::Basic' unless defined $params{base};
- my @roles = __expand_role(Base => $params{base});
+ my @roles = __PACKAGE__->_expand_role(Base => $params{base});
# NOTE:
# you don't have to have a format
# role, this just means you dont
# get anything other than pack/unpack
- push @roles, __expand_role(Format => $params{format});
+ push @roles, __PACKAGE__->_expand_role(Format => $params{format});
# NOTE:
# many IO roles don't make sense unless
# us. This allows the StorableFile to work
#(exists $params{'format'})
# || confess "You must specify a format role in order to use an IO role";
- push @roles, __expand_role(IO => $params{io});
+ push @roles, __PACKAGE__->_expand_role(IO => $params{io});
# Note:
# These traits alter the behaviour of the engine, the user can
# specify these per role-usage
for my $trait ( @{ $params{'traits'} ||= [] } ) {
- push @roles, __expand_role(Traits => $trait);
- }
-
- for my $role ( @roles ) {
- Class::MOP::load_class($role) or die "Could not load role ($role)";
+ push @roles, __PACKAGE__->_expand_role(Traits => $trait);
}
return @roles;
use Moose;
use MooseX::Storage;
- our $VERSION = '0.01';
-
with Storage('format' => 'JSON', 'io' => 'File');
has 'x' => (is => 'rw', isa => 'Int');
class is serialized into a Perl HASH reference, it is tagged with the
class name and each instance attribute is stored. Very simple.
-This level is not optional, it is the bare minumum that
+This level is not optional, it is the bare minimum that
MooseX::Storage provides and all other levels build on top of this.
-See L<Moosex::Storage::Basic> for the fundamental implementation and
+See L<MooseX::Storage::Basic> for the fundamental implementation and
options to C<pack> and C<unpack>
=item B<format>
This level is optional, if you don't want/need it, you don't have to
have it. You can just use C<pack>/C<unpack> instead.
+=for stopwords io
+
=item B<io>
The third (io) level is C<load> and C<store>. In this level we are reading
and writing data to file/network/database/etc.
This level is also optional, in most cases it does require a C<format> role
-to also be used, the expection being the C<StorableFile> role.
+to also be used, the exception being the C<StorableFile> role.
=back
=item OnlyWhenBuilt
-Only attributes that have been built (ie, where the predicate returns
+Only attributes that have been built (i.e., where the predicate returns
'true') will be serialized. This avoids any potentially expensive computations.
See L<MooseX::Storage::Traits::OnlyWhenBuilt> for details.
With Array and Hash references the first level down is inspected and
any objects found are serialized/deserialized for you. We do not do
-this recusively by default, however this feature may become an
+this recursively by default, however this feature may become an
option eventually.
+=for stopwords subtypes
+
The specific serialize/deserialize routine is determined by the
Moose type constraint a specific attribute has. In most cases subtypes
of the supported types are handled correctly, and there is a facility
=head1 CAVEAT
-This is B<not> a persistence framework, changes to your object after
+This is B<not> a persistence framework; changes to your object after
you load or store it will not be reflected in the stored class.
=head1 EXPORTS
=item B<Storage (%options)>
-This module will export the C<Storage> method will can be used to
+This module will export the C<Storage> method and can be used to
load a specific set of MooseX::Storage roles to implement a specific
combination of features. It is meant to make things easier, but it
is by no means the only way. You can still compose your roles by
hand if you like.
+By default, options are assumed to be short forms. For example, this:
+
+ Storage(format => 'JSON');
+
+...will result in looking for MooseX::Storage::Format::JSON. To use a role
+that is not under the default namespace prefix, start with an equal sign:
+
+ Storage(format => '=My::Private::JSONFormat');
+
+=for stopwords parameterized
+
+To use a parameterized role (for which, see L<MooseX::Role::Parameterized>) you
+can pass an arrayref of the role name (in short or long form, as above) and its
+parameters:
+
+ Storage(format => [ JSONpm => { json_opts => { pretty => 1 } } ]);
+
=back
=head1 METHODS
=back
+=for stopwords TODO
+
=head1 TODO
This module needs docs and probably a Cookbook of some kind as well.
it under the same terms as Perl itself.
=cut
+
+