File Coverage

blib/lib/Data/Enum.pm
Criterion Covered Total %
statement 75 75 100.0
branch 12 12 100.0
condition n/a
subroutine 19 19 100.0
pod 1 1 100.0
total 107 107 100.0


line stmt bran cond sub pod time code
1             package Data::Enum;
2              
3             # ABSTRACT: immutable enumeration classes
4              
5 1     1   646 use v5.10;
  1         3  
6              
7 1     1   4 use strict;
  1         1  
  1         16  
8 1     1   3 use warnings;
  1         2  
  1         18  
9              
10 1     1   420 use Package::Stash;
  1         6655  
  1         32  
11 1     1   6 use List::Util 1.45 qw/ any uniqstr /;
  1         12  
  1         90  
12 1     1   5 use Scalar::Util qw/ blessed refaddr /;
  1         2  
  1         41  
13              
14             # RECOMMEND PREREQ: Package::Stash::XS
15              
16 1     1   4 use overload ();
  1         2  
  1         14  
17              
18 1     1   4 use constant TRUE => 1;
  1         1  
  1         42  
19 1     1   4 use constant FALSE => 0;
  1         2  
  1         614  
20              
21             our $VERSION = 'v0.2.7';
22              
23              
24              
25             sub new {
26 5     5 1 1339 my $this = shift;
27              
28 5         11 my @values = uniqstr( sort map { "$_" } @_ );
  11         40  
29              
30 5 100       23 die "has no values" unless @values;
31              
32 4 100   10   18 die "values must be alphanumeric" if any{ /\W/ } @values;
  10         28  
33              
34 3         11 my $key = join chr(28), @values;
35              
36 3         4 state %Cache;
37 3         16 state $Counter = 1;
38              
39              
40 3 100       8 if ( my $name = $Cache{$key} ) {
41 1         5 return $name;
42             }
43              
44 2         4 my $name = "Data::Enum::" . $Counter++;
45              
46 2         18 my $base = Package::Stash->new($name);
47              
48             my $_make_symbol = sub {
49 6     6   9 my ($value) = @_;
50 6         9 my $self = bless \$value, "${name}::${value}";
51 6         13 Internals::SvREADONLY($value, 1);
52 6         14 return $self;
53 2         7 };
54              
55             my $_make_predicate = sub {
56 9     9   13 my ($value) = @_;
57 9         23 return "is_" . $value;
58 2         14 };
59              
60             $base->add_symbol(
61             '&new',
62             sub {
63 19     19   1046 my ( $class, $value ) = @_;
64             state $symbols = {
65             map {
66 19         24 $_ => $_make_symbol->($_)
  6         11  
67             } @values
68             };
69 19 100       47 exists $symbols->{"$value"} or die "invalid value: '$value'";
70 18         98 return $symbols->{"$value"};
71             }
72 2         41 );
73              
74 2     2   13 $base->add_symbol( '&values', sub { return @values });
  2         22  
75              
76 2     1   14 $base->add_symbol( '&predicates', sub { return map { $_make_predicate->($_) } @values } );
  1         2  
  3         5  
77              
78             my $match = sub {
79 10     10   751 my ( $self, $arg ) = @_;
80 10 100       85 return blessed($arg)
81             ? refaddr($arg) == refaddr($self)
82             : $arg eq $$self;
83 2         6 };
84              
85 2         11 $base->add_symbol( '&MATCH', $match );
86              
87             $name->overload::OVERLOAD(
88 6     6   176 q{""} => sub { my ($self) = @_; return $$self; },
  6         21  
89             q{eq} => $match,
90             q{ne} => sub {
91 7     7   396 my ( $self, $arg ) = @_;
92 7 100       53 return blessed($arg)
93             ? refaddr($arg) != refaddr($self)
94             : $arg ne $$self;
95             },
96 2         35 );
97              
98 2         99 for my $value (@values) {
99 6         13 my $predicate = $_make_predicate->($value);
100 6         36 $base->add_symbol( '&' . $predicate, \&FALSE );
101 6         11 my $elem = "${name}::${value}";
102 6         29 my $subtype = Package::Stash->new($elem);
103 6         60 $subtype->add_symbol( '@ISA', [$name] );
104 6         55 $subtype->add_symbol( '&' . $predicate, \&TRUE );
105             }
106              
107 2         12 return $Cache{$key} = $name;
108             }
109              
110              
111             1;
112              
113             __END__