File Coverage

blib/lib/Pixie/Proxy.pm
Criterion Covered Total %
statement 33 190 17.3
branch 0 52 0.0
condition 0 18 0.0
subroutine 11 43 25.5
pod 0 7 0.0
total 44 310 14.1


line stmt bran cond sub pod time code
1             package Pixie::Proxy;
2              
3 16     16   112 use strict;
  16         36  
  16         536  
4 16     16   116 use warnings::register;
  16         33  
  16         2788  
5             require overload;
6              
7             # For now we're going to assume that we can only handle hashes or
8             # array based objects. This may not remain the case.
9              
10              
11 16     16   85 use Scalar::Util qw/reftype/;
  16         29  
  16         2328  
12              
13             our $AUTOLOAD;
14              
15             our $VERSION="2.06";
16              
17 16     16   9387 use Pixie::Object;
  16         35  
  16         460  
18 16     16   9131 use Pixie::FinalMethods;
  16         49  
  16         474  
19 16     16   11444 use Pixie::Complicity;
  16         42  
  16         494  
20 16     16   95 use base 'Pixie::Object';
  16         34  
  16         16958  
21              
22             sub px_make_proxy {
23 0     0 0   my $self = shift;
24 0           my($oid, $obj) = @_;
25 0           my $proxied_class = ref($obj);
26 0           my $real_class = 'Pixie::Proxy::' . reftype($obj);
27              
28 0 0         $real_class .= '::Overloaded' if overload::Overloaded($proxied_class);
29 0           $real_class->new->_oid($oid)
30             ->px_class($proxied_class);
31             }
32              
33             sub px_restore {
34 0     0 0   my $class = $_[0]->px_class;
35 0           my $pixie = $_[0]->px_the_store;
36 0           $_[0]->px_clear_the_store;
37 0           my $real_obj = $_[0]->px_fetch_from($pixie);
38 0 0         return $_[0] = undef unless defined $real_obj;
39 0           $_[0]->populate_from($real_obj);
40 0           bless $real_obj, 'Class::Whitehole';
41 0           my $ret = bless $_[0], $class;
42             }
43              
44             sub px_fetch_from {
45 0     0 0   my $self = shift;
46 0           my $pixie = shift;
47              
48 0           my $oid = $self->_oid;
49              
50 0           $pixie->get_with_strategy($oid, $self->px_lock_strategy);
51             }
52              
53             sub isa {
54 0     0 0   my $self = shift;
55 0           my($class) = @_;
56 0 0 0       $self->UNIVERSAL::isa($class) || ref($self) && $self->px_class->isa($class);
57             }
58              
59             sub can {
60 0     0 0   my $self = shift;
61 0           my($method) = @_;
62              
63 0 0 0       $self->UNIVERSAL::can($method) ||
64             ref($self) && $self->px_restore->can($method);
65             }
66              
67              
68             sub STORABLE_freeze {
69 0     0 0   my $self = shift;
70 0           my $cloning = shift;
71 0 0         return if $cloning;
72              
73 0           return $self->_oid, [$self->px_class];
74             }
75              
76             sub STORABLE_thaw {
77 0     0 0   my($target, $cloning, $oid, $class) = @_;
78 0 0         return if $cloning;
79 0           $target->_oid($oid);
80 0           $target->px_class($class->[0]);
81 0           return $target;
82             }
83              
84             sub _px_insertion_thaw {
85 0     0     my $self = shift;
86 0           $self->px_the_store(Pixie->get_the_current_pixie);
87 0           return $self;
88             }
89              
90             sub _px_insertion_freeze {
91 0     0     my $self = shift;
92 0           my $dupe = ref($self)->new->_oid($self->_oid)
93             ->px_class($self->px_class);
94             }
95              
96              
97              
98             sub _px_extraction_thaw {
99 0     0     my $self = shift;
100 0           my $pixie = Pixie->get_the_current_pixie($self->_oid);
101 0           my $ret = Pixie->get_the_current_pixie->cache_get($self->_oid);
102 0 0         if ( defined $ret ) {
103 0           bless $self, 'Class::Whitehole';
104 0           $pixie->forget_about($self);
105 0           return $ret;
106             }
107              
108 0   0       $self->px_lock_strategy( $pixie->get_the_current_lock_strategy ||
109             $pixie->lock_strategy );
110              
111              
112 0 0         if ($self->px_class->px_is_immediate) {
113 0           my $oid = $self->_oid;
114 0           bless $self, 'Class::Whitehole';
115 0           Pixie->get_the_current_pixie->_get($oid);
116             }
117             else {
118 0           $self->px_the_store($pixie);
119 0           $pixie->cache_insert($self);
120 0           return $self;
121             }
122             }
123              
124             sub DESTROY {
125 0     0     my $self = shift;
126 0           local $@ = $@;
127 0 0         return unless ref $self;
128 0           my $store = $self->px_the_store;
129 0 0         if (defined $store) {
130 0           $store->forget_about($self);
131             }
132             }
133              
134             sub AUTOLOAD {
135 0     0     my $method = $AUTOLOAD;
136 0           $method =~ s/.*:://;
137 0           $_[0]->px_restore->$method(@_[1..$#_]);
138             }
139              
140             package Pixie::Proxy::ARRAY;
141              
142 16     16   109 use base 'Pixie::Proxy';
  16         28  
  16         6450  
143              
144             sub new {
145 0     0     my $proto = shift;
146 0           return bless [], $proto;
147             }
148              
149             sub _oid {
150 0     0     my $self = shift;
151 0 0         if (@_) {
152 0           my $new_oid = shift;
153 0           $self->[0] = "$new_oid";
154 0           return $self;
155             } else {
156 0           return $self->[0];
157             }
158             }
159              
160             sub px_class {
161 0     0     my $self = shift;
162 0 0         if (@_) {
163 0           $self->[1] = shift;
164 0           return $self;
165             } else {
166 0           return $self->[1];
167             }
168             }
169              
170             sub populate_from {
171 0     0     $#{$_[0]} = 0;
  0            
172 0           @{$_[0]} = @{$_[1]};
  0            
  0            
173 0           return $_[0];
174             }
175              
176             sub px_the_store {
177 0     0     my $self = shift;
178 0 0         if (@_) {
179 0           $self->[2] = shift;
180 0           return $self;
181             }
182             else {
183 0           return $self->[2];
184             }
185             }
186              
187             sub px_clear_the_store {
188 0     0     my $self = shift;
189 0           $self->[2] = undef;
190 0           return $self;
191             }
192              
193             sub px_lock_strategy {
194 0     0     my $self = shift;
195 0 0         if (@_) {
196 0           $self->[3] = shift;
197 0           return $self;
198             }
199             else {
200 0           return $self->[3];
201             }
202             }
203              
204              
205             package Pixie::Proxy::HASH;
206              
207 16     16   90 use base 'Pixie::Proxy';
  16         36  
  16         8635  
208              
209             sub new {
210 0     0     my $proto = shift;
211              
212 0           return bless {}, $proto;
213             }
214              
215             sub _oid {
216 0     0     my $self = shift;
217 0 0         if (@_) {
218 0           my $new_oid = shift;
219 0           $self->{oid} = "$new_oid";
220 0           return $self;
221             } else {
222 0           return $self->{oid};
223             }
224             }
225              
226              
227 0     0     sub px_oid { $_[0]->_oid }
228              
229             sub px_class {
230 0     0     my $self = shift;
231              
232 0 0         if (@_) {
233 0           $self->{class} = shift;
234 0           return $self;
235             } else {
236 0 0         unless (ref($self)) {
237 0           require Carp;
238 0           Carp::confess "Invalid thing: $self";
239             }
240 0           return $self->{class};
241             }
242             }
243              
244             sub populate_from {
245 0     0     foreach my $key (keys %{$_[0]}) {
  0            
246 0           delete $_[0]->{$key};
247             }
248 0           %{$_[0]} = %{$_[1]};
  0            
  0            
249 0           return $_[0];
250             }
251              
252             sub px_the_store {
253 0     0     my $self = shift;
254 0 0         if (@_) {
255 0           $self->{_the_store} = shift;
256 0           return $self;
257             }
258             else {
259 0           return $self->{_the_store};
260             }
261             }
262              
263             sub px_clear_the_store {
264 0     0     my $self = shift;
265 0           delete $self->{_the_store};
266             }
267              
268             sub px_lock_strategy {
269 0     0     my $self = shift;
270 0 0         if (@_) {
271 0           $self->{_lock_strategy} = shift;
272 0           return $self;
273             }
274             else {
275 0           return $self->{_lock_strategy};
276             }
277             }
278              
279             package Pixie::Proxy::Overloaded;
280              
281             my %FALLBACK = ( '!' => \&bool_not,
282             '.' => \&concat_str,
283             '""' => \&stringify,
284             'bool' => \&bool,
285             );
286              
287              
288              
289             use overload
290             fallback => 0,
291             nomethod => sub {
292 16     16   99 no strict 'refs';
  16         26  
  16         4166  
293 0     0     my $method = pop;
294 0           my $class = $_[0]->px_class;
295 0           my $fb = $ {$class . "::()"};
  0            
296 0 0 0       if ( my $sub = overload::ov_method( overload::mycan($class, "\($method"), $class) ) {
    0          
    0          
297 0           $_[0]->px_restore;
298 0           &$sub;
299             }
300 0           elsif (!defined($fb) || $fb) {
301             # Try falling back
302 0           push @_, $fb;
303 0 0         if (exists $FALLBACK{$method}) {
304 0           goto &{$FALLBACK{$method}}
  0            
305             }
306             else {
307 0           die "No Fallback found for $method";
308             }
309             }
310             elsif (defined $ {$class . "::()"}) {
311 0           $_[0]->can('nomethod')->(@_, $method);
312             }
313             else {
314 0           require Carp;
315 0           Carp::confess "Can't find overloaded method for $method";
316             }
317 16     16   22814 };
  16         14596  
  16         182  
318              
319             sub bool_not {
320 0 0 0 0     if ( caller->isa('Pixie::Proxy') || caller->isa('Pixie') ) {
321 0           return;
322             }
323             else {
324 0           $_[0]->px_restore;
325 0           return ! $_[0];
326             }
327             }
328              
329             sub bool {
330 0 0 0 0     if ( caller->isa('Pixie::Proxy') || caller->isa('Pixie') ) {
331 0           return 1;
332             }
333             else {
334 0           $_[0]->px_restore;
335 0           return $_[0];
336             }
337             }
338              
339             sub concat_str {
340 0     0     my($target, $rev) = @_[1,2];
341 0 0         return $rev ? ($target . "$_[0]") : ("$_[0]" . $target);
342             }
343              
344             sub stringify {
345 0     0     $_[0]->overload::StrVal;
346             }
347              
348             package Pixie::Proxy::HASH::Overloaded;
349             our @ISA = qw/Pixie::Proxy::HASH Pixie::Proxy::Overloaded/;
350              
351             package Pixie::Proxy::ARRAY::Overloaded;
352             our @ISA = qw/Pixie::Proxy::ARRAY Pixie::Proxy::Overloaded/;
353             1;