File Coverage

blib/lib/MouseX/Types/Enum.pm
Criterion Covered Total %
statement 85 88 96.5
branch 19 20 95.0
condition 14 21 66.6
subroutine 19 20 95.0
pod 0 2 0.0
total 137 151 90.7


line stmt bran cond sub pod time code
1             package MouseX::Types::Enum;
2 3     3   264552 use 5.008001;
  3         23  
3              
4 3     3   15 use strict;
  3         6  
  3         58  
5 3     3   14 use warnings;
  3         8  
  3         118  
6              
7             our $VERSION = "2.03";
8              
9 3     3   479 use Mouse;
  3         27559  
  3         16  
10 3     3   1181 use Carp qw/confess/;
  3         7  
  3         169  
11 3     3   1468 use Class::Inspector;
  3         10671  
  3         1085  
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 21     21   71093 my ($child, %build_params) = @_;
35 21         44 my $parent = __PACKAGE__;
36              
37             #@type Mouse::Meta::Class
38 21         72 my $meta = Mouse->init_meta(for_class => $child);
39              
40             $meta->add_around_method_modifier(BUILDARGS => sub {
41 15     15   4992 my ($orig, $class, @params) = @_;
42             # disallow creating instance
43 15 100       45 if (caller(2) ne __PACKAGE__) {
44 1         79 confess sprintf("Cannot call $child->new outside of %s (called in %s)", __PACKAGE__, caller(2) . "")
45             }
46 14         233 return $class->$orig(@params);
47 21         1446 });
48              
49             # this subroutine should be called as `__PACKAGE__->build_enum`.
50 21 50 33     1262 unless (caller() eq $child && !ref($child)) {
51 0         0 confess "Please call as `__PACKAGE__->_build_enum`.";
52             }
53              
54             # check reserved subroutine names
55 21         407 my @child_subs = @{Class::Inspector->functions($child)};
  21         84  
56 21         3123 my @parent_subs = @{Class::Inspector->functions($parent)};
  21         72  
57 21         4370 my %reserved_subs = map {$_ => undef} @parent_subs;
  504         830  
58 21         68 my %dup_allow_subs = map {$_ => undef} (@EXPORT_MOUSE_METHODS, 'meta', 'BUILDARGS');
  294         510  
59 21         59 for my $sub_name (@child_subs) {
60 214 100 100     602 if (exists $reserved_subs{$sub_name} && !exists $dup_allow_subs{$sub_name}) {
61 12         158 confess "`$sub_name` is reserved by " . __PACKAGE__ . ".";
62             }
63             }
64              
65             {
66 3     3   24 no strict 'refs';
  3         6  
  3         113  
  9         19  
67 3     3   19 no warnings 'redefine';
  3         6  
  3         1356  
68             # Overwrite enums
69 9         17 my @enum_subs = grep {$_ =~ /^[A-Z0-9_]+$/} @child_subs;
  158         329  
70 9         18 my %ignored_subs = map {$_ => undef} ('BUILDARGS', @{$build_params{ignore}});
  10         26  
  9         20  
71 9         20 for my $sub_name (@enum_subs) {
72 24 100       57 next if exists $ignored_subs{$sub_name};
73 17         140 my ($id, @args) = $child->$sub_name;
74 17 100       130 confess "seems to be invalid argument." if scalar(@args) % 2;
75 16 100       47 confess "unique id is required for $child->$sub_name ." unless defined $id;
76 15         34 my %args = @args;
77              
78 15 100       49 if (exists $child->_enums->{$id}) {
79 1         14 confess "id `$id` is duplicate."
80             }
81 14         149 my $instance = $child->new(
82             id => $id,
83             %args
84             );
85 14         52 $child->_enums->{$id} = $instance;
86              
87 14         138 *{"${child}\::${sub_name}"} = sub {
88 167     167   36984 my $class = shift;
89 167 100 66     722 if ($class && $class ne $child) {
90 1         18 confess "`${child}::$sub_name` can only be called as static method of `$child`. Please call `${child}->${sub_name}`.";
91             }
92 166         773 return $instance;
93             }
94 14         70 }
95             }
96              
97 6         24 $child->meta->make_immutable;
98             }
99              
100             use overload
101             # MouseX::Types::Enum can only be applied following operators
102 3         24 'eq' => \&_equals,
103             'ne' => \&_not_equals,
104             '==' => \&_equals,
105             '!=' => \&_not_equals,
106             '""' => \&_to_string,
107 3     3   3472 ;
  3         2802  
108              
109             sub get {
110 5     5 0 3182 my ($class, $id) = @_;
111 5 100       26 confess "this is class method." if ref($class);
112 4   33     17 return $class->_enums->{$id} // confess "$id is not found."
113             }
114              
115             sub all {
116 4     4 0 2696 my ($class) = shift;
117 4 100       50 confess "this is class method." if ref($class);
118 3         13 return $class->_enums;
119             }
120              
121             sub _to_string {
122 36     36   3497 my ($self) = @_;
123 36         267 return sprintf("%s[id=%s]", ref($self), $self->id);
124             }
125              
126             sub _equals {
127 66     66   1042 my ($first, $second) = @_;
128 66   100     602 return (ref($first) eq ref($second)) && ($first->id eq $second->id);
129             }
130              
131             sub _not_equals {
132 33     33   70 my ($first, $second) = @_;
133 33         71 return !_equals($first, $second);
134             }
135              
136             sub _enum_meta {
137 36     36   77 my ($class) = @_;
138 36   100     201 return $_ENUM_METAS{$class} //= {};
139             }
140              
141             sub _enums {
142 36     36   64 my ($class) = @_;
143 36   100     84 return $class->_enum_meta->{enums} //= {};
144             }
145              
146             sub _overwrite_flg {
147 0     0     my ($class) = @_;
148 0   0       return $class->_enum_meta->{overwrite_flg} //= {};
149             }
150              
151              
152             1;
153             __END__