File Coverage

blib/lib/MouseX/Types/Enum.pm
Criterion Covered Total %
statement 84 87 96.5
branch 18 20 90.0
condition 16 24 66.6
subroutine 19 20 95.0
pod 0 2 0.0
total 137 153 89.5


line stmt bran cond sub pod time code
1             package MouseX::Types::Enum;
2 3     3   221144 use 5.008001;
  3         20  
3              
4 3     3   14 use strict;
  3         6  
  3         64  
5 3     3   12 use warnings;
  3         4  
  3         101  
6              
7             our $VERSION = "2.01";
8              
9 3     3   432 use Mouse;
  3         22579  
  3         13  
10 3     3   982 use Carp qw/confess/;
  3         6  
  3         169  
11 3     3   1243 use Class::Inspector;
  3         8904  
  3         881  
12              
13             has id => (is => 'ro', isa => 'Str');
14              
15             around BUILDARGS => sub {
16             my ($orig, $class, @params) = @_;
17              
18             # This package is abstract class
19             confess __PACKAGE__ . " is abstract class." if $class eq __PACKAGE__;
20              
21             return $class->$orig(@params);
22             };
23              
24             my @EXPORT_MOUSE_METHODS = qw/
25             extends with has
26             before after around
27             override super
28             augment inner
29             blessed confess
30             /;
31             my %_ENUM_METAS;
32              
33             sub _build_enum {
34 20     20   54317 my ($child, %build_params) = @_;
35 20         33 my $parent = __PACKAGE__;
36              
37             #@type Mouse::Meta::Class
38 20         57 my $meta = Mouse->init_meta(for_class => $child);
39              
40             $meta->add_around_method_modifier(BUILDARGS => sub {
41 16     16   3590 my ($orig, $class, @params) = @_;
42             # disallow creating instance
43 16 100       58 if (caller(2) ne __PACKAGE__) {
44 1         36 confess sprintf("Cannot call $child->new outside of %s (called in %s)", __PACKAGE__, caller(2) . "")
45             }
46 15         203 return $class->$orig(@params);
47 20         1181 });
48              
49             # this subroutine should be called as `__PACKAGE__->build_enum`.
50 20 50 33     1022 unless (caller() eq $child && !ref($child)) {
51 0         0 confess "Please call as `__PACKAGE__->_build_enum`.";
52             }
53              
54             # check reserved subroutine names
55 20         332 my @child_subs = @{Class::Inspector->functions($child)};
  20         65  
56 20         2457 my @parent_subs = @{Class::Inspector->functions($parent)};
  20         49  
57 20         3436 my %reserved_subs = map {$_ => undef} @parent_subs;
  480         616  
58 20         49 my %dup_allow_subs = map {$_ => undef} (@EXPORT_MOUSE_METHODS, 'meta', 'BUILDARGS');
  280         376  
59 20         50 for my $sub_name (@child_subs) {
60 202 100 100     483 if (exists $reserved_subs{$sub_name} && !exists $dup_allow_subs{$sub_name}) {
61 12         132 confess "`$sub_name` is reserved by " . __PACKAGE__ . ".";
62             }
63             }
64              
65             {
66 3     3   20 no strict 'refs';
  3         7  
  3         94  
  8         11  
67 3     3   14 no warnings 'redefine';
  3         5  
  3         1116  
68             # Overwrite enums
69 8         14 my @enum_subs = grep {$_ =~ /^[A-Z0-9_]+$/} @child_subs;
  146         240  
70 8         12 my %ignored_subs = map {$_ => undef} ('BUILDARGS', @{$build_params{ignore}});
  9         20  
  8         16  
71 8         17 for my $sub_name (@enum_subs) {
72 25 100       47 next if exists $ignored_subs{$sub_name};
73 18         94 my ($id, @args) = $child->$sub_name;
74 18 100       110 confess "seems to be invalid argument." if scalar(@args) % 2;
75 17 50       30 confess "unique id is required for $child->$sub_name ." unless $id;
76 17         29 my %args = @args;
77              
78 17 100       40 if (exists $child->_enums->{$id}) {
79 1         12 confess "id `$id` is duplicate."
80             }
81 16         41 $child->_enums->{$id} = undef;
82              
83 16         114 *{"${child}\::${sub_name}"} = sub {
84 172     172   30021 my $class = shift;
85 172 100 66     563 if ($class && $class ne $child) {
86 1         13 confess "`${child}::$sub_name` can only be called as static method of `$child`. Please call `${child}->${sub_name}`.";
87             }
88 171   66     322 return $class->_enums->{$id} //= $class->new(
89             id => $id,
90             %args
91             );
92             }
93 16         69 }
94             }
95              
96 6         18 $child->meta->make_immutable;
97             }
98              
99             use overload
100             # MouseX::Types::Enum can only be applied following operators
101 3         21 'eq' => \&_equals,
102             'ne' => \&_not_equals,
103             '==' => \&_equals,
104             '!=' => \&_not_equals,
105             '""' => \&_to_string,
106 3     3   2818 ;
  3         2339  
107              
108             sub get {
109 5     5 0 2452 my ($class, $id) = @_;
110 5 100       23 confess "this is class method." if ref($class);
111 4   33     8 return $class->_enums->{$id} // confess "$id is not found."
112             }
113              
114             sub all {
115 5     5 0 1884 my ($class) = shift;
116 5 100       22 confess "this is class method." if ref($class);
117 4         25 return $class->_enums;
118             }
119              
120             sub _to_string {
121 213     213   3607 my ($self) = @_;
122 213         1346 return sprintf("%s[id=%s]", ref($self), $self->id);
123             }
124              
125             sub _equals {
126 67     67   1003 my ($first, $second) = @_;
127 67   100     424 return (ref($first) eq ref($second)) && ($first->id eq $second->id);
128             }
129              
130             sub _not_equals {
131 33     33   62 my ($first, $second) = @_;
132 33         57 return !_equals($first, $second);
133             }
134              
135             sub _enum_meta {
136 214     214   288 my ($class) = @_;
137 214   100     1143 return $_ENUM_METAS{$class} //= {};
138             }
139              
140             sub _enums {
141 214     214   379 my ($class) = @_;
142 214   100     310 return $class->_enum_meta->{enums} //= {};
143             }
144              
145             sub _overwrite_flg {
146 0     0     my ($class) = @_;
147 0   0       return $class->_enum_meta->{overwrite_flg} //= {};
148             }
149              
150              
151             1;
152             __END__