File Coverage

blib/lib/Module/Pragma.pm
Criterion Covered Total %
statement 97 97 100.0
branch 36 36 100.0
condition 13 13 100.0
subroutine 19 19 100.0
pod 13 13 100.0
total 178 178 100.0


line stmt bran cond sub pod time code
1             package Module::Pragma;
2              
3 3     3   85484 use 5.010_000;
  3         11  
  3         122  
4              
5 3     3   17 use strict;
  3         6  
  3         108  
6 3     3   15 use warnings;
  3         11  
  3         4729  
7              
8             #use Smart::Comments; # for debugging
9              
10             our $VERSION = '0.02';
11              
12             my %register = ();
13              
14             sub import
15             {
16 12     12   1091 my $class = shift @_;
17              
18 12 100       46 return if $class eq __PACKAGE__;
19              
20 10 100       32 @_ = $class->default_import() unless @_;
21              
22             ### import: \@_, join ' ', caller
23              
24 9         30 $class->check_exclusive(@_);
25              
26 8         34 $^H{$class} |= $class->pack_tags(@_);
27 8         30 $^H{$class} &= ~$class->pack_tags( $class->exclusive_tags(@_) );
28             }
29              
30             sub unimport
31             {
32 5     5   33 my $class = shift @_;
33              
34 5 100       27 return if $class eq __PACKAGE__;
35              
36             ### unimport: \@_, join ' ', caller
37              
38 4 100       15 if(@_){
39 2         5 $class->check_exclusive(@_);
40              
41 2         9 $^H{$class} |= $class->pack_tags( $class->exclusive_tags(@_) );
42 2         6 $^H{$class} &= ~$class->pack_tags(@_);
43             }
44             else{
45 2         59 delete $^H{$class};
46             }
47             }
48              
49             sub enabled
50             {
51 24     24 1 17297 my $class = shift @_;
52              
53 24         71 my $bits = $class->hint(1);
54              
55 24 100       86 $bits &= $class->pack_tags(@_) if @_;
56              
57 24 100       126 return wantarray ? $class->unpack_tags($bits) : $bits;
58             }
59              
60             sub hint
61             {
62 24     24 1 42 my($class, $level) = @_;
63              
64 24         32 my $hint_hash;
65             my $bits;
66 24         31 do {
67 29         29 my $pkg;
68 29         551 ($pkg, $hint_hash) = ( caller ++$level )[0, 10];
69              
70 29 100       997 return undef unless defined $pkg;
71              
72             } until defined( $bits = $hint_hash->{$class} );
73              
74 18         51 return $bits;
75             }
76              
77             sub unknown_tag
78             {
79 2     2 1 5 my($class, $tag) = @_;
80              
81 2         8 $class->_die("unknown subpragma '$tag'");
82             }
83              
84              
85             sub default_import
86             {
87 1     1 1 2 my($class) = @_;
88              
89 1         4 $class->_die('requires explicit arguments');
90             }
91              
92             sub _die
93             {
94 6     6   12 my $class = shift @_;
95              
96 6         37 require Carp;
97 6         1012 Carp::croak("$class: ", @_);
98             }
99              
100              
101             sub register_tags
102             {
103 74     74 1 8033 my($class, @tags) = @_;
104              
105 74   100     168 my $map = $register{$class} //= {};
106              
107 74         110 my $bit_ref = \($map->{___bit___});
108              
109              
110 74         152 while(defined(my $tag = shift @tags)){
111              
112 83 100       120 unless($$bit_ref){
113 7         13 $$bit_ref = 1;
114             }
115             else{
116 76         84 my $old = $$bit_ref;
117 76         72 $$bit_ref <<= 1;
118              
119             #bitmask test
120 76 100       145 if($$bit_ref == 0){
121 1         7 __PACKAGE__->_die("$tag=($old << 1) is not a valid bitmask (integer overflowed?)");
122             }
123             }
124              
125 82 100       151 if($tag =~ /^___/){
126 1         9 __PACKAGE__->_die("'$tag' is not a valid tag name");
127             }
128              
129 81 100 100     207 if(@tags && $tags[0] =~ /^\d+$/){
130 2         5 $$bit_ref = int shift @tags;
131             }
132              
133 81         278 $map->{$tag} = $$bit_ref;
134              
135             }
136              
137 72         252 return $$bit_ref;
138             }
139              
140             sub register_bundle
141             {
142 1     1 1 10 my($class, $bundle, @tags) = @_;
143              
144 1         7 $register{$class}{':' . $bundle} = $class->pack_tags(@tags);
145             }
146              
147             sub register_exclusive
148             {
149 6     6 1 25 my $class = shift @_;
150              
151 6   100     46 my $ex = $register{$class}{___ex___} //= {};
152              
153 6         29 foreach my $x(@_){
154 14         23 foreach my $y(@_){
155 38 100       526 unless($x eq $y){
156 24         25 push @ {$ex->{$x} }, $y;
  24         64  
157 24         94 $ex->{$x, $y} = 1;
158             }
159             }
160             }
161             }
162              
163             sub exclusive_tags
164             {
165 16     16 1 27 my $class = shift @_;
166              
167 16 100       46 my $ex = $register{$class}{___ex___} or return;
168              
169 15         17 my @ex_tags;
170             my %seen;
171              
172             # expansion and regulation
173 15         21 foreach my $tag(grep{ $ex->{$_} } map{ $class->unpack_tags( $class->tag($_) ) } @_)
  18         44  
  15         31  
174             {
175 16         58 push @ex_tags,
176 16         30 grep{ !$seen{$_}++ } # uniq
177 11         19 map { $class->unpack_tags( $class->tag($_) ) }
178 11         14 @{ $ex->{$tag} };
179              
180             }
181 15         68 return @ex_tags;
182             }
183             sub check_exclusive
184             {
185 11     11 1 15 my $class = shift @_;
186              
187 11 100       37 my $ex = $register{$class}{___ex___} or return;
188              
189             # check whether these are exclusive
190 10         19 foreach my $x(@_){
191 10         12 foreach my $y(@_){
192 11 100       72 $class->_die("'$x' and '$y' are exclusive mutually") if $ex->{$x, $y};
193             }
194             }
195             }
196              
197             sub tag
198             {
199 421     421 1 953 my($class, $tag) = @_;
200 421   100     2402 return $register{$class}{$tag} // $class->unknown_tag($tag);
201             }
202              
203             sub tags
204             {
205 48     48 1 76 my($class) = @_;
206              
207 48 100       115 my $map = $register{$class} or return;
208              
209 47   100     135 return grep{ not( /^:/ or /^__/ ) } keys %$map;
  293         1360  
210             }
211              
212              
213             sub pack_tags
214             {
215 40     40 1 63 my $class = shift @_;
216              
217 40         50 my $bits = 0;
218 40         69 foreach my $tag(@_){
219 51         114 $bits |= $class->tag($tag);
220             }
221 39         3320 return $bits;
222             }
223             sub unpack_tags
224             {
225 46     46 1 66 my($class, $bits) = @_;
226              
227 46 100       111 return unless defined $bits;
228              
229 40 100       85 return grep{ $class->tag($_) & $bits or $class->tag($_) == $bits } $class->tags;
  151         270  
230             }
231              
232             1;
233             __END__