File Coverage

blib/lib/Object/Realize/Later.pm
Criterion Covered Total %
statement 92 94 97.8
branch 25 36 69.4
condition 10 15 66.6
subroutine 19 20 95.0
pod 2 11 18.1
total 148 176 84.0


line stmt bran cond sub pod time code
1             # Copyrights 2001-2014 by [Mark Overmeer ].
2             # For other contributors see Changes.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.01.
5              
6             package Object::Realize::Later;
7             our $VERSION = '0.19';
8              
9              
10 7     7   156575 use Carp;
  7         21  
  7         625  
11 7     7   44 use Scalar::Util 'weaken';
  7         18  
  7         1019  
12              
13 7     7   43 use warnings;
  7         18  
  7         299  
14 7     7   41 use strict;
  7         15  
  7         285  
15 7     7   33 no strict 'refs';
  7         66  
  7         10928  
16              
17              
18             my $named = 'ORL_realization_method';
19             my $helper = 'ORL_fake_realized';
20              
21              
22             sub init_code($)
23 7     7 0 16 { my $args = shift;
24              
25 7         53 <
26             package $args->{class};
27             require $args->{source_module};
28              
29             my \$$helper = bless {}, '$args->{becomes}';
30             INIT_CODE
31             }
32              
33             sub isa_code($)
34 7     7 0 15 { my $args = shift;
35              
36 7         47 <
37             sub isa(\$)
38             { my (\$thing, \$what) = \@_;
39             return 1 if \$thing->SUPER::isa(\$what); # real dependency?
40             \$$helper\->isa(\$what);
41             }
42             ISA_CODE
43             }
44              
45              
46             sub can_code($)
47 7     7 0 15 { my $args = shift;
48 7         16 my $becomes = $args->{becomes};
49              
50 7         42 <
51             sub can(\$)
52             { my (\$thing, \$method) = \@_;
53             my \$func;
54             \$func = \$thing->SUPER::can(\$method)
55             and return \$func;
56              
57             \$func = \$$helper\->can(\$method)
58             or return;
59              
60             # wrap func() to trigger load if needed.
61             sub { ref \$thing
62             ? \$func->(\$thing->forceRealize, \@_)
63             : \$func->(\$thing, \@_)
64             };
65             }
66             CAN_CODE
67             }
68              
69              
70             sub AUTOLOAD_code($)
71 7     7 0 12 { my $args = shift;
72              
73 7 50       87 <<'CODE1' . ($args->{believe_caller} ? '' : <
74             our $AUTOLOAD;
75             sub AUTOLOAD(@)
76             { my $call = substr $AUTOLOAD, rindex($AUTOLOAD, ':')+1;
77             return if $call eq 'DESTROY';
78             CODE1
79              
80             unless(\$$helper->can(\$call) || \$$helper->can('AUTOLOAD'))
81             { use Carp;
82             croak "Unknown method \$call called";
83             }
84             NOT_BELIEVE
85             # forward as class method if required
86             shift and return $args->{becomes}->\$call( \@_ ) unless ref \$_[0];
87              
88             \$_[0]->forceRealize;
89             my \$made = shift;
90             \$made->\$call(\@_);
91             }
92             CODE2
93             }
94              
95              
96             sub realize_code($)
97 7     7 0 18 { my $args = shift;
98 7         14 my $pkg = __PACKAGE__;
99 7         56 my $argspck= join "'\n , '", %$args;
100              
101 7 100       85 <{warn_realization} ? <<'WARN' : '') .<
102             sub forceRealize(\$)
103             {
104             REALIZE_CODE
105             require Carp;
106             Carp::carp("Realization of $_[0]");
107             WARN
108             ${pkg}->realize
109             ( ref_object => \\\${_[0]}
110             , caller => [ caller 1 ]
111             , '$argspck'
112             );
113             }
114             REALIZE_CODE
115             }
116              
117              
118             sub will_realize_code($)
119 7     7 0 19 { my $args = shift;
120 7         15 my $becomes = $args->{becomes};
121 7         53 <
122             sub willRealize() {'$becomes'}
123             WILL_CODE
124             }
125              
126              
127             sub realize(@)
128 13     13 1 92 { my ($class, %args) = @_;
129 13         19 my $object = ${$args{ref_object}};
  13         30  
130 13         21 my $realize = $args{realize};
131              
132 13         61 my $already = $class->realizationOf($object);
133 13 100 66     66 if(defined $already && ref $already ne ref $object)
134 1 50       5 { if($args{warn_realize_again})
135 1         1 { my (undef, $filename, $line) = @{$args{caller}};
  1         3  
136 1         5 warn "Attempt to realize object again: old reference caught at $filename line $line.\n"
137             }
138              
139 1         6 return ${$args{ref_object}} = $already;
  1         47  
140             }
141              
142 12 50       83 my $loaded = ref $realize ? $realize->($object) : $object->$realize;
143              
144 12 50       123 warn "Load produces a ".ref($loaded)
145             . " where a $args{becomes} is expected.\n"
146             unless $loaded->isa($args{becomes});
147              
148 12         21 ${$args{ref_object}} = $loaded;
  12         24  
149 12         37 $class->realizationOf($object, $loaded);
150             }
151              
152              
153             my %realization;
154              
155             sub realizationOf($;$)
156 25     25 1 43 { my ($class, $object) = (shift, shift);
157 25         63 my $unique = "$object";
158              
159 25 100       115 if(@_)
160 12         904 { $realization{$unique} = shift;
161 12         50 weaken $realization{$unique};
162             }
163              
164 25         470 $realization{$unique};
165             }
166              
167              
168             sub import(@)
169 7     7   106 { my ($class, %args) = @_;
170              
171 7 50       43 confess "Require 'becomes'" unless $args{becomes};
172 7 50       24 confess "Require 'realize'" unless $args{realize};
173              
174 7         28 $args{class} = caller;
175 7   100     42 $args{warn_realization} ||= 0;
176 7   100     29 $args{warn_realize_again} ||= 0;
177 7   66     52 $args{source_module} ||= $args{becomes};
178              
179             # A reference to code will stringify at the eval below. To solve
180             # this, it is tranformed into a call to a named subroutine.
181 7 100       85 if(ref $args{realize} eq 'CODE')
182 2         6 { my $named_method = "$args{class}::$named";
183 2         5 *{$named_method} = $args{realize};
  2         10  
184 2         6 $args{realize} = $named_method;
185             }
186              
187             # Produce the code
188              
189 7         19 my $args = \%args;
190 7         25 my $eval
191             = init_code($args)
192             . isa_code($args)
193             . can_code($args)
194             . AUTOLOAD_code($args)
195             . realize_code($args)
196             . will_realize_code($args)
197             ;
198             #warn $eval;
199              
200             # Install the code
201              
202 7 50 33 7 0 60 eval $eval;
  7 50 50 12 0 13  
  7 100   0 0 3991  
  7 0   27   12331  
  12 100   13   9044  
  12 100   15   47  
  12 100       101  
  0         0  
  12         89  
  11         42  
  11         46  
  11         73  
  0         0  
  27         4619  
  27         54  
  27         298  
  19         329  
  6         52  
  13         632  
  12         304  
  12         857  
  15         275  
  15         129  
  9         70  
203 7 50       42 die $@ if $@;
204              
205 7         653 1;
206             }
207              
208              
209             1;