File Coverage

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


line stmt bran cond sub pod time code
1             # This code is part of Perl distribution Object-Realize-Later version 4.00.
2             # The POD got stripped from this file by OODoc version 3.05.
3             # For contributors see file ChangeLog.
4              
5             # This software is copyright (c) 2001-2025 by Mark Overmeer.
6              
7             # This is free software; you can redistribute it and/or modify it under
8             # the same terms as the Perl 5 programming language system itself.
9             # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
10              
11              
12             package Object::Realize::Later;{
13             our $VERSION = '4.00';
14             }
15              
16              
17 7     7   206100 use Log::Report 'object-release-later';
  7         1245298  
  7         43  
18              
19 7     7   2789 use Scalar::Util qw/weaken/;
  7         32  
  7         412  
20              
21 7     7   47 use warnings;
  7         19  
  7         400  
22 7     7   44 use strict;
  7         20  
  7         209  
23 7     7   37 no strict 'refs';
  7         16  
  7         8816  
24              
25             #--------------------
26              
27             #------------
28              
29             my $named = 'ORL_realization_method';
30             my $helper = 'ORL_fake_realized';
31              
32              
33             sub init_code($)
34 7     7 0 15 { my $args = shift;
35              
36 7         42 <
37             package $args->{class};
38             require $args->{source_module};
39              
40             my \$$helper = bless {}, '$args->{becomes}';
41             INIT_CODE
42             }
43              
44             sub isa_code($)
45 7     7 0 14 { my $args = shift;
46              
47 7         27 <
48             sub isa(\$)
49             { my (\$thing, \$what) = \@_;
50             return 1 if \$thing->SUPER::isa(\$what); # real dependency?
51             \$$helper\->isa(\$what);
52             }
53             ISA_CODE
54             }
55              
56              
57             sub can_code($)
58 7     7 0 13 { my $args = shift;
59 7         19 my $becomes = $args->{becomes};
60              
61 7         29 <
62             sub can(\$)
63             { my (\$thing, \$method) = \@_;
64             my \$func;
65             \$func = \$thing->SUPER::can(\$method)
66             and return \$func;
67              
68             \$func = \$$helper\->can(\$method)
69             or return;
70              
71             # wrap func() to trigger load if needed.
72             sub { ref \$thing
73             ? \$func->(\$thing->forceRealize, \@_)
74             : \$func->(\$thing, \@_)
75             };
76             }
77             CAN_CODE
78             }
79              
80              
81             sub AUTOLOAD_code($)
82 7     7 0 20 { my $args = shift;
83              
84 7 50       56 <<'CODE1' . ($args->{believe_caller} ? '' : <
85             our $AUTOLOAD;
86             sub AUTOLOAD(@)
87             { my $call = substr $AUTOLOAD, rindex($AUTOLOAD, ':')+1;
88             return if $call eq 'DESTROY';
89             CODE1
90              
91             unless(\$$helper->can(\$call) || \$$helper->can('AUTOLOAD'))
92             { use Carp;
93             croak "Unknown method \$call called";
94             }
95             NOT_BELIEVE
96             # forward as class method if required
97             shift and return $args->{becomes}->\$call( \@_ ) unless ref \$_[0];
98              
99             \$_[0]->forceRealize;
100             my \$made = shift;
101             \$made->\$call(\@_);
102             }
103             CODE2
104             }
105              
106              
107             sub realize_code($)
108 7     7 0 27 { my $args = shift;
109 7         15 my $pkg = __PACKAGE__;
110 7         68 my $argspck = join "'\n , '", %$args;
111              
112 7 100       74 <{warn_realization} ? <<'WARN' : '') . <
113             sub forceRealize(\$)
114             {
115             REALIZE_CODE
116             require Carp;
117             Carp::carp("Realization of $_[0]");
118             WARN
119             ${pkg}->realize(
120             ref_object => \\\${_[0]},
121             caller => [ caller 1 ],
122             '$argspck'
123             );
124             }
125             REALIZE_CODE
126             }
127              
128              
129             sub will_realize_code($)
130 7     7 0 31 { my $args = shift;
131 7         17 my $becomes = $args->{becomes};
132 7         28 <
133             sub willRealize() {'$becomes'}
134             WILL_CODE
135             }
136              
137             #--------------------
138              
139             sub realize(@)
140 13     13 1 106 { my ($class, %args) = @_;
141 13         26 my $object = ${$args{ref_object}};
  13         43  
142 13         31 my $realize = $args{realize};
143              
144 13         48 my $already = $class->realizationOf($object);
145 13 100 66     74 if(defined $already && ref $already ne ref $object)
146 1 50       5 { if($args{warn_realize_again})
147 1         2 { my (undef, $filename, $line) = @{$args{caller}};
  1         22  
148 1         14 warn "Attempt to realize object again: old reference caught at $filename line $line.\n"
149             }
150              
151 1         8 return ${$args{ref_object}} = $already;
  1         43  
152             }
153              
154 12 50       79 my $loaded = ref $realize ? $realize->($object) : $object->$realize;
155              
156             $loaded->isa($args{becomes})
157 12 50       116 or warn "Load produces a ".ref($loaded) . " where a $args{becomes} is expected.\n";
158              
159 12         26 ${$args{ref_object}} = $loaded;
  12         36  
160 12         134 $class->realizationOf($object, $loaded);
161             }
162              
163              
164             my %realization;
165              
166             sub realizationOf($;$)
167 25     25 1 95 { my ($class, $object) = (shift, shift);
168 25         105 my $unique = "$object";
169              
170 25 100       176 if(@_)
171 12         37 { $realization{$unique} = shift;
172 12         31 weaken $realization{$unique};
173             }
174              
175 25         547 $realization{$unique};
176             }
177              
178              
179             sub import(@)
180 7     7   134 { my ($class, %args) = @_;
181              
182 7 50       62 $args{becomes} or panic "import requires 'becomes'";
183 7 50       26 $args{realize} or panic "import requires 'realize'";
184              
185 7         27 $args{class} = caller;
186 7   100     34 $args{warn_realization} ||= 0;
187 7   100     25 $args{warn_realize_again} ||= 0;
188 7   66     53 $args{source_module} ||= $args{becomes};
189              
190             # A reference to code will stringify at the eval below. To solve
191             # this, it is tranformed into a call to a named subroutine.
192 7 100       28 if(ref $args{realize} eq 'CODE')
193 2         5 { my $named_method = "$args{class}::$named";
194 2         4 *{$named_method} = $args{realize};
  2         15  
195 2         7 $args{realize} = $named_method;
196             }
197              
198             # Produce the code
199              
200 7         16 my $args = \%args;
201 7         30 my $eval
202             = init_code($args)
203             . isa_code($args)
204             . can_code($args)
205             . AUTOLOAD_code($args)
206             . realize_code($args)
207             . will_realize_code($args);
208             #warn $eval;
209              
210             # Install the code
211              
212 7 100 33 7 0 63 eval $eval;
  7 50 50 22 0 16  
  7 100   0 0 2182  
  7 0   27   2912  
  22 100   13   928225  
  22 100   15   308  
  12 100       3866  
  0         0  
  12         72  
  11         56  
  11         59  
  11         134  
  0         0  
  27         218048  
  27         57  
  27         243  
  19         621  
  6         40  
  13         330563  
  12         305  
  12         654  
  15         223641  
  15         109  
  9         60  
213 7 50       36 panic $@ if $@;
214              
215 7         602 1;
216             }
217              
218             #--------------------
219              
220             1;