File Coverage

blib/lib/MooseX/Storage.pm
Criterion Covered Total %
statement 50 50 100.0
branch 12 14 85.7
condition 5 8 62.5
subroutine 10 10 100.0
pod n/a
total 77 82 93.9


line stmt bran cond sub pod time code
1             package MooseX::Storage; # git description: v0.49-9-gee3daf7
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.50';
6              
7 32     32   14721946 use Moose 0.99;
  32         432406  
  32         217  
8 32     32   201302 use MooseX::Storage::Meta::Attribute::DoNotSerialize;
  32         102  
  32         1123  
9 32     32   20949 use String::RewritePrefix ();
  32         29594  
  32         673  
10 32     32   466 use Module::Runtime 'use_module';
  32         57  
  32         245  
11 32     32   1280 use Carp 'confess';
  32         113  
  32         1697  
12 32     32   156 use namespace::autoclean;
  32         57  
  32         189  
13              
14             sub import {
15 41     41   57530 my $pkg = caller();
16              
17 41 100       202 return if $pkg eq 'main';
18              
19 40 50       483 ($pkg->can('meta'))
20             || confess "This package can only be used in Moose based classes";
21              
22 40         191 $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 75     75   159 my ($self, $base, $string) = @_;
29              
30 75         926 my $role_name = scalar String::RewritePrefix->rewrite(
31             {
32             '' => "MooseX::Storage::$base\::",
33             '=' => '',
34             },
35             $string,
36             );
37             }
38              
39             sub _expand_role {
40 124     124   313 my ($self, $base, $value) = @_;
41              
42 124 100       394 return unless defined $value;
43              
44 75 100       295 if (ref $value) {
45 3 50       11 confess "too many args in arrayref role declaration" if @$value > 2;
46 3         8 my ($class, $param) = @$value;
47              
48 3         11 $class = $self->_rewrite_role_name($base => $class);
49 3         179 use_module($class);
50              
51 3         111 my $role = $class->meta->generate_role(parameters => $param);
52              
53 3         15348 $HORRIBLE_GC_AVOIDANCE_HACK{ $role->name } = $role;
54 3         16 return $role->name;
55             } else {
56 72         308 my $class = $self->_rewrite_role_name($base, $value);
57 72         4586 use_module($class);
58              
59 72 100 66     1133 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         258 my $role = $class->meta->generate_role(parameters => undef);
64 1         4817 $HORRIBLE_GC_AVOIDANCE_HACK{ $role->name } = $role;
65 1         8 return $role->name;
66             }
67              
68 71         4567 return $class;
69             }
70             }
71              
72             sub _injected_storage_role_generator {
73 35     35   246012 my %params = @_;
74              
75 35 100       268 $params{base} = '=MooseX::Storage::Basic' unless defined $params{base};
76              
77 35         316 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 35         246 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 35         192 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 35   100     166 for my $trait ( @{ $params{'traits'} ||= [] } ) {
  35         315  
102 2         6 push @roles, __PACKAGE__->_expand_role(Traits => $trait);
103             }
104              
105 35         279 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.50
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 BUGS
370              
371             All complex software has bugs lurking in it, and this module is no
372             exception. If you find a bug please or add the bug to cpan-RT
373             at L<https://rt.cpan.org/Dist/Display.html?Queue=MooseX-Storage>.
374              
375             =head1 AUTHORS
376              
377             =over 4
378              
379             =item *
380              
381             Chris Prather <chris.prather@iinteractive.com>
382              
383             =item *
384              
385             Stevan Little <stevan.little@iinteractive.com>
386              
387             =item *
388              
389             יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>
390              
391             =back
392              
393             =head1 COPYRIGHT AND LICENSE
394              
395             This software is copyright (c) 2007 by Infinity Interactive, Inc..
396              
397             This is free software; you can redistribute it and/or modify it under
398             the same terms as the Perl 5 programming language system itself.
399              
400             =head1 CONTRIBUTORS
401              
402             =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
403              
404             =over 4
405              
406             =item *
407              
408             Karen Etheridge <ether@cpan.org>
409              
410             =item *
411              
412             Tomas Doran <bobtfish@bobtfish.net>
413              
414             =item *
415              
416             Ricardo Signes <rjbs@cpan.org>
417              
418             =item *
419              
420             Chris Prather <chris@prather.org>
421              
422             =item *
423              
424             Jos Boumans <jos@dwim.org>
425              
426             =item *
427              
428             Shawn M Moore <sartak@gmail.com>
429              
430             =item *
431              
432             Jonathan Yu <frequency@cpan.org>
433              
434             =item *
435              
436             Dagfinn Ilmari MannsÃ¥ker <ilmari@ilmari.org>
437              
438             =item *
439              
440             Dmitry Latin <dim0xff@gmail.com>
441              
442             =item *
443              
444             Cory Watson <gphat@Crankwizzah.local>
445              
446             =item *
447              
448             Robert Boone <robo4288@gmail.com>
449              
450             =item *
451              
452             sillitoe <ian@sillit.com>
453              
454             =item *
455              
456             Dan Brook <dan@broquaint.com>
457              
458             =item *
459              
460             David Golden <dagolden@cpan.org>
461              
462             =item *
463              
464             David Steinbrunner <dsteinbrunner@pobox.com>
465              
466             =item *
467              
468             Florian Ragwitz <rafl@debian.org>
469              
470             =item *
471              
472             Jason Pope <cowholio4@gmail.com>
473              
474             =item *
475              
476             Johannes Plunien <plu@pqpq.de>
477              
478             =item *
479              
480             Jonathan Rockway <jon@jrock.us>
481              
482             =back
483              
484             =cut