File Coverage

blib/lib/unconstant.pm
Criterion Covered Total %
statement 79 105 75.2
branch 13 42 30.9
condition 2 9 22.2
subroutine 19 20 95.0
pod 0 3 0.0
total 113 179 63.1


line stmt bran cond sub pod time code
1             package unconstant;
2 6     6   344968 use Sub::Util ();
  6         1925  
  6         133  
3 6     6   37 use warnings;
  6         11  
  6         151  
4              
5 6     6   88 use constant ();
  6         15  
  6         214  
6             my $constant_import;
7             my $installed;
8              
9 6     6   164 BEGIN { $constant_import = \&constant::import };
10              
11 6     6   96 use 5.020;
  6         27  
12 6     6   28 use strict;
  6         21  
  6         108  
13 6     6   29 use warnings;
  6         10  
  6         1913  
14              
15             our $VERSION = '0.09';
16              
17             our %declared;
18              
19             #=======================================================================
20              
21             # Some names are evil choices.
22             my %keywords = map +($_, 1), qw{ BEGIN INIT CHECK END DESTROY AUTOLOAD UNITCHECK };
23              
24             my %forced_into_main = map +($_, 1),
25             qw{ STDIN STDOUT STDERR ARGV ARGVOUT ENV INC SIG };
26              
27             my %forbidden = (%keywords, %forced_into_main);
28              
29             my $normal_constant_name = qr/^_?[^\W_0-9]\w*\z/;
30             my $tolerable = qr/^[A-Za-z_]\w*\z/;
31             my $boolean = qr/^[01]?\z/;
32              
33             sub unconstant_import {
34 9 100   9 0 1258 return if $installed;
35 6         62 *constant::import = *constant_import;
36 6         151 $installed = 1;
37             }
38              
39             sub unconstant_unimport {
40 2 50   2 0 15 return unless $installed;
41 6     6   44 no warnings 'redefine';
  6         13  
  6         1086  
42 2         6 *constant::import = $constant_import;
43 2         38 $installed = 0;
44             }
45              
46             sub constant_import {
47              
48 6     6 0 70395 my $caller = caller();
49 6         12 my $package = shift;
50 6         10 my $flush_mro;
51 6 50       23 return unless @_;
52 6         14 my $multiple = ref $_[0];
53              
54 6         8 my $constants;
55 6 50       15 if ( $multiple ) {
56 0 0       0 if ($multiple ne 'HASH') {
57 0         0 require Carp;
58 0         0 Carp::croak("Invalid reference type '".ref(shift)."' not 'HASH'");
59             }
60 0         0 $constants = shift;
61             }
62             else {
63 6 50       16 unless (defined $_[0]) {
64 0         0 require Carp;
65 0         0 Carp::croak("Can't use undef as constant name");
66             }
67 6         16 $constants->{+shift} = undef;
68             }
69              
70              
71 6         50 my $symtab;
72             {
73 6     6   41 no strict 'refs';
  6         10  
  6         777  
  6         8  
74 6         10 $symtab = \%{$caller . "::"};
  6         19  
75             }
76              
77 6         21 foreach my $name ( keys %$constants ) {
78 6         8 my $pkg = $caller;
79 6         12 my $symtab = $symtab;
80 6         7 my $orig_name = $name;
81              
82 6 100       40 if ($name =~ s/(.*)(?:::|')(?=.)//s) {
83 2         6 $pkg = $1;
84 2 50       7 if ($pkg ne $caller) {
85 6     6   40 no strict 'refs';
  6         19  
  6         1494  
86 2         3 $symtab = \%{$pkg . '::'};
  2         6  
87             }
88             }
89              
90             # Normal constant name
91 6 50 33     62 if ($name =~ $normal_constant_name and !$forbidden{$name}) {
    0 0        
    0          
    0          
    0          
92             # Everything is okay
93             }
94            
95             # Name forced into main, but we're not in main. Fatal.
96             elsif ($forced_into_main{$name} and $pkg ne 'main') {
97 0         0 require Carp;
98 0         0 Carp::croak("Constant name '$name' is forced into main::");
99             }
100            
101             # Starts with double underscore. Fatal.
102             elsif ($name =~ /^__/) {
103 0         0 require Carp;
104 0         0 Carp::croak("Constant name '$name' begins with '__'");
105             }
106            
107             # Maybe the name is tolerable
108             elsif ($name =~ $tolerable) {
109             # Then we'll warn only if you've asked for warnings
110 0 0       0 if (warnings::enabled()) {
111 0 0       0 if ($keywords{$name}) {
    0          
112 0         0 warnings::warn("Constant name '$name' is a Perl keyword");
113             } elsif ($forced_into_main{$name}) {
114 0         0 warnings::warn("Constant name '$name' is " .
115             "forced into package main::");
116             }
117             }
118             }
119              
120             # Looks like a boolean
121             # use constant FRED == fred;
122             elsif ($name =~ $boolean) {
123 0         0 require Carp;
124 0 0       0 if (@_) {
125 0         0 Carp::croak("Constant name '$name' is invalid");
126             }
127             else {
128 0         0 Carp::croak("Constant name looks like boolean value");
129             }
130             }
131             else {
132             # Must have bad characters
133 0         0 require Carp;
134 0         0 Carp::croak("Constant name '$name' has invalid characters");
135             }
136              
137 6     6   54 no strict 'refs';
  6         13  
  6         645  
138 6         18 my $full_name = "${pkg}::$name";
139              
140             # This is required to fool namespace::autoclean
141 6         11 my $const_name = "constant::$name";
142              
143 6         15 $declared{$full_name}++;
144 6 50 33     25 if ($multiple || @_ == 1) {
    0          
145 6 50       24 my $scalar = $multiple ? $constants->{$orig_name} : $_[0];
146              
147             #$symtab->{$name} = sub () { $scalar };
148             {
149 6     6   42 no warnings;
  6         14  
  6         587  
  6         9  
150 6     4   123 *$full_name = Sub::Util::set_prototype( '', Sub::Util::set_subname("constant::$name", sub { $scalar } ) );
  4     4   881  
151             }
152 6         27 ++$flush_mro->{$pkg};
153             }
154             elsif (@_) {
155 0         0 my @list = @_;
156             {
157 6     6   40 no warnings;
  6         11  
  6         1216  
  0         0  
158 0     0   0 *$full_name = Sub::Util::set_prototype( '', Sub::Util::set_subname("constant::$name", sub { @list } ) );
  0         0  
159             }
160 0         0 $flush_mro->{$pkg}++;
161             }
162             else {
163 0         0 die 'should never hit this';
164             }
165             }
166             # Flush the cache exactly once if we make any direct symbol table changes.
167 6 50       19 if ($flush_mro) {
168 6         2902 mro::method_changed_in($_) for keys %$flush_mro;
169             }
170             }
171              
172              
173             {
174 6     6   41 no warnings;
  6         12  
  6         542  
175             *import = \&unconstant_import;
176             *unimport = \&unconstant_unimport;
177             }
178              
179              
180             1;
181              
182             __END__