line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
20
|
|
|
20
|
|
188529
|
use 5.008; |
|
20
|
|
|
|
|
83
|
|
|
20
|
|
|
|
|
801
|
|
2
|
20
|
|
|
20
|
|
109
|
use strict; |
|
20
|
|
|
|
|
54
|
|
|
20
|
|
|
|
|
657
|
|
3
|
20
|
|
|
20
|
|
107
|
use warnings; |
|
20
|
|
|
|
|
36
|
|
|
20
|
|
|
|
|
1265
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Object::LocalVars; |
6
|
|
|
|
|
|
|
# ABSTRACT: Outside-in objects with local aliasing of $self and object variables |
7
|
|
|
|
|
|
|
our $VERSION = '0.21'; # VERSION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
10
|
|
|
|
|
|
|
# Required modules |
11
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
12
|
|
|
|
|
|
|
|
13
|
20
|
|
|
20
|
|
111
|
use Config; |
|
20
|
|
|
|
|
46
|
|
|
20
|
|
|
|
|
913
|
|
14
|
20
|
|
|
20
|
|
110
|
use Carp; |
|
20
|
|
|
|
|
39
|
|
|
20
|
|
|
|
|
2007
|
|
15
|
20
|
|
|
20
|
|
438
|
use Scalar::Util 1.09 qw( weaken refaddr ); |
|
20
|
|
|
|
|
542
|
|
|
20
|
|
|
|
|
1867
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
18
|
|
|
|
|
|
|
# Exporting -- wrap import so we can check for necessary warnings |
19
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
20
|
|
|
|
|
|
|
|
21
|
20
|
|
|
20
|
|
103
|
use Exporter (); |
|
20
|
|
|
|
|
35
|
|
|
20
|
|
|
|
|
5864
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our @EXPORT = qw( |
24
|
|
|
|
|
|
|
caller give_methods new BUILDALL CLONE DESTROY |
25
|
|
|
|
|
|
|
MODIFY_SCALAR_ATTRIBUTES MODIFY_CODE_ATTRIBUTES |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub import { |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# check if threads are available |
31
|
35
|
50
|
|
35
|
|
21918
|
if( $Config{useithreads} ) { |
32
|
0
|
|
|
|
|
0
|
my $caller = caller(0); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Warn about sharing, but not for Test:: modules which always |
35
|
|
|
|
|
|
|
# share if any threads are enabled |
36
|
0
|
0
|
0
|
|
|
0
|
if ( $INC{'threads/shared.pm'} && ! $INC{'Test/Builder.pm'} ) { |
37
|
0
|
|
|
|
|
0
|
carp "Warning: threads::shared is enabled, but $caller uses" |
38
|
|
|
|
|
|
|
. " Object::LocalVars (which does not allow shared objects)"; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Hand off the rest of the import |
43
|
35
|
|
|
|
|
4667
|
goto &Exporter::import; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
47
|
|
|
|
|
|
|
# Declarations |
48
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my (%public_methods, %protected_methods, %private_methods); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
my %base_class_of; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
my %prefixes_for; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
57
|
|
|
|
|
|
|
# accessor_style |
58
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub accessor_style { |
61
|
5
|
|
|
5
|
1
|
771
|
my (undef, $prefix) = @_; |
62
|
5
|
100
|
|
|
|
50
|
croak "Method accessor_style() requires a hash reference" |
63
|
|
|
|
|
|
|
if not ref $prefix eq 'HASH'; |
64
|
4
|
|
|
|
|
9
|
my $class = caller(0); |
65
|
4
|
|
|
|
|
143
|
$prefixes_for{ $class } = $prefix; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
69
|
|
|
|
|
|
|
# base_object |
70
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub base_object { |
73
|
20
|
|
|
20
|
|
124
|
no strict 'refs'; |
|
20
|
|
|
|
|
56
|
|
|
20
|
|
|
|
|
3568
|
|
74
|
2
|
|
|
2
|
1
|
291
|
my (undef, $base) = @_; |
75
|
2
|
|
|
|
|
5
|
my $class = caller(0); |
76
|
2
|
|
|
|
|
31
|
$base_class_of{ $class } = $base; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# import it if not already in @ISA |
79
|
2
|
100
|
|
|
|
4
|
if ( ! grep { $_ eq $base } @{$class."::ISA"} ) { |
|
1
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
13
|
|
80
|
1
|
|
|
|
|
2
|
push @{$class."::ISA"}, $base; |
|
1
|
|
|
|
|
12
|
|
81
|
1
|
|
|
|
|
6
|
$base =~ s{::}{/}g; |
82
|
1
|
|
|
|
|
2
|
$base .= ".pm"; |
83
|
1
|
|
|
|
|
2
|
eval { require $base }; |
|
1
|
|
|
|
|
778
|
|
84
|
1
|
50
|
|
|
|
353
|
croak $@ if $@ ne ''; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# change to other form of new |
88
|
|
|
|
|
|
|
{ |
89
|
20
|
|
|
20
|
|
119
|
no warnings 'redefine'; |
|
20
|
|
|
|
|
593
|
|
|
20
|
|
|
|
|
3795
|
|
|
2
|
|
|
|
|
4
|
|
90
|
2
|
|
|
|
|
6
|
*{$class."::new"} = \&_new_with_base; |
|
2
|
|
|
|
|
12
|
|
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
96
|
|
|
|
|
|
|
# caller |
97
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# custom caller routine ignores this module and keeps looking upwards. |
100
|
|
|
|
|
|
|
# can't use Sub::Uplevel due to an off-by-one issue in the current version |
101
|
|
|
|
|
|
|
|
102
|
20
|
|
|
20
|
|
22469
|
use subs 'caller'; |
|
20
|
|
|
|
|
448
|
|
|
20
|
|
|
|
|
108
|
|
103
|
|
|
|
|
|
|
sub caller { |
104
|
50
|
|
|
50
|
|
95
|
my ($uplevel) = @_; |
105
|
50
|
|
50
|
|
|
252
|
$uplevel ||= 0; |
106
|
50
|
|
|
|
|
401
|
$uplevel++ while ( (CORE::caller($uplevel+1))[0] eq __PACKAGE__ ); |
107
|
50
|
|
|
|
|
384
|
my @caller = CORE::caller($uplevel+1); |
108
|
50
|
50
|
|
|
|
805
|
return wantarray ? ( @_ ? @caller : @caller[0 .. 2] ) : $caller[0]; |
|
|
100
|
|
|
|
|
|
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
112
|
|
|
|
|
|
|
# give_methods |
113
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub give_methods { |
116
|
26
|
|
|
26
|
1
|
3847
|
my $package = caller; |
117
|
26
|
|
|
|
|
52
|
for ( @{$public_methods{$package}} ) { |
|
26
|
|
|
|
|
81
|
|
118
|
106
|
|
|
|
|
228
|
_install_wrapper($package, $_, "public"); |
119
|
|
|
|
|
|
|
}; |
120
|
26
|
|
|
|
|
58
|
for ( @{$protected_methods{$package}} ) { |
|
26
|
|
|
|
|
99
|
|
121
|
1
|
|
|
|
|
3
|
_install_wrapper($package, $_, "protected"); |
122
|
|
|
|
|
|
|
}; |
123
|
26
|
|
|
|
|
85
|
for ( @{$private_methods{$package}} ) { |
|
26
|
|
|
|
|
311
|
|
124
|
2
|
|
|
|
|
5
|
_install_wrapper($package, $_, "private"); |
125
|
|
|
|
|
|
|
}; |
126
|
26
|
|
|
|
|
95
|
return 1; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
130
|
|
|
|
|
|
|
# new() |
131
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub new { |
134
|
20
|
|
|
20
|
|
6769
|
no strict 'refs'; |
|
20
|
|
|
|
|
582
|
|
|
20
|
|
|
|
|
3165
|
|
135
|
41
|
|
|
41
|
1
|
45976
|
my ($class, @args) = @_; |
136
|
41
|
50
|
|
|
|
221
|
die "new can't be called on an object" if ref($class); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# create blessed object |
139
|
41
|
|
|
|
|
70
|
my $self = \do{ my $scalar }; |
|
41
|
|
|
|
|
170
|
|
140
|
41
|
|
|
|
|
128
|
bless $self, $class; |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# call initializer |
143
|
41
|
|
|
|
|
155
|
return BUILDALL( $class, $self, @args ); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub _new_with_base { |
147
|
20
|
|
|
20
|
|
124
|
no strict 'refs'; |
|
20
|
|
|
|
|
42
|
|
|
20
|
|
|
|
|
5469
|
|
148
|
2
|
|
|
2
|
|
1607
|
my ($class, @args) = @_; |
149
|
2
|
50
|
|
|
|
9
|
die "new can't be called on an object" if ref($class); |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# create blessed object |
152
|
2
|
|
|
|
|
6
|
my $base_class = $base_class_of{ $class }; |
153
|
2
|
|
|
|
|
3
|
my $prebuild = *{$class."::PREBUILD"}{CODE}; |
|
2
|
|
|
|
|
14
|
|
154
|
|
|
|
|
|
|
my @filtered_args |
155
|
2
|
50
|
|
|
|
9
|
= defined $prebuild ? $prebuild->($base_class, @args) : @args; |
156
|
2
|
|
|
|
|
12
|
my $self = $base_class->new( @filtered_args ); |
157
|
2
|
|
|
|
|
12
|
bless $self, $class; |
158
|
2
|
|
|
|
|
7
|
my $addr = refaddr $self; |
159
|
2
|
|
|
|
|
4
|
${$class . "::TRACKER"}{$addr} = $self; |
|
2
|
|
|
|
|
13
|
|
160
|
2
|
|
|
|
|
4
|
weaken ${$class . "::TRACKER"}{$addr}; # don't let this stop destruction |
|
2
|
|
|
|
|
11
|
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# call initializer -- but skip base_class |
163
|
|
|
|
|
|
|
{ |
164
|
2
|
|
|
|
|
4
|
local @{$class."::ISA"} |
|
2
|
|
|
|
|
48
|
|
|
2
|
|
|
|
|
7
|
|
165
|
2
|
|
|
|
|
6
|
= grep { $_ ne $base_class } @{$class."::ISA"}; |
|
2
|
|
|
|
|
9
|
|
166
|
2
|
|
|
|
|
12
|
return BUILDALL( $class, $self, @_ ); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
171
|
|
|
|
|
|
|
# BUILDALL |
172
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub BUILDALL { |
175
|
20
|
|
|
20
|
|
140
|
no strict 'refs'; |
|
20
|
|
|
|
|
36
|
|
|
20
|
|
|
|
|
4874
|
|
176
|
54
|
|
|
54
|
1
|
134
|
my ($class, $self, @args) = @_; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# return if we've already initialized this class |
179
|
54
|
|
|
|
|
181
|
my $addr = refaddr $self; |
180
|
54
|
100
|
|
|
|
78
|
return $self if ( exists ${$class . "::TRACKER"}{$addr} ); |
|
54
|
|
|
|
|
437
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# otherwise register $self in the tracker and continue |
183
|
51
|
|
|
|
|
134
|
${$class . "::TRACKER"}{$addr} = $self; |
|
51
|
|
|
|
|
220
|
|
184
|
51
|
|
|
|
|
76
|
weaken ${$class . "::TRACKER"}{$addr}; # don't let this stop destruction |
|
51
|
|
|
|
|
312
|
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# initialize superclasses if they can |
187
|
51
|
|
|
|
|
77
|
for my $superclass (@{"${class}::ISA"}) { |
|
51
|
|
|
|
|
289
|
|
188
|
11
|
50
|
|
|
|
136
|
if ( my $super_buildall = $superclass->can( 'BUILDALL' ) ) { |
189
|
11
|
|
|
|
|
21
|
my $prebuild = *{$class."::PREBUILD"}{CODE}; |
|
11
|
|
|
|
|
61
|
|
190
|
11
|
100
|
|
|
|
50
|
my @filtered_args = |
191
|
|
|
|
|
|
|
defined $prebuild ? $prebuild->($superclass, @args) : @args; |
192
|
11
|
|
|
|
|
79
|
$super_buildall->($superclass, $self, @filtered_args); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# initialize self if we have an initializer |
197
|
20
|
|
|
|
|
1680
|
*{$class."::BUILD"}{CODE}->($self, @args) |
|
51
|
|
|
|
|
322
|
|
198
|
51
|
100
|
|
|
|
86
|
if defined *{$class."::BUILD"}{CODE}; |
199
|
51
|
|
|
|
|
491
|
return $self; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
203
|
|
|
|
|
|
|
# CLONE |
204
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub CLONE { |
207
|
20
|
|
|
20
|
|
104
|
no strict 'refs'; |
|
20
|
|
|
|
|
521
|
|
|
20
|
|
|
|
|
4081
|
|
208
|
0
|
|
|
0
|
|
0
|
my $class = shift; |
209
|
0
|
|
|
|
|
0
|
for my $old_obj_id ( keys %{$class . "::TRACKER"} ) { |
|
0
|
|
|
|
|
0
|
|
210
|
0
|
|
|
|
|
0
|
my $new_obj_id = refaddr( |
211
|
0
|
|
|
|
|
0
|
${$class . "::TRACKER"}{$old_obj_id} |
212
|
|
|
|
|
|
|
); |
213
|
0
|
|
|
|
|
0
|
for my $prop ( keys %{"${class}::DATA::"} ) { |
|
0
|
|
|
|
|
0
|
|
214
|
0
|
|
|
|
|
0
|
my $qualified_name = $class . "::DATA::$prop"; |
215
|
0
|
|
|
|
|
0
|
$$qualified_name{ $new_obj_id } = $$qualified_name{ $old_obj_id }; |
216
|
0
|
|
|
|
|
0
|
delete $$qualified_name{ $old_obj_id }; |
217
|
|
|
|
|
|
|
} |
218
|
0
|
|
|
|
|
0
|
${$class . "::TRACKER"}{$new_obj_id} = $new_obj_id; |
|
0
|
|
|
|
|
0
|
|
219
|
0
|
|
|
|
|
0
|
delete ${$class . "::TRACKER"}{$old_obj_id}; |
|
0
|
|
|
|
|
0
|
|
220
|
|
|
|
|
|
|
} |
221
|
0
|
|
|
|
|
0
|
return 1; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
225
|
|
|
|
|
|
|
# DESTROY |
226
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub DESTROY { |
229
|
20
|
|
|
20
|
|
101
|
no strict 'refs'; |
|
20
|
|
|
|
|
34
|
|
|
20
|
|
|
|
|
5659
|
|
230
|
55
|
|
|
55
|
|
939651
|
my ($self, $class) = @_; |
231
|
55
|
|
66
|
|
|
557
|
$class ||= ref $self; |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# return if we've already destructed this class |
234
|
55
|
|
|
|
|
220
|
my $addr = refaddr $self; |
235
|
55
|
100
|
|
|
|
85
|
return if ( ! exists ${$class . "::TRACKER"}{$addr} ); |
|
55
|
|
|
|
|
560
|
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# otherwise mark that we're destroying this class and continue |
238
|
53
|
|
|
|
|
100
|
delete ${$class . "::TRACKER"}{$addr}; |
|
53
|
|
|
|
|
223
|
|
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# demolish and free data for this class |
241
|
18
|
|
|
|
|
653
|
*{$class."::DEMOLISH"}{CODE}->($self) |
|
53
|
|
|
|
|
363
|
|
242
|
53
|
100
|
|
|
|
87
|
if defined *{$class."::DEMOLISH"}{CODE}; |
243
|
53
|
|
|
|
|
161
|
for ( keys %{"${class}::DATA::"} ) { |
|
53
|
|
|
|
|
319
|
|
244
|
88
|
|
|
|
|
140
|
delete (${"${class}::DATA::$_"}{$addr}); |
|
88
|
|
|
|
|
412
|
|
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# destroy all superclasses |
248
|
53
|
|
|
|
|
168
|
for my $superclass ( @{"${class}::ISA"} ) { |
|
53
|
|
|
|
|
1710
|
|
249
|
13
|
100
|
|
|
|
234
|
if ( my $super_destroyer = $superclass->can("DESTROY") ) { |
250
|
11
|
|
|
|
|
61
|
$super_destroyer->($self, $superclass); |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
257
|
|
|
|
|
|
|
# MODIFY_CODE_ATTRIBUTES |
258
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub MODIFY_CODE_ATTRIBUTES { |
261
|
109
|
|
|
109
|
|
31292
|
my ($package, $referent, @attrs) = @_; |
262
|
109
|
|
|
|
|
195
|
for my $attr (@attrs) { |
263
|
20
|
|
|
20
|
|
121
|
no strict 'refs'; |
|
20
|
|
|
|
|
36
|
|
|
20
|
|
|
|
|
4386
|
|
264
|
109
|
100
|
|
|
|
508
|
if ( $attr =~ /^(?:Method|Pub)$/ ) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
265
|
106
|
|
|
|
|
127
|
push @{$public_methods{$package}}, $referent; |
|
106
|
|
|
|
|
229
|
|
266
|
106
|
|
|
|
|
285
|
undef $attr; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
elsif ($attr eq "Prot") { |
269
|
1
|
|
|
|
|
2
|
push @{$protected_methods{$package}}, $referent; |
|
1
|
|
|
|
|
4
|
|
270
|
1
|
|
|
|
|
3
|
undef $attr; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
elsif ($attr eq "Priv") { |
273
|
2
|
|
|
|
|
3
|
push @{$private_methods{$package}}, $referent; |
|
2
|
|
|
|
|
4
|
|
274
|
2
|
|
|
|
|
5
|
undef $attr; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
109
|
|
|
|
|
192
|
return grep {defined} @attrs; |
|
109
|
|
|
|
|
403
|
|
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
281
|
|
|
|
|
|
|
# MODIFY_SCALAR_ATTRIBUTES |
282
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub MODIFY_SCALAR_ATTRIBUTES { |
285
|
70
|
|
|
70
|
|
49171
|
my ($OL_PACKAGE, $referent, @attrs) = @_; |
286
|
70
|
|
|
|
|
140
|
for my $attr (@attrs) { |
287
|
20
|
|
|
20
|
|
108
|
no strict 'refs'; |
|
20
|
|
|
|
|
35
|
|
|
20
|
|
|
|
|
7551
|
|
288
|
70
|
100
|
|
|
|
394
|
if ($attr eq "Pub") { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
289
|
45
|
|
|
|
|
123
|
_install_accessors( $OL_PACKAGE, $referent, "public", 0 ); |
290
|
45
|
|
|
|
|
137
|
undef $attr; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
elsif ($attr eq "Prot") { |
293
|
1
|
|
|
|
|
3
|
_install_accessors( $OL_PACKAGE, $referent, "protected", 0 ); |
294
|
1
|
|
|
|
|
2
|
undef $attr; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
elsif ( $attr =~ /^(?:Prop|Priv)$/ ) { |
297
|
2
|
|
|
|
|
4
|
_install_accessors( $OL_PACKAGE, $referent, "private", 0 ); |
298
|
2
|
|
|
|
|
6
|
undef $attr; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
elsif ( $attr =~ /^(?:ReadOnly)$/ ) { |
301
|
1
|
|
|
|
|
3
|
_install_accessors( $OL_PACKAGE, $referent, "readonly", 0 ); |
302
|
1
|
|
|
|
|
2
|
undef $attr; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
elsif ($attr =~ /^(?:Class|ClassPriv)$/ ) { |
305
|
18
|
|
|
|
|
47
|
_install_accessors( $OL_PACKAGE, $referent, "private", 1 ); |
306
|
18
|
|
|
|
|
48
|
undef $attr; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
elsif ($attr =~ /^(?:ClassProt)$/ ) { |
309
|
1
|
|
|
|
|
3
|
_install_accessors( $OL_PACKAGE, $referent, "protected", 1 ); |
310
|
1
|
|
|
|
|
3
|
undef $attr; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
elsif ($attr =~ /^(?:ClassPub)$/ ) { |
313
|
1
|
|
|
|
|
4
|
_install_accessors( $OL_PACKAGE, $referent, "public", 1 ); |
314
|
1
|
|
|
|
|
3
|
undef $attr; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
elsif ($attr =~ /^(?:ClassReadOnly)$/ ) { |
317
|
1
|
|
|
|
|
3
|
_install_accessors( $OL_PACKAGE, $referent, "readonly", 1 ); |
318
|
1
|
|
|
|
|
3
|
undef $attr; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
else { |
321
|
|
|
|
|
|
|
# we don't really care |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
} |
324
|
70
|
|
|
|
|
140
|
return grep {defined} @attrs; |
|
70
|
|
|
|
|
337
|
|
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
328
|
|
|
|
|
|
|
# _findsym |
329
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
my %symcache; |
332
|
|
|
|
|
|
|
sub _findsym { |
333
|
20
|
|
|
20
|
|
113
|
no strict 'refs'; |
|
20
|
|
|
|
|
41
|
|
|
20
|
|
|
|
|
4378
|
|
334
|
179
|
|
|
179
|
|
261
|
my ($pkg, $ref, $type) = @_; |
335
|
179
|
50
|
|
|
|
778
|
return $symcache{$pkg,$ref} if $symcache{$pkg,$ref}; |
336
|
179
|
|
33
|
|
|
802
|
$type ||= ref($ref); |
337
|
179
|
|
|
|
|
197
|
my $found; |
338
|
179
|
|
|
|
|
205
|
foreach my $sym ( values %{$pkg."::"} ) { |
|
179
|
|
|
|
|
812
|
|
339
|
2184
|
|
|
|
|
6673
|
return $symcache{$pkg,$ref} = \$sym |
340
|
2184
|
100
|
100
|
|
|
2047
|
if *{$sym}{$type} && *{$sym}{$type} == $ref; |
|
1757
|
|
|
|
|
17372
|
|
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
345
|
|
|
|
|
|
|
# _gen_accessor |
346
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub _gen_accessor { |
349
|
48
|
|
|
48
|
|
83
|
my ($package, $name, $classwide) = @_; |
350
|
48
|
100
|
|
|
|
375
|
return $classwide |
351
|
|
|
|
|
|
|
? "return \$${package}::CLASSDATA{${name}}" |
352
|
|
|
|
|
|
|
: "return \$${package}::DATA::${name}" . |
353
|
|
|
|
|
|
|
"{refaddr( \$_[0] )}" ; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
357
|
|
|
|
|
|
|
# _gen_class_locals |
358
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub _gen_class_locals { |
361
|
20
|
|
|
20
|
|
108
|
no strict 'refs'; |
|
20
|
|
|
|
|
38
|
|
|
20
|
|
|
|
|
8022
|
|
362
|
109
|
|
|
109
|
|
149
|
my $package = shift; |
363
|
109
|
|
|
|
|
137
|
my $evaltext = ""; |
364
|
109
|
|
|
|
|
126
|
my @props = keys %{$package."::CLASSDATA"}; |
|
109
|
|
|
|
|
457
|
|
365
|
109
|
100
|
|
|
|
325
|
return "" unless @props; |
366
|
82
|
|
|
|
|
127
|
my @globs = map { "*${package}::$_" } @props; |
|
114
|
|
|
|
|
308
|
|
367
|
82
|
|
|
|
|
168
|
my @refs = map { "\\\$${package}::CLASSDATA{$_}" } @props; |
|
114
|
|
|
|
|
268
|
|
368
|
82
|
|
|
|
|
300
|
$evaltext .= " local ( " . join(", ", @globs) . " ) = ( " . |
369
|
|
|
|
|
|
|
join(", ", @refs) . " );\n"; |
370
|
82
|
|
|
|
|
299
|
return $evaltext; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
374
|
|
|
|
|
|
|
# _gen_acc_mut |
375
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub _gen_acc_mut { |
378
|
2
|
|
|
2
|
|
4
|
my ($package, $name, $classwide) = @_; |
379
|
2
|
50
|
|
|
|
27
|
return $classwide |
380
|
|
|
|
|
|
|
? "return (\@_ > 1) ? " . |
381
|
|
|
|
|
|
|
"\$${package}::CLASSDATA{${name}} = \$_[1] : " . |
382
|
|
|
|
|
|
|
"\$${package}::CLASSDATA{${name}} ; " . |
383
|
|
|
|
|
|
|
"\n" |
384
|
|
|
|
|
|
|
: "return (\@_ > 1) ? " . |
385
|
|
|
|
|
|
|
"\$${package}::DATA::${name}" . "{refaddr( \$_[0] )} = \$_[1] : " . |
386
|
|
|
|
|
|
|
"\$${package}::DATA::${name}" . "{refaddr( \$_[0] )} " . |
387
|
|
|
|
|
|
|
"\n"; |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
391
|
|
|
|
|
|
|
# _gen_mutator |
392
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub _gen_mutator { |
395
|
48
|
|
|
48
|
|
82
|
my ($package, $name, $classwide) = @_; |
396
|
48
|
100
|
|
|
|
285
|
return $classwide |
397
|
|
|
|
|
|
|
? "\$${package}::CLASSDATA{${name}} = \$_[1];\n" . |
398
|
|
|
|
|
|
|
"return \$_[0] " |
399
|
|
|
|
|
|
|
: "\$${package}::DATA::${name}" . |
400
|
|
|
|
|
|
|
"{refaddr( \$_[0] )} = \$_[1];\n" . |
401
|
|
|
|
|
|
|
"return \$_[0]"; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
405
|
|
|
|
|
|
|
# _gen_object_locals |
406
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub _gen_object_locals { |
409
|
20
|
|
|
20
|
|
107
|
no strict 'refs'; |
|
20
|
|
|
|
|
462
|
|
|
20
|
|
|
|
|
7885
|
|
410
|
109
|
|
|
109
|
|
157
|
my $package = shift; |
411
|
109
|
|
|
|
|
119
|
my @props = keys %{$package."::DATA::"}; |
|
109
|
|
|
|
|
410
|
|
412
|
109
|
100
|
|
|
|
333
|
return "" unless @props; |
413
|
80
|
|
|
|
|
106
|
my $evaltext = " my \$id;\n"; # need to define it |
414
|
80
|
|
|
|
|
164
|
$evaltext .= " \$id = refaddr(\$obj) if ref(\$obj);\n"; |
415
|
80
|
|
|
|
|
127
|
my @globs = map { "*${package}::$_" } @props; |
|
181
|
|
|
|
|
415
|
|
416
|
80
|
|
|
|
|
122
|
my @refs = map { "\\\$${package}::DATA::$_ {\$id}" } @props; |
|
181
|
|
|
|
|
423
|
|
417
|
80
|
|
|
|
|
320
|
$evaltext .= " local ( " . join(", ", @globs) . " ) = ( " . |
418
|
|
|
|
|
|
|
join(", ", @refs) . " ) if \$id;\n"; |
419
|
80
|
|
|
|
|
412
|
return $evaltext; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
423
|
|
|
|
|
|
|
# _gen_privacy |
424
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
sub _gen_privacy { |
427
|
207
|
|
|
207
|
|
307
|
my ($package, $name, $privacy) = @_; |
428
|
207
|
|
|
|
|
346
|
SWITCH: for ($privacy) { |
429
|
207
|
100
|
|
|
|
587
|
/public/ && do { return "" }; |
|
198
|
|
|
|
|
797
|
|
430
|
|
|
|
|
|
|
|
431
|
9
|
100
|
|
|
|
21
|
/protected/ && do { return |
432
|
7
|
|
|
|
|
37
|
" my (\$caller) = caller();\n" . |
433
|
|
|
|
|
|
|
" croak q/$name is a protected method and can't be called from ${package}/\n". |
434
|
|
|
|
|
|
|
" unless \$caller->isa( '$package' );\n" |
435
|
|
|
|
|
|
|
}; |
436
|
|
|
|
|
|
|
|
437
|
2
|
50
|
|
|
|
7
|
/private/ && do { return |
438
|
2
|
|
|
|
|
13
|
" my (\$caller) = caller();\n" . |
439
|
|
|
|
|
|
|
" croak q/$name is a private method and can't be called from ${package}/\n". |
440
|
|
|
|
|
|
|
" unless \$caller eq '$package';\n" |
441
|
|
|
|
|
|
|
}; |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
446
|
|
|
|
|
|
|
# _install_accessors |
447
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
sub _install_accessors { |
450
|
70
|
|
|
70
|
|
137
|
my ($package,$scalarref,$privacy,$classwide) = @_; |
451
|
20
|
|
|
20
|
|
114
|
no strict 'refs'; |
|
20
|
|
|
|
|
28
|
|
|
20
|
|
|
|
|
8864
|
|
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# find name from reference |
454
|
70
|
50
|
|
|
|
166
|
my $symbol = _findsym($package, $scalarref) or die; |
455
|
70
|
|
|
|
|
152
|
my $name = *{$symbol}{NAME}; |
|
70
|
|
|
|
|
138
|
|
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# make the property exist to be found by give_methods() |
458
|
70
|
100
|
|
|
|
154
|
if ($classwide) { |
459
|
21
|
|
|
|
|
51
|
${$package."::CLASSDATA"}{$name} = undef; |
|
21
|
|
|
|
|
122
|
|
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
else { |
462
|
49
|
|
|
|
|
69
|
%{$package."::DATA::".$name} = (); |
|
49
|
|
|
|
|
324
|
|
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
# determine names for accessor/mutator |
466
|
70
|
|
|
|
|
153
|
my $get = $prefixes_for{ $package }{get}; |
467
|
70
|
|
|
|
|
111
|
my $set = $prefixes_for{ $package }{set}; |
468
|
70
|
100
|
|
|
|
227
|
my $acc = ( defined $get ? $get : q{} ) . $name; |
469
|
70
|
100
|
|
|
|
165
|
my $mut = ( defined $set ? $set : q{set_} ) . $name; |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# install accessors |
472
|
70
|
100
|
|
|
|
251
|
return if $privacy eq "private"; # unless private |
473
|
50
|
100
|
|
|
|
127
|
my $accessor_privacy = $privacy eq 'readonly' ? 'public' : $privacy; |
474
|
50
|
100
|
|
|
|
111
|
my $mutator_privacy = $privacy eq 'readonly' ? 'protected' : $privacy; |
475
|
50
|
|
|
|
|
62
|
my $evaltext; |
476
|
50
|
100
|
|
|
|
124
|
if ( $acc ne $mut ) { |
477
|
48
|
|
|
|
|
168
|
$evaltext = |
478
|
|
|
|
|
|
|
"*${package}::${acc} = sub { \n" . |
479
|
|
|
|
|
|
|
_gen_privacy( $package, $name, $accessor_privacy ) . |
480
|
|
|
|
|
|
|
_gen_accessor( $package, $name, $classwide ) . |
481
|
|
|
|
|
|
|
"\n}; \n\n" . |
482
|
|
|
|
|
|
|
"*${package}::${mut} = sub { \n" . |
483
|
|
|
|
|
|
|
_gen_privacy( $package, "set_$name", $mutator_privacy ) . |
484
|
|
|
|
|
|
|
_gen_mutator( $package, $name, $classwide ) . |
485
|
|
|
|
|
|
|
"\n}; " |
486
|
|
|
|
|
|
|
; # $evaltext |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
else { |
489
|
2
|
|
|
|
|
11
|
$evaltext = |
490
|
|
|
|
|
|
|
"*${package}::${mut} = sub { \n" . |
491
|
|
|
|
|
|
|
_gen_privacy( $package, "set_$name", $mutator_privacy ) . |
492
|
|
|
|
|
|
|
_gen_acc_mut( $package, $name, $classwide ) . |
493
|
|
|
|
|
|
|
"\n}; " |
494
|
|
|
|
|
|
|
; # $evaltext |
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
50
|
|
|
30
|
|
7851
|
eval $evaltext; ## no critic |
|
30
|
|
|
|
|
1416
|
|
|
28
|
|
|
|
|
201
|
|
|
28
|
|
|
|
|
185
|
|
|
27
|
|
|
|
|
1798
|
|
|
35
|
|
|
|
|
4245
|
|
|
30
|
|
|
|
|
595
|
|
498
|
50
|
50
|
|
|
|
155
|
die $@ if $@; |
499
|
50
|
|
|
|
|
134
|
return; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
503
|
|
|
|
|
|
|
# _install_wrapper |
504
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
sub _install_wrapper { |
507
|
109
|
|
|
109
|
|
188
|
my ($package,$coderef,$privacy) = @_; |
508
|
20
|
|
|
20
|
|
114
|
no strict 'refs'; |
|
20
|
|
|
|
|
34
|
|
|
20
|
|
|
|
|
664
|
|
509
|
20
|
|
|
20
|
|
103
|
no warnings 'redefine'; |
|
20
|
|
|
|
|
42
|
|
|
20
|
|
|
|
|
5383
|
|
510
|
109
|
50
|
|
|
|
223
|
my $symbol = _findsym($package, $coderef) or die; |
511
|
109
|
|
|
|
|
243
|
my $name = *{$symbol}{NAME}; |
|
109
|
|
|
|
|
212
|
|
512
|
109
|
|
|
|
|
148
|
*{$package."::METHODS::$name"} = $coderef; |
|
109
|
|
|
|
|
654
|
|
513
|
109
|
|
|
|
|
342
|
my $evaltext = "*${package}::${name} = sub {\n". |
514
|
|
|
|
|
|
|
_gen_privacy( $package, $name, $privacy ) . |
515
|
|
|
|
|
|
|
" my \$obj = shift;\n" . |
516
|
|
|
|
|
|
|
" local \$${package}::self = \$obj;\n" . |
517
|
|
|
|
|
|
|
_gen_class_locals($package) . |
518
|
|
|
|
|
|
|
_gen_object_locals($package) . |
519
|
|
|
|
|
|
|
" local \$Carp::CarpLevel = \$Carp::CarpLevel + 2;\n". |
520
|
|
|
|
|
|
|
" ${package}::METHODS::${name}(\@_);\n". |
521
|
|
|
|
|
|
|
"}\n" |
522
|
|
|
|
|
|
|
; # my |
523
|
|
|
|
|
|
|
# XXX print "\n\n$evaltext\n\n"; |
524
|
109
|
|
|
|
|
19012
|
eval $evaltext; ## no critic |
|
22
|
|
|
|
|
580
|
|
|
21
|
|
|
|
|
79
|
|
|
16
|
|
|
|
|
1468
|
|
|
17
|
|
|
|
|
57
|
|
|
17
|
|
|
|
|
594
|
|
|
19
|
|
|
|
|
137
|
|
|
14
|
|
|
|
|
528
|
|
|
13
|
|
|
|
|
66
|
|
|
14
|
|
|
|
|
500
|
|
|
15
|
|
|
|
|
820
|
|
|
14
|
|
|
|
|
528
|
|
|
14
|
|
|
|
|
77
|
|
525
|
109
|
50
|
|
|
|
410
|
die $@ if $@; |
526
|
109
|
|
|
|
|
294
|
return; |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
1; |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
__END__ |