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