line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Class::LazyObject; |
2
|
6
|
|
|
6
|
|
461996
|
use strict; |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
258
|
|
3
|
6
|
|
|
6
|
|
32
|
use warnings; |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
178
|
|
4
|
|
|
|
|
|
|
|
5
|
6
|
|
|
6
|
|
31
|
use Carp qw(); |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
149
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
BEGIN { |
8
|
6
|
|
|
6
|
|
33
|
use vars '$VERSION'; |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
390
|
|
9
|
6
|
|
|
6
|
|
136
|
$VERSION = '0.10'; |
10
|
|
|
|
|
|
|
} |
11
|
|
|
|
|
|
|
|
12
|
6
|
|
|
6
|
|
32
|
use vars '$AUTOLOAD'; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
409
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
#We want to inflate calls to methods defined in UNIVERSAL, but we implicitly inherit from UNIVERSAL. |
15
|
|
|
|
|
|
|
#As long as we predeclare the methods here, they will override those in UNIVERSAL, but since they are never defined, AUTOLOAD will be called: |
16
|
6
|
|
|
6
|
|
21154
|
use subs grep {defined UNIVERSAL::can(__PACKAGE__, $_)} keys %UNIVERSAL::; |
|
6
|
|
|
|
|
219
|
|
|
6
|
|
|
|
|
29
|
|
|
24
|
|
|
|
|
392
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub AUTOLOAD |
19
|
|
|
|
|
|
|
{ |
20
|
96
|
|
|
96
|
|
58094
|
my $self = $_[0]; #don't shift it, since we will need to access this directly later. |
21
|
|
|
|
|
|
|
|
22
|
96
|
|
|
|
|
533
|
$AUTOLOAD =~ /.*::(\w+)/; |
23
|
96
|
|
|
|
|
192
|
my $method = $1; |
24
|
|
|
|
|
|
|
|
25
|
96
|
|
66
|
|
|
529
|
my $class_method = (ref($self) || $self).'::Methods';#call all class methods on this. |
26
|
|
|
|
|
|
|
|
27
|
96
|
100
|
66
|
|
|
719
|
if (($method eq 'new') && !ref($self)) |
28
|
|
|
|
|
|
|
{ |
29
|
|
|
|
|
|
|
#new was called on a class, rather than an object, so we should actually construct ourselves, rather than passing this to whatever we're proxying. |
30
|
40
|
|
|
|
|
176
|
return $class_method->new(@_); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
56
|
100
|
|
|
|
494
|
ref($self) or return $class_method->$method(@_[ 1 .. $#_ ]); #If this was called as a class method, pass it on to ::Methods but don't pass OUR package name. |
34
|
|
|
|
|
|
|
|
35
|
50
|
50
|
|
|
|
195
|
print "Lazy...\n" if $class_method->get_classdata('debug'); |
36
|
|
|
|
|
|
|
|
37
|
50
|
|
|
|
|
8336
|
my $object; #this is the object we will eventually replace ourselves with. |
38
|
|
|
|
|
|
|
|
39
|
50
|
100
|
66
|
|
|
215
|
if ( ref($$self) && UNIVERSAL::isa($$self, $class_method->get_classdata('class')) ) |
40
|
|
|
|
|
|
|
{ |
41
|
10
|
|
|
|
|
180
|
$object = $$self; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
else |
44
|
|
|
|
|
|
|
{ |
45
|
40
|
|
|
|
|
116
|
$object = $class_method->get_classdata('inflate')->($class_method->get_classdata('class'), $$self); |
46
|
40
|
|
|
|
|
679
|
$$self = $object; #don't create this again. |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
50
|
|
|
|
|
77
|
$_[0] = $object; #replace ourselves with the object. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
goto ( |
52
|
50
|
|
66
|
|
|
2242
|
UNIVERSAL::can($_[0], $method) || |
53
|
|
|
|
|
|
|
$class_method->_prepareAUTOLOADRef($_[0], ref($_[0]).'::'.$method) || #UNIVERSAL::can can't detect if a method is AUTOLOADed, so we have to. |
54
|
|
|
|
|
|
|
Carp::croak(sprintf qq{Can\'t locate object method "%s" via package "%s" }, $method, ref $_[0] )#Error message stolen from Class::WhiteHole |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub DESTROY #You won't AUTOLOAD this! Muahahaha! |
59
|
|
|
|
|
|
|
{ |
60
|
40
|
|
|
40
|
|
4704
|
undef; #This is here because certain perl versions can't handle completely emtpy subs. |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
#class method to see whether something is lazy? |
65
|
|
|
|
|
|
|
#class methods for original isa and can |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
#--------- |
68
|
|
|
|
|
|
|
package Class::LazyObject::Methods; |
69
|
|
|
|
|
|
|
#stick all of our class methods here so we don't pollute Class::LazyObject's namespace. |
70
|
|
|
|
|
|
|
#everything in this class should be called as class methods, NOT object methods. |
71
|
|
|
|
|
|
|
|
72
|
6
|
|
|
6
|
|
13877
|
use Carp::Clan '^Class::LazyObject(::|$)'; |
|
6
|
|
|
|
|
59860
|
|
|
6
|
|
|
|
|
52
|
|
73
|
6
|
|
|
6
|
|
21381
|
use Class::Data::TIN qw(get_classdata); |
|
6
|
|
|
|
|
135900
|
|
|
6
|
|
|
|
|
586
|
|
74
|
6
|
|
|
6
|
|
52348
|
use Class::ISA; |
|
6
|
|
|
|
|
173194
|
|
|
6
|
|
|
|
|
4836
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _findAUTOLOADPackage |
77
|
|
|
|
|
|
|
{ |
78
|
|
|
|
|
|
|
#Takes 1 argument, either an object or the name of a package. |
79
|
|
|
|
|
|
|
#Returns the name of the package containing the sub AUTOLOAD that would be called when $first_arg->AUTOLOAD was called |
80
|
|
|
|
|
|
|
#In other words, it traverses the inheritance hierarchy the same way Perl does until it finds an AUTOLOAD, and returns the name of the package containing the AUTOLOAD. |
81
|
|
|
|
|
|
|
#Returns undef if AUTOLOAD is not in the inheritance hierarchy. |
82
|
|
|
|
|
|
|
|
83
|
16
|
|
|
16
|
|
20
|
shift;#Don't care about our package name. |
84
|
|
|
|
|
|
|
|
85
|
16
|
|
|
|
|
22
|
my $object_or_package = shift; |
86
|
16
|
|
33
|
|
|
49
|
my $orig_class = ref($object_or_package) || $object_or_package; |
87
|
|
|
|
|
|
|
|
88
|
16
|
50
|
|
|
|
70
|
return undef unless UNIVERSAL::can($orig_class, 'AUTOLOAD'); |
89
|
|
|
|
|
|
|
|
90
|
16
|
|
|
|
|
62
|
my @classes = (Class::ISA::self_and_super_path($orig_class), 'UNIVERSAL'); |
91
|
|
|
|
|
|
|
|
92
|
16
|
|
|
|
|
411
|
my $package; |
93
|
16
|
|
|
|
|
227
|
foreach my $class (@classes) |
94
|
|
|
|
|
|
|
{ |
95
|
6
|
|
|
6
|
|
66
|
no strict 'refs';#Symbol table munging ahead |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
798
|
|
96
|
24
|
|
|
|
|
29
|
$package = $class; |
97
|
24
|
100
|
|
|
|
23
|
last if defined(*{$package.'::AUTOLOAD';}{CODE}); |
|
24
|
|
|
|
|
93
|
|
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
16
|
|
|
|
|
40
|
return $package; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub _prepareAUTOLOADRef |
104
|
|
|
|
|
|
|
{ |
105
|
|
|
|
|
|
|
#Takes 2 arguments: |
106
|
|
|
|
|
|
|
# either an object or the name of a package |
107
|
|
|
|
|
|
|
# the fully qualified method name to make AUTOLOAD think it was called as a result of |
108
|
|
|
|
|
|
|
#Sets the appropriate package's $AUTOLOAD so that when the AUTOLOAD method is called on the first argument, it will think it was called as a result of a call to the method specified by the second argument. |
109
|
|
|
|
|
|
|
#Returns the result of (UNIVERSAL::can($first_arg, 'AUTOLOAD')); |
110
|
|
|
|
|
|
|
|
111
|
19
|
|
|
19
|
|
31
|
my $class = shift; |
112
|
|
|
|
|
|
|
|
113
|
19
|
|
|
|
|
38
|
my ($object, $method) = @_; |
114
|
|
|
|
|
|
|
|
115
|
19
|
100
|
|
|
|
79
|
if (UNIVERSAL::can($object, 'AUTOLOAD'))#no point in doing any of this if it can't AUTOLOAD. |
116
|
|
|
|
|
|
|
{ |
117
|
16
|
|
|
|
|
56
|
my $package = $class->_findAUTOLOADPackage($object); |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
{ |
120
|
6
|
|
|
6
|
|
35
|
no strict 'refs'; |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
1743
|
|
|
16
|
|
|
|
|
24
|
|
121
|
16
|
|
|
|
|
20
|
*{$package.'::AUTOLOAD'} = \$method; |
|
16
|
|
|
|
|
48
|
|
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
19
|
|
|
|
|
723
|
return UNIVERSAL::can($object, 'AUTOLOAD'); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
#defaults, these are overridable when someone calls ->inherit |
129
|
|
|
|
|
|
|
Class::Data::TIN->new(__PACKAGE__, |
130
|
|
|
|
|
|
|
inflate => sub {return $_[0]->new_inflate($_[1]);}, |
131
|
|
|
|
|
|
|
debug => 0, |
132
|
|
|
|
|
|
|
); |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub inherit |
135
|
|
|
|
|
|
|
{ |
136
|
|
|
|
|
|
|
#calls to Class::LazyObject->inherit are forwarded here. |
137
|
|
|
|
|
|
|
|
138
|
6
|
|
|
6
|
|
2512
|
my $class = shift; #don't care about our own package name. |
139
|
6
|
|
|
|
|
41
|
my %params = @_; |
140
|
|
|
|
|
|
|
|
141
|
6
|
|
|
|
|
193
|
my @required_params = qw(inflated_class deflated_class); |
142
|
|
|
|
|
|
|
|
143
|
6
|
|
|
|
|
18
|
foreach my $param (@required_params) |
144
|
|
|
|
|
|
|
{ |
145
|
11
|
100
|
|
|
|
55
|
croak "You did not pass '$param', which is a required parameter." unless exists $params{$param}; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
5
|
|
|
|
|
18
|
my %param_map = ( #keys are key names in the parameters passed to this function. Values are corrisponding class data names. |
149
|
|
|
|
|
|
|
inflated_class => 'class' |
150
|
|
|
|
|
|
|
); |
151
|
|
|
|
|
|
|
|
152
|
5
|
|
|
|
|
21
|
my %class_data = %params; |
153
|
5
|
|
|
|
|
20
|
delete @class_data{keys %param_map, 'deflated_class'};#we'll stick these in with their appropriate names: |
154
|
5
|
|
|
|
|
42
|
@class_data{values %param_map} = @params{keys %param_map};#pass the parameters whose names have changed |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
5
|
|
|
|
|
18
|
my $method_package = $params{deflated_class}.'::Methods'; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
{ |
160
|
6
|
|
|
6
|
|
40
|
no strict 'refs'; #more symbol table munging |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
1308
|
|
|
5
|
|
|
|
|
9
|
|
161
|
5
|
|
|
|
|
10
|
push(@{$method_package.'::ISA'}, __PACKAGE__); #Create a package to hold all the methods, that inherits from THIS class, or add this class to its inheritance if it does exist. #Should this be $class instead of __PACKAGE__ |
|
5
|
|
|
|
|
83
|
|
162
|
|
|
|
|
|
|
#^Push is used instead of unshift so that someone can override their ::Methods package with its own inheritence hierarchy, and methods will be called here only AFTER Perl finds they don't exist in the overridden ISA. |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
5
|
|
|
|
|
39
|
Class::Data::TIN->new($method_package, %class_data); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub new |
169
|
|
|
|
|
|
|
{ |
170
|
40
|
|
|
40
|
|
78
|
my ($own_package, $class, $id) = @_;#first argument is this method's, class, not the lazy object's |
171
|
|
|
|
|
|
|
|
172
|
40
|
50
|
33
|
|
|
112
|
if (ref($id) && UNIVERSAL::isa($id, $own_package->get_classdata('class'))) |
173
|
|
|
|
|
|
|
{ |
174
|
0
|
|
|
|
|
0
|
croak "A Lazy Object's ID cannot be a an object of same class (or of a class inherited from the one) it is proxying!"; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
40
|
|
|
|
|
195
|
return bless \$id, $class; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
1; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
#LAUNDRY LIST: |
183
|
|
|
|
|
|
|
#LAZYNESS, impatience, hubris |
184
|
|
|
|
|
|
|
#should we document the $AUTOLOAD persistence thingy as a caveat? |
185
|
|
|
|
|
|
|
#CALLING AUTOLOAD on inflate |
186
|
|
|
|
|
|
|
#CAVEAT: can't distinguish between no id and an id of undef. |
187
|
|
|
|
|
|
|
# -solve by storing a Class::LazyObject::NoID object instead of undef? |
188
|
|
|
|
|
|
|
#Does goto propogate scalar/list context? |
189
|
|
|
|
|
|
|
#Lvalue subs? |
190
|
|
|
|
|
|
|
#PROBLEM: Can't inherit from a lazy object (that has already called inherit) it right now without calling inherit because the corrisponding ::Methods class hasn't been created yet. Instead of being completely nonpolluting, can we create a method with a long convoluted name like __________Class_____LazyObject______Find____Methods and use the NEXT module to make redispatch any calls of it that are object method calls instead of static class calls? |
191
|
|
|
|
|
|
|
#Does ORL's can work correctly for classes that inherit from an unrealized class? |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
__END__ |