File Coverage

blib/lib/KiokuDB/TypeMap/Entry/Callback.pm
Criterion Covered Total %
statement 2 4 50.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 4 6 66.6


line stmt bran cond sub pod time code
1             package KiokuDB::TypeMap::Entry::Callback;
2             BEGIN {
3 2     2   49379 $KiokuDB::TypeMap::Entry::Callback::AUTHORITY = 'cpan:NUFFIN';
4             }
5             $KiokuDB::TypeMap::Entry::Callback::VERSION = '0.57';
6 2     2   3547 use Moose;
  0            
  0            
7             # ABSTRACT: Callback based inflation/deflation of objects
8              
9             no warnings 'recursion';
10              
11             use Carp qw(croak);
12              
13             use namespace::clean -except => 'meta';
14              
15             with qw(KiokuDB::TypeMap::Entry::Std);
16              
17             has [qw(collapse expand)] => (
18             is => "ro",
19             isa => "Str|CodeRef",
20             required => 1,
21             );
22              
23             has [qw(id refresh)] => (
24             is => "ro",
25             isa => "Str|CodeRef",
26             );
27              
28             sub compile_collapse_body {
29             my ( $self, $class, @args ) = @_;
30              
31             my $collapse_object = $self->collapse;
32              
33             return sub {
34             my ( $self, %args ) = @_;
35              
36             my @data = $args{object}->$collapse_object;
37              
38             my $data;
39              
40             if ( @data == 1 and not ref $data[0] ) {
41             $data = $data[0];
42             } else {
43             $data = [ map { $self->visit($_) } @data ];
44             }
45              
46             return $self->make_entry(
47             %args,
48             data => $data,
49             );
50             };
51             }
52              
53             sub _entry_data_to_args {
54             my ( $self, $linker, $entry ) = @_;
55              
56             my $data = $entry->data;
57              
58             if ( ref $data ) {
59             my @args;
60              
61             my $refs = 0;
62              
63             foreach my $value ( @$data ) {
64             if ( ref $value ) {
65             push @args, undef;
66             $linker->inflate_data($value, \$args[-1]);
67             $refs++;
68             } else {
69             push @args, $value;
70             }
71             }
72              
73             $linker->load_queue if $refs; # force @args to be fully vivified
74              
75             return @args;
76             } else {
77             return $data;
78             }
79             }
80              
81             sub compile_expand {
82             my ( $self, $class, @args ) =@_;
83              
84             my $expand_object = $self->expand;
85              
86             return sub {
87             my ( $linker, $entry ) = @_;
88              
89             my @args = $self->_entry_data_to_args($linker, $entry);
90              
91             # does *NOT* support circular refs
92             my $object = $entry->class->$expand_object(@args);
93              
94             $linker->register_object( $entry => $object );
95              
96             return $object;
97             };
98             }
99              
100              
101             sub compile_refresh {
102             my ( $self, $class, @args ) = @_;
103              
104             if ( my $refresh_object = $self->refresh ) {
105             return sub {
106             my ( $linker, $object, $entry ) = @_;
107              
108             my @args = $self->_entry_data_to_args($linker, $entry);
109              
110             $object->$refresh_object(@args);
111              
112             return $object;
113             };
114             } else {
115             return sub {
116             croak "No refresh method provided for $class by typemap entry $self";
117             };
118             }
119             }
120              
121             sub compile_id {
122             my ( $self, $class, @args ) = @_;
123              
124             if ( my $get_id = $self->id ) {
125             return sub {
126             my ( $self, $object ) = @_;
127             $object->$get_id;
128             };
129             } else {
130             return "generate_uuid";
131             }
132             }
133              
134             __PACKAGE__->meta->make_immutable;
135              
136             __PACKAGE__
137              
138             __END__
139              
140             =pod
141              
142             =encoding UTF-8
143              
144             =head1 NAME
145              
146             KiokuDB::TypeMap::Entry::Callback - Callback based inflation/deflation of objects
147              
148             =head1 VERSION
149              
150             version 0.57
151              
152             =head1 SYNOPSIS
153              
154             KiokuDB::TypeMap->new(
155             entries => {
156             'My::Class' => KiokuDB::TypeMap::Entry::Callback->new(
157             expand => "new", # My::Class->new(%$self)
158             collapse => sub {
159             my $self = shift;
160             return %$self; # provide args to 'new' in this example
161             },
162             id => sub { "foo" }, # 'id' callback is optional
163             ),
164             },
165             );
166              
167             =head1 DESCRIPTION
168              
169             This L<KiokuDB::TypeMap> entry provides callback based inflation/deflation.
170              
171             The major limitation of this method is that it cannot be used for self
172             referential structures. This is because the object being inflated is only
173             constructed after all of its arguments are.
174              
175             For the overwhelming majority of the use cases this is good enough though.
176              
177             =head1 ATTRIBUTES
178              
179             =over 4
180              
181             =item collapse
182              
183             A method name or code reference invoked on the object during collapsing.
184              
185             This is evaluated in list context, and the list of values it returns will be
186             collapsed by the L<KiokuDB::Collapser> and then stored.
187              
188             =item expand
189              
190             A method name or code reference invoked on the class of the object during loading.
191              
192             The arguments are as returned by the C<collapse> callback.
193              
194             =item id
195              
196             An optional method name or code reference invoked to get an ID for the object.
197              
198             If one is not provided the default (UUID based) generation is used.
199              
200             =item intrinsic
201              
202             A boolean denoting whether or not the object should be collapsed with no ID,
203             and serialized as part of its parent object.
204              
205             This is useful for value like objects, for whom the reference address makes no
206             difference (such as L<URI> objects).
207              
208             =back
209              
210             =head1 AUTHOR
211              
212             Yuval Kogman <nothingmuch@woobling.org>
213              
214             =head1 COPYRIGHT AND LICENSE
215              
216             This software is copyright (c) 2014 by Yuval Kogman, Infinity Interactive.
217              
218             This is free software; you can redistribute it and/or modify it under
219             the same terms as the Perl 5 programming language system itself.
220              
221             =cut