File Coverage

blib/lib/enum.pm
Criterion Covered Total %
statement 64 84 76.1
branch 36 60 60.0
condition 0 2 0.0
subroutine 6 6 100.0
pod n/a
total 106 152 69.7


line stmt bran cond sub pod time code
1             package enum;
2             $enum::VERSION = '1.12';
3 7     7   76081 use 5.006;
  7         55  
4 7     7   96 use strict;
  7         12  
  7         149  
5 7     7   31 use warnings;
  7         11  
  7         283  
6 7     7   40 no strict 'refs'; # Let's just make this very clear right off
  7         13  
  7         250  
7              
8 7     7   64 use Carp;
  7         30  
  7         7681  
9              
10             my $Ident = '[^\W_0-9]\w*';
11              
12             sub ENUM () { 1 }
13             sub BITMASK () { 2 }
14              
15             sub import {
16 20     20   1129 my $class = shift;
17 20 100       252 @_ or return; # Ignore 'use enum;'
18 15         47 my $pkg = caller() . '::';
19 15         20 my $prefix = ''; # default no prefix
20 15         25 my $index = 0; # default start index
21 15         20 my $mode = ENUM; # default to enum
22              
23             ## Pragmas should be as fast as they can be, so we inline some
24             ## pieces.
25 15         34 foreach (@_) {
26             ## Plain tag is most common case
27 210 100       3728 if (/^$Ident$/o) {
    100          
    100          
    50          
28 139         214 my $n = $index;
29              
30 139 50       217 if ($mode == ENUM) {
    0          
31 139         174 $index++;
32             }
33             elsif ($mode == BITMASK) {
34 0   0     0 $index ||= 1;
35 0         0 $index *= 2;
36 0 0       0 if ( $index & ($index - 1) ) {
37 0         0 croak (
38             "$index is not a valid single bitmask "
39             . " (Maybe you overflowed your system's max int value?)"
40             );
41             }
42             }
43             else {
44 0         0 confess qq(Can't Happen: mode $mode invalid);
45             }
46              
47 139         6458 *{"$pkg$prefix$_"} = eval "sub () { $n }";
  139         1223  
48             }
49              
50             ## Index change
51             elsif (/^($Ident)=(-?)(.+)$/o) {
52 28         63 my $name= $1;
53 28         58 my $neg = $2;
54 28         82 $index = $3;
55              
56             ## Convert non-decimal numerics to decimal
57 28 100       117 if ($index =~ /^0x[0-9a-f]+$/i) { ## Hex
    100          
    50          
58 1         3 $index = hex $index;
59             }
60             elsif ($index =~ /^0[0-9]/) { ## Octal
61 1         3 $index = oct $index;
62             }
63             elsif ($index !~ /[^0-9_]/) { ## 123_456 notation
64 26         50 $index =~ s/_//g;
65             }
66              
67             ## Force numeric context, but only in numeric context
68 28 50       61 if ($index =~ /\D/) {
69 0         0 $index = "$neg$index";
70             }
71             else {
72 28         114 $index = "$neg$index";
73 28         64 $index += 0;
74             }
75              
76 28         41 my $n = $index;
77              
78 28 50       73 if ($mode == BITMASK) {
    50          
79 0 0       0 ($index & ($index - 1))
80             and croak "$index is not a valid single bitmask";
81 0         0 $index *= 2;
82             }
83             elsif ($mode == ENUM) {
84 28         33 $index++;
85             }
86             else {
87 0         0 confess qq(Can't Happen: mode $mode invalid);
88             }
89              
90 28         1264 *{"$pkg$prefix$name"} = eval "sub () { $n }";
  28         1564  
91             }
92              
93             ## Prefix/option change
94             elsif (/^([A-Z]*):($Ident)?(=?)(-?)(.*)/) {
95             ## Option change
96 33 100       125 if ($1) {
97 3 50       9 if ($1 eq 'ENUM') { $mode = ENUM; $index = 0 }
  0 50       0  
  0         0  
98 3         5 elsif ($1 eq 'BITMASK') { $mode = BITMASK; $index = 1 }
  3         3  
99 0         0 else { croak qq(Invalid enum option '$1') }
100             }
101              
102 33         118 my $neg = $4;
103              
104             ## Index change too?
105 33 100       94 if ($3) {
106 23 50       71 if (length $5) {
107 23         48 $index = $5;
108              
109             ## Convert non-decimal numerics to decimal
110 23 50       116 if ($index =~ /^0x[0-9a-f]+$/i) { ## Hex
    50          
    50          
111 0         0 $index = hex $index;
112             }
113             elsif ($index =~ /^0[0-9]/) { ## Oct
114 0         0 $index = oct $index;
115             }
116             elsif ($index !~ /[^0-9_]/) { ## 123_456 notation
117 23         46 $index =~ s/_//g;
118             }
119              
120             ## Force numeric context, but only in numeric context
121 23 50       53 if ($index =~ /[^0-9]/) {
122 0         0 $index = "$neg$index";
123             }
124             else {
125 23         57 $index = "$neg$index";
126 23         62 $index += 0;
127             }
128              
129             ## Bitmask mode must check index changes
130 23 100       53 if ($mode == BITMASK) {
131 3 50       445 ($index & ($index - 1))
132             and croak "$index is not a valid single bitmask";
133             }
134             }
135             else {
136 0         0 croak qq(No index value defined after "=");
137             }
138             }
139              
140             ## Incase it's a null prefix
141 30 100       720 $prefix = defined $2 ? $2 : '';
142             }
143              
144             ## A..Z case magic lists
145             elsif (/^($Ident)\.\.($Ident)$/o) {
146             ## Almost never used, so check last
147 10         60 foreach my $name ("$1" .. "$2") {
148 260         444 my $n = $index;
149              
150 260 50       517 if ($mode == BITMASK) {
    50          
151 0 0       0 ($index & ($index - 1))
152             and croak "$index is not a valid single bitmask";
153 0         0 $index *= 2;
154             }
155             elsif ($mode == ENUM) {
156 260         299 $index++;
157             }
158             else {
159 0         0 confess qq(Can't Happen: mode $mode invalid);
160             }
161              
162 260         11330 *{"$pkg$prefix$name"} = eval "sub () { $n }";
  260         1736  
163             }
164             }
165              
166             else {
167 0           croak qq(Can't define "$_" as enum type (name contains invalid characters));
168             }
169             }
170             }
171              
172             1;
173              
174             __END__