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 |