File Coverage

blib/lib/MooseX/Storage.pm
Criterion Covered Total %
statement 50 50 100.0
branch 11 14 78.5
condition 5 8 62.5
subroutine 10 10 100.0
pod n/a
total 76 82 92.6


line stmt bran cond sub pod time code
1             package MooseX::Storage; # git description: v0.51-5-gd63087b
2             # ABSTRACT: A serialization framework for Moose classes
3             # KEYWORDS: moose extension serial serialization class object store storage types strings
4              
5             our $VERSION = '0.52';
6              
7 31     31   12295178 use Moose 0.99;
  31         387048  
  31         170  
8 31     31   155711 use MooseX::Storage::Meta::Attribute::DoNotSerialize;
  31         87  
  31         1171  
9 31     31   14386 use String::RewritePrefix ();
  31         26028  
  31         629  
10 31     31   411 use Module::Runtime 'use_module';
  31         36  
  31         208  
11 31     31   1239 use Carp 'confess';
  31         40  
  31         1623  
12 31     31   136 use namespace::autoclean;
  31         39  
  31         172  
13              
14             sub import {
15 40     40   52678 my $pkg = caller();
16              
17 40 100       157 return if $pkg eq 'main';
18              
19 39 50       470 ($pkg->can('meta'))
20             || confess "This package can only be used in Moose based classes";
21              
22 39         179 $pkg->meta->add_method('Storage' => __PACKAGE__->meta->find_method_by_name('_injected_storage_role_generator'));
23             }
24              
25             my %HORRIBLE_GC_AVOIDANCE_HACK;
26              
27             sub _rewrite_role_name {
28 73     73   125 my ($self, $base, $string) = @_;
29              
30 73         747 my $role_name = scalar String::RewritePrefix->rewrite(
31             {
32             '' => "MooseX::Storage::$base\::",
33             '=' => '',
34             },
35             $string,
36             );
37             }
38              
39             sub _expand_role {
40 121     121   260 my ($self, $base, $value) = @_;
41              
42 121 100       341 return unless defined $value;
43              
44 73 100       203 if (ref $value) {
45 3 50       12 confess "too many args in arrayref role declaration" if @$value > 2;
46 3         7 my ($class, $param) = @$value;
47              
48 3         10 $class = $self->_rewrite_role_name($base => $class);
49 3         187 use_module($class);
50              
51 3         119 my $role = $class->meta->generate_role(parameters => $param);
52              
53 3         14053 $HORRIBLE_GC_AVOIDANCE_HACK{ $role->name } = $role;
54 3         19 return $role->name;
55             } else {
56 70         216 my $class = $self->_rewrite_role_name($base, $value);
57 70         4020 use_module($class);
58              
59 70 100 66     1103 if ($class->meta->isa('MooseX::Role::Parameterized::Meta::Role::Parameterizable')
      33        
60             or ($class->meta->meta->can('does_role')
61             && $class->meta->meta->does_role('MooseX::Role::Parameterized::Meta::Trait::Parameterizable'))
62             ) {
63 1         207 my $role = $class->meta->generate_role(parameters => undef);
64 1         3639 $HORRIBLE_GC_AVOIDANCE_HACK{ $role->name } = $role;
65 1         8 return $role->name;
66             }
67              
68 69         3727 return $class;
69             }
70             }
71              
72             sub _injected_storage_role_generator {
73 34     34   37734 my %params = @_;
74              
75 34 50       232 $params{base} = '=MooseX::Storage::Basic' unless defined $params{base};
76              
77 34         253 my @roles = __PACKAGE__->_expand_role(Base => $params{base});
78              
79             # NOTE:
80             # you don't have to have a format
81             # role, this just means you don't
82             # get anything other than pack/unpack
83 34         219 push @roles, __PACKAGE__->_expand_role(Format => $params{format});
84              
85             # NOTE:
86             # many IO roles don't make sense unless
87             # you have also have a format role chosen
88             # too, the exception being StorableFile
89             #
90             # NOTE:
91             # we don't need this code anymore, because
92             # the role composition will catch it for
93             # us. This allows the StorableFile to work
94             #(exists $params{'format'})
95             # || confess "You must specify a format role in order to use an IO role";
96 34         185 push @roles, __PACKAGE__->_expand_role(IO => $params{io});
97              
98             # Note:
99             # These traits alter the behaviour of the engine, the user can
100             # specify these per role-usage
101 34   100     136 for my $trait ( @{ $params{'traits'} ||= [] } ) {
  34         275  
102 2         6 push @roles, __PACKAGE__->_expand_role(Traits => $trait);
103             }
104              
105 34         223 return @roles;
106             }
107              
108             1;
109              
110             __END__
111              
112             =pod
113              
114             =encoding UTF-8
115              
116             =head1 NAME
117              
118             MooseX::Storage - A serialization framework for Moose classes
119              
120             =head1 VERSION
121              
122             version 0.52
123              
124             =head1 SYNOPSIS
125              
126             package Point;
127             use Moose;
128             use MooseX::Storage;
129              
130             with Storage('format' => 'JSON', 'io' => 'File');
131              
132             has 'x' => (is => 'rw', isa => 'Int');
133             has 'y' => (is => 'rw', isa => 'Int');
134              
135             1;
136              
137             my $p = Point->new(x => 10, y => 10);
138              
139             ## methods to pack/unpack an
140             ## object in perl data structures
141              
142             # pack the class into a hash
143             $p->pack(); # { __CLASS__ => 'Point-0.01', x => 10, y => 10 }
144              
145             # unpack the hash into a class
146             my $p2 = Point->unpack({ __CLASS__ => 'Point-0.01', x => 10, y => 10 });
147              
148             ## methods to freeze/thaw into
149             ## a specified serialization format
150             ## (in this case JSON)
151              
152             # pack the class into a JSON string
153             $p->freeze(); # { "__CLASS__" : "Point-0.01", "x" : 10, "y" : 10 }
154              
155             # unpack the JSON string into a class
156             my $p2 = Point->thaw('{ "__CLASS__" : "Point-0.01", "x" : 10, "y" : 10 }');
157              
158             ## methods to load/store a class
159             ## on the file system
160              
161             $p->store('my_point.json');
162              
163             my $p2 = Point->load('my_point.json');
164              
165             =head1 DESCRIPTION
166              
167             MooseX::Storage is a serialization framework for Moose, it provides
168             a very flexible and highly pluggable way to serialize Moose classes
169             to a number of different formats and styles.
170              
171             =head2 Levels of Serialization
172              
173             There are three levels to the serialization, each of which builds upon
174             the other and each of which can be customized to the specific needs
175             of your class.
176              
177             =over 4
178              
179             =item B<base>
180              
181             The first (base) level is C<pack> and C<unpack>. In this level the
182             class is serialized into a Perl HASH reference, it is tagged with the
183             class name and each instance attribute is stored. Very simple.
184              
185             This level is not optional, it is the bare minimum that
186             MooseX::Storage provides and all other levels build on top of this.
187              
188             See L<MooseX::Storage::Basic> for the fundamental implementation and
189             options to C<pack> and C<unpack>
190              
191             =item B<format>
192              
193             The second (format) level is C<freeze> and C<thaw>. In this level the
194             output of C<pack> is sent to C<freeze> or the output of C<thaw> is sent
195             to C<unpack>. This levels primary role is to convert to and from the
196             specific serialization format and Perl land.
197              
198             This level is optional, if you don't want/need it, you don't have to
199             have it. You can just use C<pack>/C<unpack> instead.
200              
201             =for stopwords io
202              
203             =item B<io>
204              
205             The third (io) level is C<load> and C<store>. In this level we are reading
206             and writing data to file/network/database/etc.
207              
208             This level is also optional, in most cases it does require a C<format> role
209             to also be used, the exception being the C<StorableFile> role.
210              
211             =back
212              
213             =head2 Behaviour modifiers
214              
215             The serialization behaviour can be changed by supplying C<traits> to either
216             the class or an individual attribute.
217              
218             This can be done as follows:
219              
220             use MooseX::Storage;
221              
222             # adjust behaviour for the entire class
223             with Storage( traits => [Trait1, Trait2,...] );
224              
225             # adjust behaviour for an attribute
226             has my_attr => (
227             traits => [Trait1, Trait2, ...],
228             ...
229             );
230              
231             The following B<class traits> are currently bundled with L<MooseX::Storage>:
232              
233             =over 4
234              
235             =item OnlyWhenBuilt
236              
237             Only attributes that have been built (i.e., where the predicate returns
238             'true') will be serialized. This avoids any potentially expensive computations.
239              
240             See L<MooseX::Storage::Traits::OnlyWhenBuilt> for details.
241              
242             =item DisableCycleDetection
243              
244             =for stopwords serialisable
245              
246             Disables the default checks for circular references, which is necessary if you
247             use such references in your serialisable objects.
248              
249             See L<MooseX::Storage::Traits::DisableCycleDetection> for details.
250              
251             =back
252              
253             The following B<attribute traits> are currently bundled with L<MooseX::Storage>:
254              
255             =over 4
256              
257             =item DoNotSerialize
258              
259             Skip serialization entirely for this attribute.
260              
261             See L<MooseX::Storage::Meta::Attribute::Trait::DoNotSerialize> for details.
262              
263             =back
264              
265             =head2 How we serialize
266              
267             There are always limits to any serialization framework -- there are just
268             some things which are really difficult to serialize properly and some
269             things which cannot be serialized at all.
270              
271             =head2 What can be serialized?
272              
273             Currently only numbers, string, ARRAY refs, HASH refs and other
274             MooseX::Storage-enabled objects are supported.
275              
276             With Array and Hash references the first level down is inspected and
277             any objects found are serialized/deserialized for you. We do not do
278             this recursively by default, however this feature may become an
279             option eventually.
280              
281             =for stopwords subtypes
282              
283             The specific serialize/deserialize routine is determined by the
284             L<Moose> type constraint a specific attribute has. In most cases subtypes
285             of the supported types are handled correctly, and there is a facility
286             for adding handlers for custom types as well. This will get documented
287             eventually, but it is currently still in development.
288              
289             =head2 What can not be serialized?
290              
291             We do not support CODE references yet, but this support might be added
292             in using L<B::Deparse> or some other deep magic.
293              
294             Scalar refs are not supported, mostly because there is no way to know
295             if the value being referenced will be there when the object is inflated.
296             I highly doubt will be ever support this in a general sense, but it
297             would be possible to add this yourself for a small specific case.
298              
299             Circular references are specifically disallowed, however if you break
300             the cycles yourself then re-assemble them later you can get around this.
301             The reason we disallow circular refs is because they are not always supported
302             in all formats we use, and they tend to be very tricky to do for all
303             possible cases. It is almost always something you want to have tight control
304             over anyway.
305              
306             =head1 CAVEAT
307              
308             This is B<not> a persistence framework; changes to your object after
309             you load or store it will not be reflected in the stored class.
310              
311             =head1 EXPORTS
312              
313             =over 4
314              
315             =item B<Storage (%options)>
316              
317             This module will export the C<Storage> method and can be used to
318             load a specific set of MooseX::Storage roles to implement a specific
319             combination of features. It is meant to make things easier, but it
320             is by no means the only way. You can still compose your roles by
321             hand if you like.
322              
323             By default, options are assumed to be short forms. For example, this:
324              
325             Storage(format => 'JSON');
326              
327             ...will result in looking for MooseX::Storage::Format::JSON. To use a role
328             that is not under the default namespace prefix, start with an equal sign:
329              
330             Storage(format => '=My::Private::JSONFormat');
331              
332             =for stopwords parameterized
333              
334             To use a parameterized role (for which, see L<MooseX::Role::Parameterized>) you
335             can pass an arrayref of the role name (in short or long form, as above) and its
336             parameters:
337              
338             Storage(format => [ JSONpm => { json_opts => { pretty => 1 } } ]);
339              
340             =back
341              
342             =head1 METHODS
343              
344             =over 4
345              
346             =item B<import>
347              
348             =back
349              
350             =head2 Introspection
351              
352             =over 4
353              
354             =item B<meta>
355              
356             =back
357              
358             =for stopwords TODO
359              
360             =head1 TODO
361              
362             This module needs docs and probably a Cookbook of some kind as well.
363             This is an early release, so that is my excuse for now :)
364              
365             For the time being, please read the tests and feel free to email me
366             if you have any questions. This module can also be discussed on IRC
367             in the #moose channel on irc.perl.org.
368              
369             =head1 SUPPORT
370              
371             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Storage>
372             (or L<bug-MooseX-Storage@rt.cpan.org|mailto:bug-MooseX-Storage@rt.cpan.org>).
373              
374             There is also a mailing list available for users of this distribution, at
375             L<http://lists.perl.org/list/moose.html>.
376              
377             There is also an irc channel available for users of this distribution, at
378             L<C<#moose> on C<irc.perl.org>|irc://irc.perl.org/#moose>.
379              
380             =head1 AUTHORS
381              
382             =over 4
383              
384             =item *
385              
386             Chris Prather <chris.prather@iinteractive.com>
387              
388             =item *
389              
390             Stevan Little <stevan.little@iinteractive.com>
391              
392             =item *
393              
394             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
395              
396             =back
397              
398             =head1 CONTRIBUTORS
399              
400             =for stopwords Karen Etheridge Tomas Doran Ricardo Signes Chris Prather Jos Boumans Shawn M Moore Jonathan Yu Dagfinn Ilmari MannsÃ¥ker Dmitry Latin Cory Watson Robert Boone sillitoe Dan Brook David Golden Steinbrunner Florian Ragwitz Jason Pope Johannes Plunien Rockway
401              
402             =over 4
403              
404             =item *
405              
406             Karen Etheridge <ether@cpan.org>
407              
408             =item *
409              
410             Tomas Doran <bobtfish@bobtfish.net>
411              
412             =item *
413              
414             Ricardo Signes <rjbs@cpan.org>
415              
416             =item *
417              
418             Chris Prather <chris@prather.org>
419              
420             =item *
421              
422             Jos Boumans <jos@dwim.org>
423              
424             =item *
425              
426             Shawn M Moore <sartak@gmail.com>
427              
428             =item *
429              
430             Jonathan Yu <frequency@cpan.org>
431              
432             =item *
433              
434             Dagfinn Ilmari MannsÃ¥ker <ilmari@ilmari.org>
435              
436             =item *
437              
438             Dmitry Latin <dim0xff@gmail.com>
439              
440             =item *
441              
442             Cory Watson <gphat@Crankwizzah.local>
443              
444             =item *
445              
446             Robert Boone <robo4288@gmail.com>
447              
448             =item *
449              
450             sillitoe <ian@sillit.com>
451              
452             =item *
453              
454             Dan Brook <dan@broquaint.com>
455              
456             =item *
457              
458             David Golden <dagolden@cpan.org>
459              
460             =item *
461              
462             David Steinbrunner <dsteinbrunner@pobox.com>
463              
464             =item *
465              
466             Florian Ragwitz <rafl@debian.org>
467              
468             =item *
469              
470             Jason Pope <cowholio4@gmail.com>
471              
472             =item *
473              
474             Johannes Plunien <plu@pqpq.de>
475              
476             =item *
477              
478             Jonathan Rockway <jon@jrock.us>
479              
480             =back
481              
482             =head1 COPYRIGHT AND LICENSE
483              
484             This software is copyright (c) 2007 by Infinity Interactive, Inc.
485              
486             This is free software; you can redistribute it and/or modify it under
487             the same terms as the Perl 5 programming language system itself.
488              
489             =cut