| line | stmt | bran | cond | sub | pod | time | code | 
| 1 | 17 |  |  | 17 |  | 957124 | use 5.008; | 
|  | 17 |  |  | 8 |  | 190 |  | 
|  | 8 |  |  |  |  | 541444 |  | 
|  | 8 |  |  |  |  | 99 |  | 
| 2 | 17 |  |  | 17 |  | 89 | use strict; | 
|  | 17 |  |  | 8 |  | 33 |  | 
|  | 17 |  |  |  |  | 496 |  | 
|  | 8 |  |  |  |  | 45 |  | 
|  | 8 |  |  |  |  | 13 |  | 
|  | 8 |  |  |  |  | 192 |  | 
| 3 | 17 |  |  | 17 |  | 89 | use warnings FATAL => 'all'; | 
|  | 17 |  |  | 8 |  | 29 |  | 
|  | 17 |  |  |  |  | 1519 |  | 
|  | 8 |  |  |  |  | 48 |  | 
|  | 8 |  |  |  |  | 14 |  | 
|  | 8 |  |  |  |  | 771 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | package namespace::local; | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | our $VERSION = '0.09'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | =head1 NAME | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | namespace::local - Confine imports or functions to a given scope | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | This module allows to confine imports or private functions | 
| 16 |  |  |  |  |  |  | to a given scope. | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | package My::Module; | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | sub normal_method { | 
| 21 |  |  |  |  |  |  | # frobnicate; # nope! | 
| 22 |  |  |  |  |  |  | }; | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | sub method_with_sugar { | 
| 25 |  |  |  |  |  |  | use namespace::local; | 
| 26 |  |  |  |  |  |  | use Crazy::Prototyped::DSL qw(do_this do_that frobnicate); | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | do_this; | 
| 29 |  |  |  |  |  |  | do_that; | 
| 30 |  |  |  |  |  |  | frobnicate; | 
| 31 |  |  |  |  |  |  | }; | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | sub another_method { | 
| 34 |  |  |  |  |  |  | # frobnicate; # nope! | 
| 35 |  |  |  |  |  |  | }; | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | The calling module's symbol table is saved at the C | 
| 38 |  |  |  |  |  |  | and restored upon leaving the block. | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | The subsequent imports will do their job within the block, | 
| 41 |  |  |  |  |  |  | but will not be available as methods at runtime. | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | =head1 MODES OF OPERATION | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | =head2 -around | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | This confines all subsequent imports and functions | 
| 48 |  |  |  |  |  |  | between the use of L and the end of scope. | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | package My::Package; | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | sub normal_sub { | 
| 53 |  |  |  |  |  |  | # frobnicate() is unknown | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | sub using_import { | 
| 57 |  |  |  |  |  |  | use namespace::local -around; | 
| 58 |  |  |  |  |  |  | use Some::Crazy::DSL qw(frobnicate); | 
| 59 |  |  |  |  |  |  | frobnicate Foo => 42; | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | sub no_import { | 
| 63 |  |  |  |  |  |  | # frobnicate() is unknown | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | =head2 -below (the default) | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | Hides subsequent imports and functions on end of scope. | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | This may be used to mask private functions: | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | package My::Package; | 
| 73 |  |  |  |  |  |  | use Moo::Role; | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | # This is available everywhere | 
| 76 |  |  |  |  |  |  | sub public { | 
| 77 |  |  |  |  |  |  | return private(); | 
| 78 |  |  |  |  |  |  | }; | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | use namespace::local -below; | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | # This is only available in the current file | 
| 83 |  |  |  |  |  |  | sub private { | 
| 84 |  |  |  |  |  |  | return 42; | 
| 85 |  |  |  |  |  |  | }; | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | Note that this doesn't work for private I since methods | 
| 88 |  |  |  |  |  |  | are resolved at runtime. | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | =head2 -above | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | Hide all functions and exports above the use line. | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | This emulates L, by which this module is clearly inspired. | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | package My::Module; | 
| 97 |  |  |  |  |  |  | use POSIX; | 
| 98 |  |  |  |  |  |  | use Time::HiRes; | 
| 99 |  |  |  |  |  |  | use Carp; | 
| 100 |  |  |  |  |  |  | use namespace::local -above; | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | # now define public functions here | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | =head2 no namespace::local | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | Use C (C) to force end of scope for the latest | 
| 107 |  |  |  |  |  |  | L instance in action: | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | package My::Module; | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | use namespace::local; | 
| 112 |  |  |  |  |  |  | sub private { ... }; | 
| 113 |  |  |  |  |  |  | no namespace::local; | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | # private not available here, even though the scope didn't end! | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | No options are currently supported. | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | B. | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | =head1 OPTIONS | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | Extra options may be passed to namespace::local: | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | =head2 -target => Package::Name | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | Act on another package instead of the caller. | 
| 128 |  |  |  |  |  |  | Note that L is only meant to be used in BEGIN phase. | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | =head2 -except => \@list | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | Exempt symbols mentioned in list (with sigils) | 
| 133 |  |  |  |  |  |  | from the module's action. | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | No sigil means a function. | 
| 136 |  |  |  |  |  |  | Only names made of word characters are supported. | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  | =head2 -except => | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | Exempt symbols with names matching the regular expression | 
| 141 |  |  |  |  |  |  | from the module's action. | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | Note that sigils are ignored here. | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | =head2 -only => \@list | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | Only affect the listed symbols (with sigils). | 
| 148 |  |  |  |  |  |  | Rules are the same as for -except. | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | =head2 -only => | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | Only affect symbols with matching names. | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | All C<-only> and C<-except> options act together, further restricting the | 
| 155 |  |  |  |  |  |  | set of affected symbols. | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | =head1 EXEMPTIONS | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | The following symbols are not touched by this module, to avoid breaking things: | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | =over | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | =item * anything that does not consist of word characters; | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | =item * $_, @_, $1, $2, ...; | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | =item * Arrays: C<@CARP_NOT>, C<@EXPORT>, C<@EXPORT_OK>, C<@ISA>; | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | =item * Hashes: C<%OVERLOAD>; | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | =item * Files: C, C, C, C; | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | =item * Functions: C, C, C; | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | =item * Scalars: C<$AUTOLOAD>, C<$a>, C<$b>; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | =back | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | This list is likely incomplete, and may grow in the future. | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | =head1 METHODS/FUNCTIONS | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | None. | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | =head1 CAVEATS | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | This module is highly experimental. | 
| 188 |  |  |  |  |  |  | The following two conditions are guaranteed to hold | 
| 189 |  |  |  |  |  |  | at least until leaving the beta stage: | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | =over | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | =item * All symbols available before the use line will stay so | 
| 194 |  |  |  |  |  |  | after end of scope | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | =item * All I imported I below the use line | 
| 197 |  |  |  |  |  |  | with names consisting of words and not present in L | 
| 198 |  |  |  |  |  |  | are not going to be available after end of scope. | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | =back | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | The rest is a big grey zone. | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | Currently the module works by saving and then restoring globs, | 
| 205 |  |  |  |  |  |  | so variables and filehandles are also reset. | 
| 206 |  |  |  |  |  |  | This may be changed in the future. | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | Due to order of callback execution in L, | 
| 209 |  |  |  |  |  |  | other modules in C namespace may interact poorly | 
| 210 |  |  |  |  |  |  | with L. | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | Up to v.0.07, C<-around> used to be the default mode instead of C<-below>. | 
| 213 |  |  |  |  |  |  | C<-around> is much more restrictive, in particular, it prevents functions | 
| 214 |  |  |  |  |  |  | defined below the block from propagating above the block. | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | This is less of a problem than imported functions leaking upward. | 
| 217 |  |  |  |  |  |  | No perfect solution has yet been found. | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | =cut | 
| 220 |  |  |  |  |  |  |  | 
| 221 | 25 |  |  | 25 |  | 218 | use Carp; | 
|  | 25 |  |  |  |  | 58 |  | 
|  | 25 |  |  |  |  | 1719 |  | 
| 222 | 25 |  |  | 25 |  | 10811 | use B::Hooks::EndOfScope 'on_scope_end'; | 
|  | 25 |  |  |  |  | 265614 |  | 
|  | 25 |  |  |  |  | 162 |  | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | my @stack; | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | sub import { | 
| 227 | 32 |  |  | 32 |  | 1702 | my $class = shift; | 
| 228 |  |  |  |  |  |  |  | 
| 229 | 32 |  |  |  |  | 120 | my $command = namespace::local::_command->new( caller => [ caller ] ); | 
| 230 | 32 |  |  |  |  | 120 | $command->parse_options( @_ ); | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | # on_scope_end executes multiple callbacks as FIFO | 
| 233 |  |  |  |  |  |  | # we need reversed order, so use a stack of commands. | 
| 234 | 28 | 100 |  |  |  | 89 | $stack[-1]->set_next( $command ) if @stack; | 
| 235 | 28 |  |  |  |  | 106 | push @stack, $command; | 
| 236 |  |  |  |  |  |  |  | 
| 237 | 28 |  |  |  |  | 110 | $command->prepare; | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | on_scope_end { | 
| 240 | 28 | 100 |  | 28 |  | 1932 | if (!$command->is_done) { | 
| 241 | 24 |  |  |  |  | 48 | pop @stack; # make sure push == pop | 
| 242 | 24 |  |  |  |  | 66 | local $Carp::Internal{'B::Hooks::EndOfScope::XS'} = 1; | 
| 243 | 24 |  |  |  |  | 58 | local $Carp::Internal{'B::Hooks::EndOfScope'} = 1; | 
| 244 | 24 |  |  |  |  | 61 | $command->execute; | 
| 245 |  |  |  |  |  |  | }; | 
| 246 | 28 |  |  |  |  | 172 | }; | 
| 247 |  |  |  |  |  |  | }; | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | sub unimport { | 
| 250 | 2 |  |  | 2 |  | 130 | my $class = shift; | 
| 251 |  |  |  |  |  |  |  | 
| 252 | 2 | 50 |  |  |  | 6 | croak "No options supported for 'no namespace::local'" | 
| 253 |  |  |  |  |  |  | if @_; | 
| 254 |  |  |  |  |  |  |  | 
| 255 | 2 | 50 |  |  |  | 7 | croak "'no namespace::local' called but namespace::local isn't active" | 
| 256 |  |  |  |  |  |  | unless @stack; | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 2 |  |  |  |  | 3 | my $command = pop @stack; | 
| 259 | 2 |  |  |  |  | 4 | $command->execute; | 
| 260 |  |  |  |  |  |  | }; | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | =head1 ENVIRONMENT | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | Set C to see some debugging information | 
| 265 |  |  |  |  |  |  | upon module load. | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | =head1 THE INTERNALS | 
| 268 |  |  |  |  |  |  |  | 
| 269 |  |  |  |  |  |  | A stack of "command" objects is used behind the scenes. | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | Its interface is not public, see this module's source. | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | Calling | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | =over | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | =item new | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | =back | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | on this package will create a command object, | 
| 282 |  |  |  |  |  |  | I a C instance. | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | The creation and destruction of command has no effect on the namespaces. | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | Instead, special C and C methods | 
| 287 |  |  |  |  |  |  | are called upon import and leaving scope, respectively. | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | =cut | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | sub new { | 
| 292 | 1 |  |  | 1 | 1 | 11 | my $unused = shift; | 
| 293 | 1 |  |  |  |  | 4 | namespace::local::_command->new(caller => [caller 0], @_); | 
| 294 |  |  |  |  |  |  | }; | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | package | 
| 297 |  |  |  |  |  |  | namespace::local::_command; | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | # FIRST AND FOREMOST | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | # See C for how perl stores the Symbol Tables. | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | # In this module we use two-level hashrefs to represent the table: | 
| 304 |  |  |  |  |  |  | # $table->{ $name }{ $type } = $reference | 
| 305 |  |  |  |  |  |  | # where $name is a function/variable/whatever name, | 
| 306 |  |  |  |  |  |  | # $type is one of ARRAY, CODE, FORMAT, HASH, IO, and SCALAR (see @TYPES below), | 
| 307 |  |  |  |  |  |  | # and $reference is a reference of corresponding type (or undef). | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | # So Foo::bar() would be represented as $table->{foo}{CODE} | 
| 310 |  |  |  |  |  |  | # whereas @Foo::ISA is $table->{ISA}{ARRAY}. | 
| 311 |  |  |  |  |  |  |  | 
| 312 | 25 |  |  | 25 |  | 7615 | use Carp; | 
|  | 25 |  |  |  |  | 53 |  | 
|  | 25 |  |  |  |  | 1392 |  | 
| 313 | 25 |  |  | 25 |  | 153 | use Scalar::Util qw(blessed refaddr reftype); | 
|  | 25 |  |  |  |  | 46 |  | 
|  | 25 |  |  |  |  | 2036 |  | 
| 314 |  |  |  |  |  |  | our @CARP_NOT = qw(namespace::local); | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | # TODO need better env parsing... | 
| 317 | 25 | 100 | 100 | 25 |  | 151 | use constant DEBUG => ( lc ($ENV{PERL_NAMESPACE_LOCAL} || '' ) eq 'debug' ? 1 : 0 ); | 
|  | 25 |  |  |  |  | 47 |  | 
|  | 25 |  |  |  |  | 48576 |  | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | ### Setup methods | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | sub new { | 
| 322 | 33 |  |  | 33 |  | 600 | my ($class, %opt) = @_; | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | # TODO check options | 
| 325 | 33 |  | 50 |  |  | 154 | $opt{caller}     ||= [ caller 0 ]; | 
| 326 | 33 |  | 33 |  |  | 291 | $opt{except_rex} ||= qr/^[0-9]+$|^_$/; # no matter what, exempt $_, $1, ... | 
| 327 | 33 |  | 33 |  |  | 186 | $opt{only_rex}   ||= qr/^/; # match all | 
| 328 | 33 |  | 50 |  |  | 168 | $opt{action}     ||= '-below'; | 
| 329 | 33 |  | 66 |  |  | 191 | $opt{target}     ||= $opt{caller}[0]; | 
| 330 | 33 |  | 33 |  |  | 117 | $opt{origin}     ||= join ":", @{$opt{caller}}[1,2]; | 
|  | 33 |  |  |  |  | 184 |  | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | # Skip some well-known variables and functions | 
| 333 |  |  |  |  |  |  | # Format: touch_not{ $name }{ $type } | 
| 334 |  |  |  |  |  |  | # NOTE if you change the list, also change the EXEMPTIONS section in the POD. | 
| 335 | 33 |  |  |  |  | 198 | $opt{touch_not}{$_}{ARRAY}++  for qw( CARP_NOT EXPORT EXPORT_OK ISA ); | 
| 336 | 33 |  |  |  |  | 136 | $opt{touch_not}{$_}{CODE}++   for qw( AUTOLOAD DESTROY import ); | 
| 337 | 33 |  |  |  |  | 112 | $opt{touch_not}{$_}{HASH}++   for qw( OVERLOAD ); | 
| 338 | 33 |  |  |  |  | 200 | $opt{touch_not}{$_}{IO}++     for qw( DATA STDERR STDIN STDOUT ); | 
| 339 | 33 |  |  |  |  | 139 | $opt{touch_not}{$_}{SCALAR}++ for qw( AUTOLOAD a b ); | 
| 340 |  |  |  |  |  |  |  | 
| 341 | 33 |  |  |  |  | 106 | return bless \%opt, $class; | 
| 342 |  |  |  |  |  |  | }; | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | sub set_next { | 
| 345 | 5 |  |  | 5 |  | 10 | my ($self, $next) = @_; | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | carp "probably a bug in namespace::local - uncommitted command replaced in chain" | 
| 348 | 5 | 50 | 66 |  |  | 60 | if $self->{next} and !$self->{next}{done}; | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 5 |  |  |  |  | 14 | $self->{next} = $next; | 
| 351 |  |  |  |  |  |  | }; | 
| 352 |  |  |  |  |  |  |  | 
| 353 |  |  |  |  |  |  | sub is_done { | 
| 354 | 28 |  |  | 28 |  | 117 | return $_[0]->{done}; | 
| 355 |  |  |  |  |  |  | }; | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | sub DESTROY { | 
| 358 | 5 |  |  | 5 |  | 3842 | my $self = shift; | 
| 359 |  |  |  |  |  |  | carp "probably a bug in namespace::local: callback set at $self->{origin} but never executed" | 
| 360 | 5 | 50 | 33 |  |  | 231 | if $self->{todo} and !$self->{done}; | 
| 361 |  |  |  |  |  |  | }; | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | my %known_action; | 
| 364 |  |  |  |  |  |  | $known_action{$_}++ for qw(-above -below -around); | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | # This changes nothing except the object itself | 
| 367 |  |  |  |  |  |  | # input is the same as that of namespace::local->import | 
| 368 |  |  |  |  |  |  | sub parse_options { | 
| 369 | 32 |  |  | 32 |  | 56 | my $self = shift; | 
| 370 |  |  |  |  |  |  |  | 
| 371 |  |  |  |  |  |  | # wrote a Getopt::Long from scratch... | 
| 372 | 32 |  |  |  |  | 96 | while (@_) { | 
| 373 | 27 |  |  |  |  | 48 | my $arg = shift; | 
| 374 | 27 | 100 |  |  |  | 197 | if ( $known_action{$arg} ) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 375 | 15 |  |  |  |  | 142 | $self->{action} = $arg; | 
| 376 |  |  |  |  |  |  | } elsif ($arg eq '-target') { | 
| 377 | 2 |  |  |  |  | 17 | $self->{target} = shift; | 
| 378 |  |  |  |  |  |  | } elsif ($arg eq '-except') { | 
| 379 | 5 |  |  |  |  | 15 | my $cond = shift; | 
| 380 | 5 | 100 |  |  |  | 16 | if (ref $cond eq 'Regexp') { | 
|  |  | 100 |  |  |  |  |  | 
| 381 | 1 |  |  |  |  | 27 | $self->{except_rex} = qr((?:$self->{except_rex})|(?:$cond)); | 
| 382 |  |  |  |  |  |  | } elsif (ref $cond eq 'ARRAY') { | 
| 383 | 3 |  |  |  |  | 9 | $self->touch_not( @$cond ); | 
| 384 |  |  |  |  |  |  | } else { | 
| 385 | 1 |  |  |  |  | 3 | _croak( "-except argument must be regexp or array" ) | 
| 386 |  |  |  |  |  |  | }; | 
| 387 |  |  |  |  |  |  | } elsif ($arg eq '-only') { | 
| 388 | 4 |  |  |  |  | 14 | my $cond = shift; | 
| 389 | 4 | 100 |  |  |  | 13 | if (ref $cond eq 'Regexp') { | 
|  |  | 100 |  |  |  |  |  | 
| 390 | 2 |  |  |  |  | 14 | $self->{only_rex} = $cond; | 
| 391 |  |  |  |  |  |  | } elsif (ref $cond eq 'ARRAY') { | 
| 392 | 1 |  |  |  |  | 2 | $self->restrict( @$cond ); | 
| 393 |  |  |  |  |  |  | } else { | 
| 394 | 1 |  |  |  |  | 2 | _croak( "-only argument must be regexp or array" ) | 
| 395 |  |  |  |  |  |  | }; | 
| 396 |  |  |  |  |  |  | } else { | 
| 397 | 1 |  |  |  |  | 3 | _croak( "unknown option $arg" ); | 
| 398 |  |  |  |  |  |  | }; | 
| 399 |  |  |  |  |  |  | }; | 
| 400 |  |  |  |  |  |  | }; | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | sub touch_not { | 
| 403 | 3 |  |  | 3 |  | 24 | my ($self, @list) = @_; | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 3 |  |  |  |  | 12 | foreach (sigil_to_type(@list)) { | 
| 406 | 3 |  |  |  |  | 24 | $self->{touch_not}{ $_->[0] }{ $_->[1] }++ | 
| 407 |  |  |  |  |  |  | }; | 
| 408 |  |  |  |  |  |  | }; | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | sub restrict { | 
| 411 | 1 |  |  | 1 |  | 3 | my ($self, @list) = @_; | 
| 412 |  |  |  |  |  |  |  | 
| 413 | 1 |  |  |  |  | 4 | foreach (sigil_to_type(@list)) { | 
| 414 | 2 |  |  |  |  | 15 | $self->{restrict_symbols}{ $_->[0] }{ $_->[1] }++ | 
| 415 |  |  |  |  |  |  | }; | 
| 416 |  |  |  |  |  |  | }; | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | # TODO join with @TYPES array from below | 
| 419 |  |  |  |  |  |  | my %sigil = ( | 
| 420 |  |  |  |  |  |  | ''  => 'CODE', | 
| 421 |  |  |  |  |  |  | '$' => 'SCALAR', | 
| 422 |  |  |  |  |  |  | '%' => 'HASH', | 
| 423 |  |  |  |  |  |  | '@' => 'ARRAY', | 
| 424 |  |  |  |  |  |  | ); | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | # returns [ name, type ] for each argument | 
| 427 |  |  |  |  |  |  | sub sigil_to_type { | 
| 428 |  |  |  |  |  |  | map { | 
| 429 | 4 | 100 |  | 4 |  | 9 | /^([\$\@\%]?)(\w+)$/ | 
|  | 6 |  |  |  |  | 37 |  | 
| 430 |  |  |  |  |  |  | or _croak( "cannot exempt sybmol $_: unsupported format" ); | 
| 431 | 5 |  |  |  |  | 30 | [ $2, $sigil{$1} ] | 
| 432 |  |  |  |  |  |  | } @_; | 
| 433 |  |  |  |  |  |  | }; | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | ### Command pattern split into prepare + execute | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  | # input: none | 
| 438 |  |  |  |  |  |  | # output: none | 
| 439 |  |  |  |  |  |  | # side effects: modify target package + setup callback for self->execute | 
| 440 |  |  |  |  |  |  | sub prepare { | 
| 441 | 28 |  |  | 28 |  | 50 | my $self = shift; | 
| 442 |  |  |  |  |  |  |  | 
| 443 | 28 |  |  |  |  | 82 | my $action = $self->{action}; | 
| 444 |  |  |  |  |  |  |  | 
| 445 | 28 |  |  |  |  | 95 | my $table = $self->read_symbols; | 
| 446 |  |  |  |  |  |  |  | 
| 447 | 28 | 100 |  |  |  | 117 | if ($action eq '-around') { | 
|  |  | 100 |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | # Overwrite symbol table with a copy of itself. | 
| 449 |  |  |  |  |  |  | # Somehow this triggers binding of symbols in the code | 
| 450 |  |  |  |  |  |  | #    that was parsed so far (i.e. above the 'use' line) | 
| 451 |  |  |  |  |  |  | #    and undefined symbols (in that area) remain so forever | 
| 452 | 4 |  |  |  |  | 10 | $self->write_symbols( $table ); | 
| 453 |  |  |  |  |  |  | } elsif ( $action eq '-below' ) { | 
| 454 |  |  |  |  |  |  | # Stabilize known functions, leave everything else as is | 
| 455 | 17 |  |  |  |  | 66 | my $func = $self->filter_functions( $table ); | 
| 456 | 17 |  |  |  |  | 47 | $self->write_symbols( $func ); | 
| 457 |  |  |  |  |  |  | }; | 
| 458 |  |  |  |  |  |  |  | 
| 459 | 28 | 100 |  |  |  | 88 | if ($action eq '-above' ) { | 
| 460 |  |  |  |  |  |  | $self->{todo} = sub { | 
| 461 | 7 |  |  | 7 |  | 23 | $self->erase_only_symbols( $table ); | 
| 462 | 7 |  |  |  |  | 38 | }; | 
| 463 |  |  |  |  |  |  | } else { | 
| 464 |  |  |  |  |  |  | $self->{todo} = sub { | 
| 465 | 21 |  |  | 21 |  | 56 | $self->replace_symbols( undef, $table ); | 
| 466 | 21 |  |  |  |  | 137 | }; | 
| 467 |  |  |  |  |  |  | }; | 
| 468 |  |  |  |  |  |  | }; | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | # input: none | 
| 471 |  |  |  |  |  |  | # output: none | 
| 472 |  |  |  |  |  |  | # side effect: modify target package | 
| 473 |  |  |  |  |  |  | sub execute { | 
| 474 | 29 |  |  | 29 |  | 66 | my ($self) = @_; | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  | # always execute stacked commands in reverse order | 
| 477 |  |  |  |  |  |  | $self->{next}->execute | 
| 478 | 29 | 100 |  |  |  | 94 | if $self->{next}; | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | $self->{todo}->() | 
| 481 | 29 | 100 |  |  |  | 156 | unless $self->{done}++; | 
| 482 |  |  |  |  |  |  | }; | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | ### High-level effectful functions | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | # Don't ever touch NAME, PACKAGE, and GLOB that are also known to Perl | 
| 487 |  |  |  |  |  |  | my @TYPES = qw(SCALAR ARRAY HASH CODE IO FORMAT); | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | # In: symbol table hashref | 
| 490 |  |  |  |  |  |  | # Out: side effect | 
| 491 |  |  |  |  |  |  | sub erase_only_symbols { | 
| 492 | 7 |  |  | 7 |  | 15 | my ($self, $table) = @_; | 
| 493 |  |  |  |  |  |  |  | 
| 494 | 7 |  |  |  |  | 14 | my $package = $self->{target}; | 
| 495 | 7 |  |  |  |  | 20 | my @list = keys %$table; | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | # load all necessary symbols | 
| 498 | 7 |  |  |  |  | 21 | my $current = $self->read_symbols( \@list ); | 
| 499 |  |  |  |  |  |  |  | 
| 500 |  |  |  |  |  |  | # filter out what we were going to delete | 
| 501 | 7 |  |  |  |  | 28 | foreach my $name ( @list ) { | 
| 502 |  |  |  |  |  |  | $table->{$name}{$_} and delete $current->{$name}{$_} | 
| 503 | 13 |  | 66 |  |  | 95 | for @TYPES; | 
| 504 |  |  |  |  |  |  | }; | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | # put it back in place | 
| 507 | 7 |  |  |  |  | 21 | $self->replace_symbols( \@list, $current ); | 
| 508 |  |  |  |  |  |  | }; | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | # This method's signature is a bit counterintuitive: | 
| 511 |  |  |  |  |  |  | # $self->replace_symbols( \@names_to_erase, \%new_table_entries ) | 
| 512 |  |  |  |  |  |  | # If first argument is omitted, the whole namespace is scanned instead. | 
| 513 |  |  |  |  |  |  | # Separate erase_symbols and write_symbols turned out to be cumbersome | 
| 514 |  |  |  |  |  |  | #    because of the need to handle granular exclusion list. | 
| 515 |  |  |  |  |  |  | # This method can fill both roles. | 
| 516 |  |  |  |  |  |  | # Providing an empty list would make it just write the symbol table, | 
| 517 |  |  |  |  |  |  | #    whereas an empty hash would mean deletion only. | 
| 518 |  |  |  |  |  |  | sub replace_symbols { | 
| 519 | 30 |  |  | 30 |  | 2158 | my ($self, $clear_list, $table) = @_; | 
| 520 |  |  |  |  |  |  |  | 
| 521 | 30 |  | 100 |  |  | 143 | $clear_list ||= [ $self->read_names ]; | 
| 522 | 30 |  | 100 |  |  | 97 | $table ||= {}; | 
| 523 |  |  |  |  |  |  |  | 
| 524 | 30 |  |  |  |  | 72 | my %uniq; | 
| 525 | 30 |  |  |  |  | 259 | $uniq{$_}++ for keys %$table, @$clear_list; | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | # re-read the symbol table | 
| 528 | 30 |  |  |  |  | 161 | my $old_table = $self->read_symbols( [ keys %uniq ] ); | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  | # create a plan for change | 
| 531 | 30 |  |  |  |  | 121 | my $diff = $self->table_diff( $old_table, $table ); | 
| 532 | 30 | 50 |  |  |  | 138 | return unless keys %$diff; | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 30 |  |  |  |  | 91 | $self->write_symbols( $diff ); | 
| 535 |  |  |  |  |  |  | }; | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  | sub filter_functions { | 
| 538 | 17 |  |  | 17 |  | 39 | my ($self, $table) = @_; | 
| 539 |  |  |  |  |  |  |  | 
| 540 | 17 |  |  |  |  | 27 | my %new_table; | 
| 541 |  |  |  |  |  |  |  | 
| 542 | 17 |  |  |  |  | 72 | foreach (keys %$table) { | 
| 543 |  |  |  |  |  |  | $new_table{$_} = $table->{$_} | 
| 544 | 165 | 100 |  |  |  | 349 | if defined $table->{$_}{CODE}; | 
| 545 |  |  |  |  |  |  | }; | 
| 546 |  |  |  |  |  |  |  | 
| 547 | 17 |  |  |  |  | 43 | return \%new_table; | 
| 548 |  |  |  |  |  |  | }; | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | # Oddly enough, pure | 
| 551 |  |  |  |  |  |  | # In: old and new two symbol table hashrefs | 
| 552 |  |  |  |  |  |  | # Out: part of new table that differs from the old, | 
| 553 |  |  |  |  |  |  | #      with touch_not rules applied | 
| 554 |  |  |  |  |  |  | sub table_diff { | 
| 555 | 30 |  |  | 30 |  | 71 | my ($self, $old_table, $new_table) = @_; | 
| 556 |  |  |  |  |  |  |  | 
| 557 | 30 |  |  |  |  | 49 | my %uniq_name; | 
| 558 | 30 |  |  |  |  | 260 | $uniq_name{$_}++ for keys %$old_table, keys %$new_table; | 
| 559 |  |  |  |  |  |  |  | 
| 560 | 30 |  |  |  |  | 78 | my $touch_not = $self->{touch_not}; | 
| 561 |  |  |  |  |  |  |  | 
| 562 | 30 | 100 |  |  |  | 97 | if (my $restrict = $self->{restrict_symbols}) { | 
| 563 |  |  |  |  |  |  | # If a restriction is in place, invert it and merge into skip | 
| 564 |  |  |  |  |  |  | # TODO write this better | 
| 565 |  |  |  |  |  |  | # TODO does it really belong here? | 
| 566 | 1 |  | 33 |  |  | 7 | $restrict->{$_} or delete $uniq_name{$_} for keys %uniq_name; | 
| 567 | 1 |  |  |  |  | 2 | my %real_touch_not; | 
| 568 | 1 |  |  |  |  | 2 | foreach my $name (keys %uniq_name) { | 
| 569 |  |  |  |  |  |  | # 2 levels of shallow copy is enough | 
| 570 | 2 |  |  |  |  | 4 | foreach my $type( @TYPES ) { | 
| 571 |  |  |  |  |  |  | $real_touch_not{$name}{$type}++ | 
| 572 | 12 | 100 | 66 |  |  | 37 | unless $restrict->{$name}{$type} and not $touch_not->{$name}{$type}; | 
| 573 |  |  |  |  |  |  | }; | 
| 574 |  |  |  |  |  |  | }; | 
| 575 | 1 |  |  |  |  | 3 | $touch_not = \%real_touch_not; | 
| 576 |  |  |  |  |  |  | }; | 
| 577 |  |  |  |  |  |  |  | 
| 578 | 30 |  |  |  |  | 52 | my $diff; | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | # iterate over keys of both, 2 levels deep | 
| 581 | 30 |  |  |  |  | 187 | foreach my $name (sort keys %uniq_name) { | 
| 582 | 268 |  | 50 |  |  | 538 | my $old  = $old_table->{$name} || {}; | 
| 583 | 268 |  | 100 |  |  | 523 | my $new  = $new_table->{$name} || {}; | 
| 584 | 268 |  | 100 |  |  | 744 | my $skip = $touch_not->{$name} || {}; | 
| 585 |  |  |  |  |  |  |  | 
| 586 | 268 |  |  |  |  | 349 | my %uniq_type; | 
| 587 | 268 |  |  |  |  | 967 | $uniq_type{$_}++ for keys %$old, keys %$new; | 
| 588 |  |  |  |  |  |  |  | 
| 589 | 268 |  |  |  |  | 667 | foreach my $type (sort keys %uniq_type) { | 
| 590 | 492 | 100 |  |  |  | 877 | next if $skip->{$type}; | 
| 591 |  |  |  |  |  |  |  | 
| 592 | 467 | 100 |  |  |  | 967 | if (ref $old->{$type} ne ref $new->{$type}) { | 
| 593 |  |  |  |  |  |  | # As nonrefs are not allowed here, | 
| 594 |  |  |  |  |  |  | # this also handles undef vs. defined case | 
| 595 | 71 |  |  |  |  | 138 | $diff->{$name}{$type} = $new->{$type}; | 
| 596 | 71 |  |  |  |  | 153 | next; | 
| 597 |  |  |  |  |  |  | }; | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | # both undef, nothing to see here | 
| 600 | 396 | 50 |  |  |  | 649 | next unless ref $new->{$type}; | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | # pointing to different things | 
| 603 | 396 | 100 |  |  |  | 1001 | if (refaddr $old->{$type} != refaddr $new->{$type}) { | 
| 604 | 4 |  |  |  |  | 11 | $diff->{$name}{$type} = $new->{$type}; | 
| 605 | 4 |  |  |  |  | 8 | next; | 
| 606 |  |  |  |  |  |  | }; | 
| 607 |  |  |  |  |  |  | }; | 
| 608 |  |  |  |  |  |  |  | 
| 609 | 268 | 100 |  |  |  | 637 | if ($diff->{$name}) { | 
| 610 |  |  |  |  |  |  | # if we cannot avoid overwriting, | 
| 611 |  |  |  |  |  |  | # make sure to copy ALL skipped values we know of | 
| 612 | 53 |  |  |  |  | 135 | $diff->{$name}{$_} = $old->{$_} for keys %$skip; | 
| 613 |  |  |  |  |  |  |  | 
| 614 |  |  |  |  |  |  | # removing a scalar copletely didn't work very well on Perl 5.10.1, | 
| 615 |  |  |  |  |  |  | # causing segfaults in unrelated places. | 
| 616 | 53 |  | 100 |  |  | 289 | $diff->{$name}{SCALAR} ||= \undef; | 
| 617 |  |  |  |  |  |  | }; | 
| 618 |  |  |  |  |  |  | }; | 
| 619 |  |  |  |  |  |  |  | 
| 620 | 30 |  |  |  |  | 137 | return $diff; | 
| 621 |  |  |  |  |  |  | }; | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | ### Low-level symbol-table read & write | 
| 624 |  |  |  |  |  |  | ### no magic should happen above this line | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | # NOTE that even here we are in full strict mode | 
| 627 |  |  |  |  |  |  | # The pattern for working with raw data is this: | 
| 628 |  |  |  |  |  |  | # my $value = do { no strict 'refs'; ... }; ## no critic | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | # in: none | 
| 631 |  |  |  |  |  |  | # out: sorted & filtered list of symbols | 
| 632 |  |  |  |  |  |  | sub read_names { | 
| 633 | 53 |  |  | 53 |  | 90 | my $self = shift; | 
| 634 |  |  |  |  |  |  |  | 
| 635 | 53 |  |  |  |  | 85 | my $package = $self->{target}; | 
| 636 | 53 |  |  |  |  | 99 | my $except  = $self->{except_rex}; | 
| 637 | 53 |  |  |  |  | 86 | my $only    = $self->{only_rex}; | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  | my @list = sort grep { | 
| 640 | 2155 | 100 | 100 |  |  | 8713 | /^\w+$/ and $_ !~ $except and $_ =~ $only | 
| 641 | 53 |  |  |  |  | 70 | } do { | 
| 642 | 25 |  |  | 25 |  | 214 | no strict 'refs'; ## no critic | 
|  | 25 |  |  |  |  | 52 |  | 
|  | 25 |  |  |  |  | 3799 |  | 
| 643 | 53 |  |  |  |  | 123 | keys %{ $package."::" }; | 
|  | 53 |  |  |  |  | 774 |  | 
| 644 |  |  |  |  |  |  | }; | 
| 645 |  |  |  |  |  |  |  | 
| 646 | 53 |  |  |  |  | 410 | return @list; | 
| 647 |  |  |  |  |  |  | }; | 
| 648 |  |  |  |  |  |  |  | 
| 649 |  |  |  |  |  |  | # In: symbol list arrayref (read_symbols if none) | 
| 650 |  |  |  |  |  |  | # Out: symbol table hashref | 
| 651 |  |  |  |  |  |  | sub read_symbols { | 
| 652 | 69 |  |  | 69 |  | 163 | my ($self, $list) = @_; | 
| 653 |  |  |  |  |  |  |  | 
| 654 | 69 |  |  |  |  | 123 | my $package = $self->{target}; | 
| 655 | 69 |  | 100 |  |  | 237 | $list ||= [ $self->read_names ]; | 
| 656 | 4 |  |  |  |  | 9 | $list = [ grep { $self->{restrict_symbols}{$_} } @$list ] | 
| 657 | 69 | 100 |  |  |  | 173 | if $self->{restrict_symbols}; | 
| 658 |  |  |  |  |  |  |  | 
| 659 | 69 |  |  |  |  | 105 | my %content; | 
| 660 | 69 |  |  |  |  | 123 | foreach my $name ( @$list ) { | 
| 661 | 528 |  |  |  |  | 753 | foreach my $type (@TYPES) { | 
| 662 | 3168 |  |  |  |  | 3756 | my $value = do { | 
| 663 | 25 |  |  | 25 |  | 187 | no strict 'refs'; ## no critic | 
|  | 25 |  |  |  |  | 62 |  | 
|  | 25 |  |  |  |  | 5173 |  | 
| 664 | 3168 |  |  |  |  | 3463 | *{$package."::".$name}{$type}; | 
|  | 3168 |  |  |  |  | 5772 |  | 
| 665 |  |  |  |  |  |  | }; | 
| 666 | 3168 | 100 |  |  |  | 6317 | $content{$name}{$type} = $value if defined $value; | 
| 667 |  |  |  |  |  |  | }; | 
| 668 |  |  |  |  |  |  | }; | 
| 669 |  |  |  |  |  |  |  | 
| 670 | 69 |  |  |  |  | 173 | return \%content; | 
| 671 |  |  |  |  |  |  | }; | 
| 672 |  |  |  |  |  |  |  | 
| 673 |  |  |  |  |  |  | # writes raw symbols, ignoring touch_not! | 
| 674 |  |  |  |  |  |  | # In: symbol table hashref | 
| 675 |  |  |  |  |  |  | # Out: none | 
| 676 |  |  |  |  |  |  | sub write_symbols { | 
| 677 | 51 |  |  | 51 |  | 101 | my ($self, $table) = @_; | 
| 678 |  |  |  |  |  |  |  | 
| 679 | 51 |  |  |  |  | 100 | my $package = $self->{target}; | 
| 680 |  |  |  |  |  |  |  | 
| 681 | 51 |  |  |  |  | 66 | if (DEBUG) { | 
| 682 |  |  |  |  |  |  | my $old_table = $self->read_symbols; | 
| 683 |  |  |  |  |  |  | $self->message( "package $self->{target} to be altered: ".dump_table($table, $old_table) ) | 
| 684 |  |  |  |  |  |  | }; | 
| 685 |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  |  | 
| 687 | 51 |  |  |  |  | 136 | foreach my $name( keys %$table ) { | 
| 688 | 212 |  |  |  |  | 315 | my $copy = $table->{$name}; | 
| 689 |  |  |  |  |  |  |  | 
| 690 |  |  |  |  |  |  | { | 
| 691 | 25 |  |  | 25 |  | 234 | no strict 'refs'; ## no critic | 
|  | 25 |  |  |  |  | 62 |  | 
|  | 25 |  |  |  |  | 1640 |  | 
|  | 212 |  |  |  |  | 1708 |  | 
| 692 | 212 |  |  |  |  | 249 | delete ${ $package."::" }{$name}; | 
|  | 212 |  |  |  |  | 635 |  | 
| 693 |  |  |  |  |  |  | }; | 
| 694 |  |  |  |  |  |  |  | 
| 695 | 212 |  |  |  |  | 477 | foreach my $type ( keys %$copy ) { | 
| 696 | 406 | 100 |  |  |  | 822 | ref $copy->{$type} or next; | 
| 697 |  |  |  |  |  |  | eval { | 
| 698 |  |  |  |  |  |  | # FIXME on perls 5.014..5.022 this block fails | 
| 699 |  |  |  |  |  |  | # because @ISA is readonly. | 
| 700 |  |  |  |  |  |  | # So we wrap it in eval with no catch | 
| 701 |  |  |  |  |  |  | # until a better solution is done | 
| 702 | 25 |  |  | 25 |  | 188 | no strict 'refs'; ## no critic | 
|  | 25 |  |  |  |  | 48 |  | 
|  | 25 |  |  |  |  | 12852 |  | 
| 703 | 374 |  |  |  |  | 470 | *{ $package."::".$name } = $copy->{$type}; | 
|  | 372 |  |  |  |  | 993 |  | 
| 704 | 372 |  |  |  |  | 1175 | 1; | 
| 705 | 371 | 50 |  |  |  | 513 | } || do { | 
| 706 | 4 |  |  |  |  | 15 | carp "namespace::local: failed to write $package :: $name ($type), but trying to continue: $@"; | 
| 707 |  |  |  |  |  |  | }; | 
| 708 |  |  |  |  |  |  | }; | 
| 709 |  |  |  |  |  |  | }; | 
| 710 |  |  |  |  |  |  | }; | 
| 711 |  |  |  |  |  |  |  | 
| 712 |  |  |  |  |  |  | ### Logging | 
| 713 |  |  |  |  |  |  |  | 
| 714 |  |  |  |  |  |  | sub dump_table { | 
| 715 | 7 |  |  | 3 |  | 35 | my ($table, $old_table) = @_; | 
| 716 |  |  |  |  |  |  |  | 
| 717 | 3 |  |  |  |  | 4 | my @out; | 
| 718 | 3 |  |  |  |  | 10 | foreach my $name( sort keys %$table ) { | 
| 719 | 3 |  |  |  |  | 4 | my $glob = $table->{$name}; | 
| 720 | 3 |  |  |  |  | 10 | foreach my $type( sort keys %$glob ) { | 
| 721 |  |  |  |  |  |  | push @out, "*$name\{$type\}=".( | 
| 722 |  |  |  |  |  |  | $old_table | 
| 723 |  |  |  |  |  |  | ? _is_and_was( $glob->{$type}, $old_table->{$name}{$type} ) | 
| 724 | 6 | 50 |  |  |  | 27 | : _ref2str( $glob->{$type} ) | 
| 725 |  |  |  |  |  |  | ); | 
| 726 |  |  |  |  |  |  | }; | 
| 727 |  |  |  |  |  |  | }; | 
| 728 |  |  |  |  |  |  |  | 
| 729 | 3 |  |  |  |  | 16 | return join ", ", @out; | 
| 730 |  |  |  |  |  |  | }; | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | sub _is_and_was { | 
| 733 | 6 |  |  | 6 |  | 14 | my ($new, $old) = @_; | 
| 734 |  |  |  |  |  |  |  | 
| 735 | 6 | 50 | 100 |  |  | 42 | if ((refaddr $new || 0) != (refaddr $old || 0)) { | 
|  |  |  | 100 |  |  |  |  | 
| 736 | 6 |  |  |  |  | 46 | return _ref2str( $new )."[was: "._ref2str( $old )."]"; | 
| 737 |  |  |  |  |  |  | } else { | 
| 738 | 0 |  |  |  |  | 0 | return _ref2str( $new )."[unchanged]"; | 
| 739 |  |  |  |  |  |  | }; | 
| 740 |  |  |  |  |  |  | }; | 
| 741 |  |  |  |  |  |  |  | 
| 742 |  |  |  |  |  |  | # TODO find existing? | 
| 743 |  |  |  |  |  |  | sub _ref2str { | 
| 744 | 12 |  |  | 12 |  | 25 | my $ref = shift; | 
| 745 |  |  |  |  |  |  |  | 
| 746 | 12 | 50 |  |  |  | 81 | return ref $ref | 
|  |  | 100 |  |  |  |  |  | 
| 747 |  |  |  |  |  |  | ? blessed $ref | 
| 748 |  |  |  |  |  |  | ? sprintf "%s=%s(0x%x)", ref $ref, reftype $ref, refaddr $ref | 
| 749 |  |  |  |  |  |  | : sprintf "%s(0x%x)", ref $ref, refaddr $ref | 
| 750 |  |  |  |  |  |  | : 'undef'; | 
| 751 |  |  |  |  |  |  | }; | 
| 752 |  |  |  |  |  |  |  | 
| 753 |  |  |  |  |  |  | sub message { | 
| 754 | 3 |  |  | 3 |  | 6 | my ($self, $msg) = @_; | 
| 755 |  |  |  |  |  |  |  | 
| 756 | 3 |  |  |  |  | 7 | $msg =~ s/\n$//s; | 
| 757 | 3 |  |  |  |  | 419 | carp "$msg via namespace::local from $self->{origin}"; | 
| 758 |  |  |  |  |  |  | }; | 
| 759 |  |  |  |  |  |  |  | 
| 760 |  |  |  |  |  |  | sub _croak { | 
| 761 | 4 |  |  | 4 |  | 37 | croak ("namespace::local: ".shift); | 
| 762 |  |  |  |  |  |  | }; | 
| 763 |  |  |  |  |  |  |  | 
| 764 |  |  |  |  |  |  | =head1 BUGS | 
| 765 |  |  |  |  |  |  |  | 
| 766 |  |  |  |  |  |  | As of 0.0604, C<-around> hides subroutines defined below its scope end | 
| 767 |  |  |  |  |  |  | from anything above it. | 
| 768 |  |  |  |  |  |  | No solution exists so far. | 
| 769 |  |  |  |  |  |  |  | 
| 770 |  |  |  |  |  |  | This is experimental module. There certainly are more bugs. | 
| 771 |  |  |  |  |  |  |  | 
| 772 |  |  |  |  |  |  | Bug reports, feature requests, suggestions and general feedback welcome at: | 
| 773 |  |  |  |  |  |  |  | 
| 774 |  |  |  |  |  |  | =over | 
| 775 |  |  |  |  |  |  |  | 
| 776 |  |  |  |  |  |  | =item * L | 
| 777 |  |  |  |  |  |  |  | 
| 778 |  |  |  |  |  |  | =item * L | 
| 779 |  |  |  |  |  |  |  | 
| 780 |  |  |  |  |  |  | =item * C | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | =back | 
| 783 |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  | =head1 SUPPORT | 
| 785 |  |  |  |  |  |  |  | 
| 786 |  |  |  |  |  |  | You can find documentation for this module with the C command. | 
| 787 |  |  |  |  |  |  |  | 
| 788 |  |  |  |  |  |  | perldoc namespace::local | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | You can also look for information at: | 
| 791 |  |  |  |  |  |  |  | 
| 792 |  |  |  |  |  |  | =over | 
| 793 |  |  |  |  |  |  |  | 
| 794 |  |  |  |  |  |  | =item * github: | 
| 795 |  |  |  |  |  |  |  | 
| 796 |  |  |  |  |  |  | L | 
| 797 |  |  |  |  |  |  |  | 
| 798 |  |  |  |  |  |  | =item * RT: CPAN's request tracker (report bugs here) | 
| 799 |  |  |  |  |  |  |  | 
| 800 |  |  |  |  |  |  | L | 
| 801 |  |  |  |  |  |  |  | 
| 802 |  |  |  |  |  |  | =item * AnnoCPAN: Annotated CPAN documentation | 
| 803 |  |  |  |  |  |  |  | 
| 804 |  |  |  |  |  |  | L | 
| 805 |  |  |  |  |  |  |  | 
| 806 |  |  |  |  |  |  | =item * CPAN Ratings | 
| 807 |  |  |  |  |  |  |  | 
| 808 |  |  |  |  |  |  | L | 
| 809 |  |  |  |  |  |  |  | 
| 810 |  |  |  |  |  |  | =item * Search CPAN | 
| 811 |  |  |  |  |  |  |  | 
| 812 |  |  |  |  |  |  | L | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | =back | 
| 815 |  |  |  |  |  |  |  | 
| 816 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 817 |  |  |  |  |  |  |  | 
| 818 |  |  |  |  |  |  | L gave the inspiration for this module. | 
| 819 |  |  |  |  |  |  |  | 
| 820 |  |  |  |  |  |  | L, L and probably more also clean | 
| 821 |  |  |  |  |  |  | caller's namespace, but differently. | 
| 822 |  |  |  |  |  |  |  | 
| 823 |  |  |  |  |  |  | L is used as a backend. | 
| 824 |  |  |  |  |  |  |  | 
| 825 |  |  |  |  |  |  | L explains how reading/writing the namespace works. | 
| 826 |  |  |  |  |  |  |  | 
| 827 |  |  |  |  |  |  | =head1 LICENSE AND COPYRIGHT | 
| 828 |  |  |  |  |  |  |  | 
| 829 |  |  |  |  |  |  | Copyright 2018 Konstantin S. Uvarin, C<<  >> | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it | 
| 832 |  |  |  |  |  |  | under the terms of the the Artistic License (2.0). You may obtain a | 
| 833 |  |  |  |  |  |  | copy of the full license at: | 
| 834 |  |  |  |  |  |  |  | 
| 835 |  |  |  |  |  |  | L | 
| 836 |  |  |  |  |  |  |  | 
| 837 |  |  |  |  |  |  | Any use, modification, and distribution of the Standard or Modified | 
| 838 |  |  |  |  |  |  | Versions is governed by this Artistic License. By using, modifying or | 
| 839 |  |  |  |  |  |  | distributing the Package, you accept this license. Do not use, modify, | 
| 840 |  |  |  |  |  |  | or distribute the Package, if you do not accept this license. | 
| 841 |  |  |  |  |  |  |  | 
| 842 |  |  |  |  |  |  | If your Modified Version has been derived from a Modified Version made | 
| 843 |  |  |  |  |  |  | by someone other than you, you are nevertheless required to ensure that | 
| 844 |  |  |  |  |  |  | your Modified Version complies with the requirements of this license. | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  | This license does not grant you the right to use any trademark, service | 
| 847 |  |  |  |  |  |  | mark, tradename, or logo of the Copyright Holder. | 
| 848 |  |  |  |  |  |  |  | 
| 849 |  |  |  |  |  |  | This license includes the non-exclusive, worldwide, free-of-charge | 
| 850 |  |  |  |  |  |  | patent license to make, have made, use, offer to sell, sell, import and | 
| 851 |  |  |  |  |  |  | otherwise transfer the Package with respect to any patent claims | 
| 852 |  |  |  |  |  |  | licensable by the Copyright Holder that are necessarily infringed by the | 
| 853 |  |  |  |  |  |  | Package. If you institute patent litigation (including a cross-claim or | 
| 854 |  |  |  |  |  |  | counterclaim) against any party alleging that the Package constitutes | 
| 855 |  |  |  |  |  |  | direct or contributory patent infringement, then this Artistic License | 
| 856 |  |  |  |  |  |  | to you shall terminate on the date that such litigation is filed. | 
| 857 |  |  |  |  |  |  |  | 
| 858 |  |  |  |  |  |  | Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER | 
| 859 |  |  |  |  |  |  | AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. | 
| 860 |  |  |  |  |  |  | THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | 
| 861 |  |  |  |  |  |  | PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY | 
| 862 |  |  |  |  |  |  | YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR | 
| 863 |  |  |  |  |  |  | CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR | 
| 864 |  |  |  |  |  |  | CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, | 
| 865 |  |  |  |  |  |  | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 866 |  |  |  |  |  |  |  | 
| 867 |  |  |  |  |  |  |  | 
| 868 |  |  |  |  |  |  | =cut | 
| 869 |  |  |  |  |  |  |  | 
| 870 |  |  |  |  |  |  | 1; # End of namespace::local | 
| 871 |  |  |  |  |  |  |  |