File Coverage

blib/lib/Data/Enum.pm
Criterion Covered Total %
statement 67 67 100.0
branch 12 12 100.0
condition n/a
subroutine 17 17 100.0
pod 1 1 100.0
total 97 97 100.0


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