| File: | local/lib/perl5/Sub/Exporter.pm |
| Coverage: | 64.2% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | 6 6 | 54 7 | use 5.006; | |||
| 2 | 6 6 6 | 12 1 60 | use strict; | |||
| 3 | 6 6 6 | 10 2 123 | use warnings; | |||
| 4 | package Sub::Exporter; | |||||
| 5 | { | |||||
| 6 | $Sub::Exporter::VERSION = '0.987'; | |||||
| 7 | } | |||||
| 8 | # ABSTRACT: a sophisticated exporter for custom-built routines | |||||
| 9 | ||||||
| 10 | 6 6 6 | 10 2 47 | use Carp (); | |||
| 11 | 6 6 6 | 621 63 66 | use Data::OptList 0.100 (); | |||
| 12 | 6 6 6 | 15 42 42 | use Params::Util 0.14 (); # _CODELIKE | |||
| 13 | 6 6 6 | 9 25 3182 | use Sub::Install 0.92 (); | |||
| 14 | ||||||
| 15 | ||||||
| 16 | # Given a potential import name, this returns the group name -- if it's got a | |||||
| 17 | # group prefix. | |||||
| 18 | sub _group_name { | |||||
| 19 | 30 | 14 | my ($name) = @_; | |||
| 20 | ||||||
| 21 | 30 | 54 | return if (index q{-:}, (substr $name, 0, 1)) == -1; | |||
| 22 | 8 | 11 | return substr $name, 1; | |||
| 23 | } | |||||
| 24 | ||||||
| 25 | # \@groups is a canonicalized opt list of exports and groups this returns | |||||
| 26 | # another canonicalized opt list with groups replaced with relevant exports. | |||||
| 27 | # \%seen is groups we've already expanded and can ignore. | |||||
| 28 | # \%merge is merged options from the group we're descending through. | |||||
| 29 | sub _expand_groups { | |||||
| 30 | 16 | 12 | my ($class, $config, $groups, $collection, $seen, $merge) = @_; | |||
| 31 | 16 | 27 | $seen ||= {}; | |||
| 32 | 16 | 28 | $merge ||= {}; | |||
| 33 | 16 | 13 | my @groups = @$groups; | |||
| 34 | ||||||
| 35 | 16 | 17 | for my $i (reverse 0 .. $#groups) { | |||
| 36 | 26 | 22 | if (my $group_name = _group_name($groups[$i][0])) { | |||
| 37 | 4 | 5 | my $seen = { %$seen }; # faux-dynamic scoping | |||
| 38 | ||||||
| 39 | 4 | 7 | splice @groups, $i, 1, | |||
| 40 | _expand_group($class, $config, $groups[$i], $collection, $seen, $merge); | |||||
| 41 | } else { | |||||
| 42 | # there's nothing to munge in this export's args | |||||
| 43 | 22 | 38 | next unless my %merge = %$merge; | |||
| 44 | ||||||
| 45 | # we have things to merge in; do so | |||||
| 46 | 0 | 0 | my $prefix = (delete $merge{-prefix}) || ''; | |||
| 47 | 0 | 0 | my $suffix = (delete $merge{-suffix}) || ''; | |||
| 48 | ||||||
| 49 | 0 | 0 | if ( | |||
| 50 | Params::Util::_CODELIKE($groups[$i][1]) ## no critic Private | |||||
| 51 | or | |||||
| 52 | Params::Util::_SCALAR0($groups[$i][1]) ## no critic Private | |||||
| 53 | ) { | |||||
| 54 | # this entry was build by a group generator | |||||
| 55 | 0 | 0 | $groups[$i][0] = $prefix . $groups[$i][0] . $suffix; | |||
| 56 | } else { | |||||
| 57 | 0 | 0 | my $as | |||
| 58 | = ref $groups[$i][1]{-as} ? $groups[$i][1]{-as} | |||||
| 59 | : $groups[$i][1]{-as} ? $prefix . $groups[$i][1]{-as} . $suffix | |||||
| 60 | : $prefix . $groups[$i][0] . $suffix; | |||||
| 61 | ||||||
| 62 | 0 0 | 0 0 | $groups[$i][1] = { %{ $groups[$i][1] }, %merge, -as => $as }; | |||
| 63 | } | |||||
| 64 | } | |||||
| 65 | } | |||||
| 66 | ||||||
| 67 | 16 | 29 | return \@groups; | |||
| 68 | } | |||||
| 69 | ||||||
| 70 | # \@group is a name/value pair from an opt list. | |||||
| 71 | sub _expand_group { | |||||
| 72 | 4 | 3 | my ($class, $config, $group, $collection, $seen, $merge) = @_; | |||
| 73 | 4 | 6 | $merge ||= {}; | |||
| 74 | ||||||
| 75 | 4 | 3 | my ($group_name, $group_arg) = @$group; | |||
| 76 | 4 | 6 | $group_name = _group_name($group_name); | |||
| 77 | ||||||
| 78 | 4 | 7 | Carp::croak qq(group "$group_name" is not exported by the $class module) | |||
| 79 | unless exists $config->{groups}{$group_name}; | |||||
| 80 | ||||||
| 81 | 4 | 15 | return if $seen->{$group_name}++; | |||
| 82 | ||||||
| 83 | 4 | 5 | if (ref $group_arg) { | |||
| 84 | 0 | 0 | my $prefix = (delete $merge->{-prefix}||'') . ($group_arg->{-prefix}||''); | |||
| 85 | 0 | 0 | my $suffix = ($group_arg->{-suffix}||'') . (delete $merge->{-suffix}||''); | |||
| 86 | 0 | 0 | $merge = { | |||
| 87 | %$merge, | |||||
| 88 | %$group_arg, | |||||
| 89 | ($prefix ? (-prefix => $prefix) : ()), | |||||
| 90 | ($suffix ? (-suffix => $suffix) : ()), | |||||
| 91 | }; | |||||
| 92 | } | |||||
| 93 | ||||||
| 94 | 4 | 2 | my $exports = $config->{groups}{$group_name}; | |||
| 95 | ||||||
| 96 | 4 | 17 | if ( | |||
| 97 | Params::Util::_CODELIKE($exports) ## no critic Private | |||||
| 98 | or | |||||
| 99 | Params::Util::_SCALAR0($exports) ## no critic Private | |||||
| 100 | ) { | |||||
| 101 | # I'm not very happy with this code for hiding -prefix and -suffix, but | |||||
| 102 | # it's needed, and I'm not sure, offhand, how to make it better. | |||||
| 103 | # -- rjbs, 2006-12-05 | |||||
| 104 | 0 | 0 | my $group_arg = $merge ? { %$merge } : {}; | |||
| 105 | 0 | 0 | delete $group_arg->{-prefix}; | |||
| 106 | 0 | 0 | delete $group_arg->{-suffix}; | |||
| 107 | ||||||
| 108 | 0 | 0 | my $group = Params::Util::_CODELIKE($exports) ## no critic Private | |||
| 109 | ? $exports->($class, $group_name, $group_arg, $collection) | |||||
| 110 | : $class->$$exports($group_name, $group_arg, $collection); | |||||
| 111 | ||||||
| 112 | 0 | 0 | Carp::croak qq(group generator "$group_name" did not return a hashref) | |||
| 113 | if ref $group ne 'HASH'; | |||||
| 114 | ||||||
| 115 | 0 0 | 0 0 | my $stuff = [ map { [ $_ => $group->{$_} ] } keys %$group ]; | |||
| 116 | return @{ | |||||
| 117 | 0 0 | 0 0 | _expand_groups($class, $config, $stuff, $collection, $seen, $merge) | |||
| 118 | }; | |||||
| 119 | } else { | |||||
| 120 | 4 | 7 | $exports | |||
| 121 | = Data::OptList::mkopt($exports, "$group_name exports"); | |||||
| 122 | ||||||
| 123 | return @{ | |||||
| 124 | 4 4 | 6 11 | _expand_groups($class, $config, $exports, $collection, $seen, $merge) | |||
| 125 | }; | |||||
| 126 | } | |||||
| 127 | } | |||||
| 128 | ||||||
| 129 | sub _mk_collection_builder { | |||||
| 130 | 12 | 8 | my ($col, $etc) = @_; | |||
| 131 | 12 | 12 | my ($config, $import_args, $class, $into) = @$etc; | |||
| 132 | ||||||
| 133 | 12 | 7 | my %seen; | |||
| 134 | sub { | |||||
| 135 | 6 | 2 | my ($collection) = @_; | |||
| 136 | 6 | 6 | my ($name, $value) = @$collection; | |||
| 137 | ||||||
| 138 | 6 | 10 | Carp::croak "collection $name provided multiple times in import" | |||
| 139 | if $seen{ $name }++; | |||||
| 140 | ||||||
| 141 | 6 | 10 | if (ref(my $hook = $config->{collectors}{$name})) { | |||
| 142 | 6 | 16 | my $arg = { | |||
| 143 | name => $name, | |||||
| 144 | config => $config, | |||||
| 145 | import_args => $import_args, | |||||
| 146 | class => $class, | |||||
| 147 | into => $into, | |||||
| 148 | }; | |||||
| 149 | ||||||
| 150 | 6 | 7 | my $error_msg = "collection $name failed validation"; | |||
| 151 | 6 | 10 | if (Params::Util::_SCALAR0($hook)) { ## no critic Private | |||
| 152 | 0 | 0 | Carp::croak $error_msg unless $class->$$hook($value, $arg); | |||
| 153 | } else { | |||||
| 154 | 6 | 14 | Carp::croak $error_msg unless $hook->($value, $arg); | |||
| 155 | } | |||||
| 156 | } | |||||
| 157 | ||||||
| 158 | 6 | 10 | $col->{ $name } = $value; | |||
| 159 | } | |||||
| 160 | 12 | 27 | } | |||
| 161 | ||||||
| 162 | # Given a config and pre-canonicalized importer args, remove collections from | |||||
| 163 | # the args and return them. | |||||
| 164 | sub _collect_collections { | |||||
| 165 | 12 | 8 | my ($config, $import_args, $class, $into) = @_; | |||
| 166 | ||||||
| 167 | my @collections | |||||
| 168 | 6 12 | 10 22 | = map { splice @$import_args, $_, 1 } | |||
| 169 | 12 | 15 | grep { exists $config->{collectors}{ $import_args->[$_][0] } } | |||
| 170 | reverse 0 .. $#$import_args; | |||||
| 171 | ||||||
| 172 | 12 | 16 | unshift @collections, [ INIT => {} ] if $config->{collectors}{INIT}; | |||
| 173 | ||||||
| 174 | 12 | 8 | my $col = {}; | |||
| 175 | 12 | 14 | my $builder = _mk_collection_builder($col, \@_); | |||
| 176 | 12 | 14 | for my $collection (@collections) { | |||
| 177 | 6 | 7 | $builder->($collection) | |||
| 178 | } | |||||
| 179 | ||||||
| 180 | 12 | 52 | return $col; | |||
| 181 | } | |||||
| 182 | ||||||
| 183 | ||||||
| 184 | sub setup_exporter { | |||||
| 185 | 6 | 3 | my ($config) = @_; | |||
| 186 | ||||||
| 187 | 6 | 16 | Carp::croak 'into and into_level may not both be supplied to exporter' | |||
| 188 | if exists $config->{into} and exists $config->{into_level}; | |||||
| 189 | ||||||
| 190 | 6 | 23 | my $as = delete $config->{as} || 'import'; | |||
| 191 | 6 | 21 | my $into | |||
| 192 | = exists $config->{into} ? delete $config->{into} | |||||
| 193 | : exists $config->{into_level} ? caller(delete $config->{into_level}) | |||||
| 194 | : caller(0); | |||||
| 195 | ||||||
| 196 | 6 | 8 | my $import = build_exporter($config); | |||
| 197 | ||||||
| 198 | 6 | 18 | Sub::Install::reinstall_sub({ | |||
| 199 | code => $import, | |||||
| 200 | into => $into, | |||||
| 201 | as => $as, | |||||
| 202 | }); | |||||
| 203 | } | |||||
| 204 | ||||||
| 205 | ||||||
| 206 | sub _key_intersection { | |||||
| 207 | 12 | 9 | my ($x, $y) = @_; | |||
| 208 | 12 60 | 14 39 | my %seen = map { $_ => 1 } keys %$x; | |||
| 209 | 12 6 | 21 17 | my @names = grep { $seen{$_} } keys %$y; | |||
| 210 | } | |||||
| 211 | ||||||
| 212 | # Given the config passed to setup_exporter, which contains sugary opt list | |||||
| 213 | # data, rewrite the opt lists into hashes, catch a few kinds of invalid | |||||
| 214 | # configurations, and set up defaults. Since the config is a reference, it's | |||||
| 215 | # rewritten in place. | |||||
| 216 | my %valid_config_key; | |||||
| 217 | BEGIN { | |||||
| 218 | 54 | 3483 | %valid_config_key = | |||
| 219 | 6 | 7 | map { $_ => 1 } | |||
| 220 | qw(as collectors installer generator exports groups into into_level), | |||||
| 221 | qw(exporter), # deprecated | |||||
| 222 | } | |||||
| 223 | ||||||
| 224 | sub _assert_collector_names_ok { | |||||
| 225 | 12 | 6 | my ($collectors) = @_; | |||
| 226 | ||||||
| 227 | 12 6 | 14 17 | for my $reserved_name (grep { /\A[_A-Z]+\z/ } keys %$collectors) { | |||
| 228 | 0 | 0 | Carp::croak "unknown reserved collector name: $reserved_name" | |||
| 229 | if $reserved_name ne 'INIT'; | |||||
| 230 | } | |||||
| 231 | } | |||||
| 232 | ||||||
| 233 | sub _rewrite_build_config { | |||||
| 234 | 12 | 5 | my ($config) = @_; | |||
| 235 | ||||||
| 236 | 12 24 | 15 37 | if (my @keys = grep { not exists $valid_config_key{$_} } keys %$config) { | |||
| 237 | 0 | 0 | Carp::croak "unknown options (@keys) passed to Sub::Exporter"; | |||
| 238 | } | |||||
| 239 | ||||||
| 240 | 12 | 19 | Carp::croak q(into and into_level may not both be supplied to exporter) | |||
| 241 | if exists $config->{into} and exists $config->{into_level}; | |||||
| 242 | ||||||
| 243 | # XXX: Remove after deprecation period. | |||||
| 244 | 12 | 15 | if ($config->{exporter}) { | |||
| 245 | 0 | 0 | Carp::cluck "'exporter' argument to build_exporter is deprecated. Use 'installer' instead; the semantics are identical."; | |||
| 246 | 0 | 0 | $config->{installer} = delete $config->{exporter}; | |||
| 247 | } | |||||
| 248 | ||||||
| 249 | 12 | 21 | Carp::croak q(into and into_level may not both be supplied to exporter) | |||
| 250 | if exists $config->{into} and exists $config->{into_level}; | |||||
| 251 | ||||||
| 252 | 12 | 11 | for (qw(exports collectors)) { | |||
| 253 | 24 | 35 | $config->{$_} = Data::OptList::mkopt_hash( | |||
| 254 | $config->{$_}, | |||||
| 255 | $_, | |||||
| 256 | [ 'CODE', 'SCALAR' ], | |||||
| 257 | ); | |||||
| 258 | } | |||||
| 259 | ||||||
| 260 | 12 | 16 | _assert_collector_names_ok($config->{collectors}); | |||
| 261 | ||||||
| 262 | 12 | 16 | if (my @names = _key_intersection(@$config{qw(exports collectors)})) { | |||
| 263 | 0 | 0 | Carp::croak "names (@names) used in both collections and exports"; | |||
| 264 | } | |||||
| 265 | ||||||
| 266 | 12 | 18 | $config->{groups} = Data::OptList::mkopt_hash( | |||
| 267 | $config->{groups}, | |||||
| 268 | 'groups', | |||||
| 269 | [ | |||||
| 270 | 'HASH', # standard opt list | |||||
| 271 | 'ARRAY', # standard opt list | |||||
| 272 | 'CODE', # group generator | |||||
| 273 | 'SCALAR', # name of group generation method | |||||
| 274 | ] | |||||
| 275 | ); | |||||
| 276 | ||||||
| 277 | # by default, export nothing | |||||
| 278 | 12 | 34 | $config->{groups}{default} ||= []; | |||
| 279 | ||||||
| 280 | # by default, build an all-inclusive 'all' group | |||||
| 281 | 12 6 | 24 13 | $config->{groups}{all} ||= [ keys %{ $config->{exports} } ]; | |||
| 282 | ||||||
| 283 | 12 | 30 | $config->{generator} ||= \&default_generator; | |||
| 284 | 12 | 28 | $config->{installer} ||= \&default_installer; | |||
| 285 | } | |||||
| 286 | ||||||
| 287 | sub build_exporter { | |||||
| 288 | 12 | 8 | my ($config) = @_; | |||
| 289 | ||||||
| 290 | 12 | 11 | _rewrite_build_config($config); | |||
| 291 | ||||||
| 292 | my $import = sub { | |||||
| 293 | 12 | 9 | my ($class) = shift; | |||
| 294 | ||||||
| 295 | # XXX: clean this up -- rjbs, 2006-03-16 | |||||
| 296 | 12 | 15 | my $special = (ref $_[0]) ? shift(@_) : {}; | |||
| 297 | 12 | 20 | Carp::croak q(into and into_level may not both be supplied to exporter) | |||
| 298 | if exists $special->{into} and exists $special->{into_level}; | |||||
| 299 | ||||||
| 300 | 12 | 16 | if ($special->{exporter}) { | |||
| 301 | 0 | 0 | Carp::cluck "'exporter' special import argument is deprecated. Use 'installer' instead; the semantics are identical."; | |||
| 302 | 0 | 0 | $special->{installer} = delete $special->{exporter}; | |||
| 303 | } | |||||
| 304 | ||||||
| 305 | 12 | 38 | my $into | |||
| 306 | = defined $special->{into} ? delete $special->{into} | |||||
| 307 | : defined $special->{into_level} ? caller(delete $special->{into_level}) | |||||
| 308 | : defined $config->{into} ? $config->{into} | |||||
| 309 | : defined $config->{into_level} ? caller($config->{into_level}) | |||||
| 310 | : caller(0); | |||||
| 311 | ||||||
| 312 | 12 | 32 | my $generator = delete $special->{generator} || $config->{generator}; | |||
| 313 | 12 | 23 | my $installer = delete $special->{installer} || $config->{installer}; | |||
| 314 | ||||||
| 315 | # this builds a AOA, where the inner arrays are [ name => value_ref ] | |||||
| 316 | 12 | 16 | my $import_args = Data::OptList::mkopt([ @_ ]); | |||
| 317 | ||||||
| 318 | # is this right? defaults first or collectors first? -- rjbs, 2006-06-24 | |||||
| 319 | 12 | 17 | $import_args = [ [ -default => undef ] ] unless @$import_args; | |||
| 320 | ||||||
| 321 | 12 | 15 | my $collection = _collect_collections($config, $import_args, $class, $into); | |||
| 322 | ||||||
| 323 | 12 | 15 | my $to_import = _expand_groups($class, $config, $import_args, $collection); | |||
| 324 | ||||||
| 325 | # now, finally $import_arg is really the "to do" list | |||||
| 326 | 12 | 26 | _do_import( | |||
| 327 | { | |||||
| 328 | class => $class, | |||||
| 329 | col => $collection, | |||||
| 330 | config => $config, | |||||
| 331 | into => $into, | |||||
| 332 | generator => $generator, | |||||
| 333 | installer => $installer, | |||||
| 334 | }, | |||||
| 335 | $to_import, | |||||
| 336 | ); | |||||
| 337 | 12 | 20 | }; | |||
| 338 | ||||||
| 339 | 12 | 19 | return $import; | |||
| 340 | } | |||||
| 341 | ||||||
| 342 | sub _do_import { | |||||
| 343 | 12 | 6 | my ($arg, $to_import) = @_; | |||
| 344 | ||||||
| 345 | 12 | 11 | my @todo; | |||
| 346 | ||||||
| 347 | 12 | 7 | for my $pair (@$to_import) { | |||
| 348 | 22 | 15 | my ($name, $import_arg) = @$pair; | |||
| 349 | ||||||
| 350 | 22 | 9 | my ($generator, $as); | |||
| 351 | ||||||
| 352 | 22 | 36 | if ($import_arg and Params::Util::_CODELIKE($import_arg)) { ## no critic | |||
| 353 | # This is the case when a group generator has inserted name/code pairs. | |||||
| 354 | 0 0 | 0 0 | $generator = sub { $import_arg }; | |||
| 355 | 0 | 0 | $as = $name; | |||
| 356 | } else { | |||||
| 357 | 22 | 27 | $import_arg = { $import_arg ? %$import_arg : () }; | |||
| 358 | ||||||
| 359 | 22 | 27 | Carp::croak qq("$name" is not exported by the $arg->{class} module) | |||
| 360 | unless exists $arg->{config}{exports}{$name}; | |||||
| 361 | ||||||
| 362 | 22 | 18 | $generator = $arg->{config}{exports}{$name}; | |||
| 363 | ||||||
| 364 | 22 | 23 | $as = exists $import_arg->{-as} ? (delete $import_arg->{-as}) : $name; | |||
| 365 | } | |||||
| 366 | ||||||
| 367 | 22 | 36 | my $code = $arg->{generator}->( | |||
| 368 | { | |||||
| 369 | class => $arg->{class}, | |||||
| 370 | name => $name, | |||||
| 371 | arg => $import_arg, | |||||
| 372 | col => $arg->{col}, | |||||
| 373 | generator => $generator, | |||||
| 374 | } | |||||
| 375 | ); | |||||
| 376 | ||||||
| 377 | 22 | 30 | push @todo, $as, $code; | |||
| 378 | } | |||||
| 379 | ||||||
| 380 | 12 | 28 | $arg->{installer}->( | |||
| 381 | { | |||||
| 382 | class => $arg->{class}, | |||||
| 383 | into => $arg->{into}, | |||||
| 384 | col => $arg->{col}, | |||||
| 385 | }, | |||||
| 386 | \@todo, | |||||
| 387 | ); | |||||
| 388 | } | |||||
| 389 | ||||||
| 390 | ## Cute idea, possibly for future use: also supply an "unimport" for: | |||||
| 391 | ## no Module::Whatever qw(arg arg arg); | |||||
| 392 | # sub _unexport { | |||||
| 393 | # my (undef, undef, undef, undef, undef, $as, $into) = @_; | |||||
| 394 | # | |||||
| 395 | # if (ref $as eq 'SCALAR') { | |||||
| 396 | # undef $$as; | |||||
| 397 | # } elsif (ref $as) { | |||||
| 398 | # Carp::croak "invalid reference type for $as: " . ref $as; | |||||
| 399 | # } else { | |||||
| 400 | # no strict 'refs'; | |||||
| 401 | # delete &{$into . '::' . $as}; | |||||
| 402 | # } | |||||
| 403 | # } | |||||
| 404 | ||||||
| 405 | ||||||
| 406 | sub default_generator { | |||||
| 407 | 22 | 10 | my ($arg) = @_; | |||
| 408 | 22 | 24 | my ($class, $name, $generator) = @$arg{qw(class name generator)}; | |||
| 409 | ||||||
| 410 | 22 | 19 | if (not defined $generator) { | |||
| 411 | 16 | 46 | my $code = $class->can($name) | |||
| 412 | or Carp::croak "can't locate exported subroutine $name via $class"; | |||||
| 413 | 16 | 8 | return $code; | |||
| 414 | } | |||||
| 415 | ||||||
| 416 | # I considered making this "$class->$generator(" but it seems that | |||||
| 417 | # overloading precedence would turn an overloaded-as-code generator object | |||||
| 418 | # into a string before code. -- rjbs, 2006-06-11 | |||||
| 419 | 6 | 13 | return $generator->($class, $name, $arg->{arg}, $arg->{col}) | |||
| 420 | if Params::Util::_CODELIKE($generator); ## no critic Private | |||||
| 421 | ||||||
| 422 | # This "must" be a scalar reference, to a generator method name. | |||||
| 423 | # -- rjbs, 2006-12-05 | |||||
| 424 | 0 | 0 | return $class->$$generator($name, $arg->{arg}, $arg->{col}); | |||
| 425 | } | |||||
| 426 | ||||||
| 427 | ||||||
| 428 | sub default_installer { | |||||
| 429 | 12 | 4 | my ($arg, $to_export) = @_; | |||
| 430 | ||||||
| 431 | 12 | 1355 | for (my $i = 0; $i < @$to_export; $i += 2) { | |||
| 432 | 22 | 20 | my ($as, $code) = @$to_export[ $i, $i+1 ]; | |||
| 433 | ||||||
| 434 | # Allow as isa ARRAY to push onto an array? | |||||
| 435 | # Allow into isa HASH to install name=>code into hash? | |||||
| 436 | ||||||
| 437 | 22 | 31 | if (ref $as eq 'SCALAR') { | |||
| 438 | 0 | 0 | $$as = $code; | |||
| 439 | } elsif (ref $as) { | |||||
| 440 | 0 | 0 | Carp::croak "invalid reference type for $as: " . ref $as; | |||
| 441 | } else { | |||||
| 442 | 22 | 35 | Sub::Install::reinstall_sub({ | |||
| 443 | code => $code, | |||||
| 444 | into => $arg->{into}, | |||||
| 445 | as => $as | |||||
| 446 | }); | |||||
| 447 | } | |||||
| 448 | } | |||||
| 449 | } | |||||
| 450 | ||||||
| 451 | sub default_exporter { | |||||
| 452 | 0 | 0 | Carp::cluck "default_exporter is deprecated; call default_installer instead; the semantics are identical"; | |||
| 453 | 0 | 0 | goto &default_installer; | |||
| 454 | } | |||||
| 455 | ||||||
| 456 | ||||||
| 457 | setup_exporter({ | |||||
| 458 | exports => [ | |||||
| 459 | qw(setup_exporter build_exporter), | |||||
| 460 | _import => sub { build_exporter($_[2]) }, | |||||
| 461 | ], | |||||
| 462 | groups => { | |||||
| 463 | all => [ qw(setup_exporter build_export) ], | |||||
| 464 | }, | |||||
| 465 | collectors => { -setup => \&_setup }, | |||||
| 466 | }); | |||||
| 467 | ||||||
| 468 | sub _setup { | |||||
| 469 | 6 | 4 | my ($value, $arg) = @_; | |||
| 470 | ||||||
| 471 | 6 | 11 | if (ref $value eq 'HASH') { | |||
| 472 | 6 6 | 2 14 | push @{ $arg->{import_args} }, [ _import => { -as => 'import', %$value } ]; | |||
| 473 | 6 | 15 | return 1; | |||
| 474 | } elsif (ref $value eq 'ARRAY') { | |||||
| 475 | 0 0 | push @{ $arg->{import_args} }, | ||||
| 476 | [ _import => { -as => 'import', exports => $value } ]; | |||||
| 477 | 0 | return 1; | ||||
| 478 | } | |||||
| 479 | 0 | return; | ||||
| 480 | } | |||||
| 481 | ||||||
| 482 | ||||||
| 483 | ||||||
| 484 | "jn8:32"; # <-- magic true value | |||||
| 485 | ||||||