line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Method::Lexical; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
329665
|
use 5.008001; |
|
9
|
|
|
|
|
39
|
|
|
9
|
|
|
|
|
701
|
|
4
|
|
|
|
|
|
|
|
5
|
9
|
|
|
9
|
|
61
|
use strict; |
|
9
|
|
|
|
|
17
|
|
|
9
|
|
|
|
|
553
|
|
6
|
9
|
|
|
9
|
|
51
|
use warnings; |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
1123
|
|
7
|
|
|
|
|
|
|
|
8
|
9
|
|
|
9
|
|
11897
|
use B::Hooks::EndOfScope; |
|
9
|
|
|
|
|
175443
|
|
|
9
|
|
|
|
|
79
|
|
9
|
9
|
|
|
9
|
|
12869
|
use B::Hooks::OP::Check; |
|
9
|
|
|
|
|
24027
|
|
|
9
|
|
|
|
|
487
|
|
10
|
9
|
|
|
9
|
|
10883
|
use B::Hooks::OP::Annotation; |
|
9
|
|
|
|
|
12403
|
|
|
9
|
|
|
|
|
361
|
|
11
|
9
|
|
|
9
|
|
76
|
use Carp qw(carp confess); |
|
9
|
|
|
|
|
129
|
|
|
9
|
|
|
|
|
1410
|
|
12
|
9
|
|
|
9
|
|
11227
|
use Devel::Pragma qw(ccstash fqname my_hints new_scope on_require); |
|
9
|
|
|
|
|
38848
|
|
|
9
|
|
|
|
|
205
|
|
13
|
9
|
|
|
9
|
|
2636
|
use XSLoader; |
|
9
|
|
|
|
|
23
|
|
|
9
|
|
|
|
|
3464
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.30'; |
16
|
|
|
|
|
|
|
our @CARP_NOT = qw(B::Hooks::EndOfScope); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
XSLoader::load(__PACKAGE__, $VERSION); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
my $DEBUG = xs_get_debug(); # flag indicating whether debug messages should be printed |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# The key under which the $installed hash is installed in %^H i.e. 'Method::Lexical' |
23
|
|
|
|
|
|
|
# Defined as a preprocessor macro in Lexical.xs to ensure the Perl and XS are kept in sync |
24
|
|
|
|
|
|
|
my $METHOD_LEXICAL = xs_signature(); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# accessors for the debug flags - note there is one for Perl ($DEBUG) and one defined |
27
|
|
|
|
|
|
|
# in the XS (METHOD_LEXICAL_DEBUG). The accessors ensure that the two are kept in sync |
28
|
0
|
|
|
0
|
|
0
|
sub _get_debug() { $DEBUG } |
29
|
0
|
|
0
|
0
|
|
0
|
sub _set_debug($) { xs_set_debug($DEBUG = shift || 0) } |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# This logs method installations/uninstallations |
32
|
|
|
|
|
|
|
sub _debug { |
33
|
0
|
|
|
0
|
|
0
|
my ($class, $action, $fqname) = @_; |
34
|
0
|
|
|
|
|
0
|
carp "$class: $action $fqname"; |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# return true if $ref ISA $class - works with non-references, unblessed references and objects |
38
|
|
|
|
|
|
|
sub _isa($$) { |
39
|
29
|
|
|
29
|
|
61
|
my ($ref, $class) = @_; |
40
|
29
|
50
|
|
|
|
190
|
return Scalar::Util::blessed(ref) ? $ref->isa($class) : ref($ref) eq $class; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# given a fully-qualified subroutine name (e.g. Foo::Bar::baz) load the module (Foo::Bar) |
44
|
|
|
|
|
|
|
sub _load($) { |
45
|
6
|
|
|
6
|
|
16
|
my $fqname = shift; |
46
|
6
|
|
|
|
|
17
|
my ($module, $subname) = fqname($fqname); |
47
|
|
|
|
|
|
|
|
48
|
6
|
|
|
|
|
702
|
eval "require $module"; |
49
|
|
|
|
|
|
|
|
50
|
6
|
50
|
|
|
|
51
|
if ($@) { |
51
|
9
|
|
|
9
|
|
146
|
no strict 'refs'; |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
7419
|
|
52
|
|
|
|
|
|
|
# don't raise an error if the package is declared in an already-loaded file |
53
|
6
|
100
|
|
|
|
9
|
confess "Can't load $module for subroutine $fqname: $@" unless (%{"$module\::"}); |
|
6
|
|
|
|
|
862
|
|
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# install one or more lexical methods in the current scope |
58
|
|
|
|
|
|
|
# |
59
|
|
|
|
|
|
|
# import() has to keep track of two things: |
60
|
|
|
|
|
|
|
# |
61
|
|
|
|
|
|
|
# 1) $installed keeps track of *all* currently active lexical methods so that Lexical.xs |
62
|
|
|
|
|
|
|
# can track them without needing to know the subclass of Method::Lexical that installed them |
63
|
|
|
|
|
|
|
# 2) $class_data keeps track of which subs have been installed by this class (which may be a subclass of |
64
|
|
|
|
|
|
|
# Method::Lexical) in this scope, so that they can be unimported with "no MyPragma (...)" |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub import { |
67
|
14
|
|
|
14
|
|
2297
|
my $class = shift; |
68
|
14
|
100
|
66
|
|
|
120
|
my %bindings = ((@_ == 1) && _isa($_[0], 'HASH')) ? %{shift()} : @_; # hash or hashref |
|
6
|
|
|
|
|
45
|
|
69
|
|
|
|
|
|
|
|
70
|
14
|
100
|
|
|
|
86
|
return unless (%bindings); |
71
|
|
|
|
|
|
|
|
72
|
13
|
|
|
|
|
45
|
my $autoload = delete $bindings{-autoload}; |
73
|
13
|
|
|
|
|
25
|
my $debug = delete $bindings{-debug}; |
74
|
13
|
|
|
|
|
106
|
my $hints = my_hints; |
75
|
13
|
|
|
|
|
107
|
my $caller = ccstash(); |
76
|
13
|
|
|
|
|
18
|
my $installed; |
77
|
|
|
|
|
|
|
|
78
|
13
|
50
|
|
|
|
53
|
if (defined $debug) { |
79
|
0
|
|
|
|
|
0
|
my $old_debug = _get_debug(); |
80
|
0
|
0
|
|
|
|
0
|
if ($debug != $old_debug) { |
81
|
0
|
|
|
|
|
0
|
_set_debug($debug); |
82
|
0
|
|
|
0
|
|
0
|
on_scope_end { _set_debug($old_debug) }; |
|
0
|
|
|
|
|
0
|
|
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
13
|
50
|
|
|
|
47
|
if (new_scope($METHOD_LEXICAL)) { |
87
|
13
|
|
|
|
|
470
|
my $top_level = 0; |
88
|
13
|
|
|
|
|
31
|
my $temp = $hints->{$METHOD_LEXICAL}; |
89
|
|
|
|
|
|
|
|
90
|
13
|
50
|
|
|
|
199
|
if ($temp) { |
91
|
|
|
|
|
|
|
# the hash is cloned to ensure that inner/nested scopes don't clobber/contaminate |
92
|
|
|
|
|
|
|
# outer/previous scopes with their new bindings. Likewise, unimport installs |
93
|
|
|
|
|
|
|
# a new hash to ensure that previous bindings aren't clobbered e.g. |
94
|
|
|
|
|
|
|
# |
95
|
|
|
|
|
|
|
# { |
96
|
|
|
|
|
|
|
# package Foo; |
97
|
|
|
|
|
|
|
# |
98
|
|
|
|
|
|
|
# use Method::Lexical bar => sub { ... }; |
99
|
|
|
|
|
|
|
# |
100
|
|
|
|
|
|
|
# Foo->new->bar(); |
101
|
|
|
|
|
|
|
# |
102
|
|
|
|
|
|
|
# no Method::Lexical; # don't clobber the bindings associated with the previous method call |
103
|
|
|
|
|
|
|
# } |
104
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
0
|
$installed = $hints->{$METHOD_LEXICAL} = { %$temp }; # clone |
106
|
|
|
|
|
|
|
} else { |
107
|
13
|
|
|
|
|
18
|
$top_level = 1; |
108
|
13
|
|
|
|
|
76
|
$installed = $hints->{$METHOD_LEXICAL} = {}; # create |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# disable Method::Lexical altogether when we leave the top-level scope in which it was enabled |
111
|
13
|
|
|
|
|
72
|
on_scope_end \&xs_leave; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# disable/re-enable check hooks before/after require |
114
|
13
|
|
|
|
|
428
|
on_require \&xs_leave, \&xs_enter; |
115
|
|
|
|
|
|
|
|
116
|
13
|
|
|
|
|
725
|
xs_enter(); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
} else { |
119
|
0
|
|
|
|
|
0
|
$installed = $hints->{$METHOD_LEXICAL}; # augment |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Note: the class-specific data is stored under "Method::Lexical($subclass)" rather than |
123
|
|
|
|
|
|
|
# $subclass. The subclass might well have its own uses for $^H{$subclass}, so we keep |
124
|
|
|
|
|
|
|
# our mitts off it |
125
|
|
|
|
|
|
|
# |
126
|
|
|
|
|
|
|
# Also, the unadorned class name can't be used as a key if $METHOD_LEXICAL is 'Method::Lexical' (which |
127
|
|
|
|
|
|
|
# it is) as the two uses conflict with and clobber each other |
128
|
|
|
|
|
|
|
|
129
|
13
|
|
|
|
|
39
|
my $subclass = "$METHOD_LEXICAL($class)"; |
130
|
13
|
|
|
|
|
43
|
my $class_data; |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# never use $class as the identifier for new_scope() here - see above |
133
|
13
|
50
|
|
|
|
38
|
if (new_scope($subclass)) { |
134
|
13
|
|
|
|
|
322
|
my $temp = $hints->{$subclass}; |
135
|
|
|
|
|
|
|
|
136
|
13
|
50
|
|
|
|
84
|
$class_data = $hints->{$subclass} = $temp ? { %$temp } : {}; # clone/create |
137
|
|
|
|
|
|
|
} else { |
138
|
0
|
|
|
|
|
0
|
$class_data = $hints->{$subclass}; # augment |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
13
|
|
|
|
|
46
|
for my $name (keys %bindings) { |
142
|
23
|
|
|
|
|
41
|
my $sub = $bindings{$name}; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# normalize bindings |
145
|
23
|
100
|
|
|
|
59
|
unless (_isa($sub, 'CODE')) { |
146
|
8
|
|
|
|
|
24
|
my $_autoload = $sub =~ s{^\+}{}; # autoload this sub's package |
147
|
8
|
|
|
|
|
25
|
my $subname = fqname($sub); # XXX watch out for fqname returning a list |
148
|
|
|
|
|
|
|
|
149
|
8
|
100
|
100
|
|
|
162
|
if ($_autoload || $autoload) { |
150
|
6
|
|
|
|
|
15
|
_load($subname); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
6
|
|
33
|
|
|
8
|
$sub = do { |
154
|
9
|
|
|
9
|
|
76
|
no strict 'refs'; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
5791
|
|
155
|
|
|
|
|
|
|
*{$subname}{CODE} |
156
|
|
|
|
|
|
|
} || confess "Can't find subroutine for target $name: '$subname'"; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
21
|
|
|
|
|
77
|
my $fqname = fqname($name, $caller); |
160
|
|
|
|
|
|
|
|
161
|
21
|
50
|
|
|
|
489
|
if ($DEBUG) { |
162
|
0
|
0
|
|
|
|
0
|
if (exists $installed->{$fqname}) { |
163
|
0
|
|
|
|
|
0
|
$class->_debug('redefining', $fqname); |
164
|
|
|
|
|
|
|
} else { |
165
|
0
|
|
|
|
|
0
|
$class->_debug('creating', $fqname); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
21
|
|
|
|
|
54
|
$installed->{$fqname} = $sub; |
170
|
21
|
|
|
|
|
7078
|
$class_data->{$fqname} = $sub; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# uninstall one or more lexical subs from the current scope |
175
|
|
|
|
|
|
|
sub unimport { |
176
|
1
|
|
|
1
|
|
8
|
my $class = shift; |
177
|
1
|
|
|
|
|
3
|
my $hints = my_hints; |
178
|
1
|
|
|
|
|
7
|
my $subclass = "$METHOD_LEXICAL($class)"; |
179
|
1
|
|
|
|
|
1
|
my $class_data; |
180
|
|
|
|
|
|
|
|
181
|
1
|
50
|
33
|
|
|
15
|
return unless (($^H & 0x20000) && ($class_data = $hints->{$subclass})); |
182
|
|
|
|
|
|
|
|
183
|
1
|
|
|
|
|
9
|
my $caller = ccstash(); |
184
|
1
|
50
|
|
|
|
6
|
my @subs = @_ ? (map { scalar(fqname($_, $caller)) } @_) : keys(%$class_data); |
|
0
|
|
|
|
|
0
|
|
185
|
1
|
|
|
|
|
3
|
my $installed = $hints->{$METHOD_LEXICAL}; |
186
|
1
|
|
|
|
|
2
|
my $new_installed = { %$installed }; # clone |
187
|
1
|
|
|
|
|
2
|
my $deleted = 0; |
188
|
|
|
|
|
|
|
|
189
|
1
|
|
|
|
|
2
|
for my $fqname (@subs) { |
190
|
1
|
|
|
|
|
2
|
my $sub = $class_data->{$fqname}; |
191
|
|
|
|
|
|
|
|
192
|
1
|
50
|
|
|
|
5
|
if ($sub) { # the coderef of the method this subclass installed |
193
|
|
|
|
|
|
|
# if the current sub ($installed->{$fqname}) is the sub this module installed ($class_data->{$fqname}) |
194
|
1
|
50
|
|
|
|
5
|
if (Scalar::Util::refaddr($sub) == Scalar::Util::refaddr($installed->{$fqname})) { |
195
|
1
|
50
|
|
|
|
3
|
$class->_debug('unimporting', $fqname) if ($DEBUG); |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# what import adds, unimport taketh away |
198
|
1
|
|
|
|
|
2
|
delete $new_installed->{$fqname}; |
199
|
1
|
|
|
|
|
2
|
delete $class_data->{$fqname}; |
200
|
|
|
|
|
|
|
|
201
|
1
|
|
|
|
|
2
|
++$deleted; |
202
|
|
|
|
|
|
|
} else { |
203
|
0
|
|
|
|
|
0
|
carp "$class: attempt to unimport a shadowed lexical method: $fqname"; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} else { |
206
|
0
|
|
|
|
|
0
|
carp "$class: attempt to unimport an undefined lexical method: $fqname"; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
1
|
50
|
|
|
|
4
|
if ($deleted) { |
211
|
1
|
|
|
|
|
176
|
$hints->{$METHOD_LEXICAL} = $new_installed; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
1; |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
__END__ |