File Coverage

blib/lib/unconstant.pm
Criterion Covered Total %
statement 75 102 73.5
branch 13 42 30.9
condition 2 9 22.2
subroutine 17 19 89.4
pod 0 3 0.0
total 107 175 61.1


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