File Coverage

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


line stmt bran cond sub pod time code
1             package MouseX::Types::Enum;
2 3     3   234758 use 5.008001;
  3         21  
3              
4 3     3   15 use strict;
  3         4  
  3         53  
5 3     3   13 use warnings;
  3         5  
  3         109  
6              
7             our $VERSION = "2.02";
8              
9 3     3   512 use Mouse;
  3         27598  
  3         11  
10 3     3   1194 use Carp qw/confess/;
  3         6  
  3         178  
11 3     3   1348 use Class::Inspector;
  3         9769  
  3         1035  
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 19     19   52194 my ($child, %build_params) = @_;
35 19         35 my $parent = __PACKAGE__;
36              
37             #@type Mouse::Meta::Class
38 19         50 my $meta = Mouse->init_meta(for_class => $child);
39              
40             $meta->add_around_method_modifier(BUILDARGS => sub {
41 14     14   3867 my ($orig, $class, @params) = @_;
42             # disallow creating instance
43 14 100       42 if (caller(2) ne __PACKAGE__) {
44 1         61 confess sprintf("Cannot call $child->new outside of %s (called in %s)", __PACKAGE__, caller(2) . "")
45             }
46 13         179 return $class->$orig(@params);
47 19         1102 });
48              
49             # this subroutine should be called as `__PACKAGE__->build_enum`.
50 19 50 33     953 unless (caller() eq $child && !ref($child)) {
51 0         0 confess "Please call as `__PACKAGE__->_build_enum`.";
52             }
53              
54             # check reserved subroutine names
55 19         305 my @child_subs = @{Class::Inspector->functions($child)};
  19         73  
56 19         2352 my @parent_subs = @{Class::Inspector->functions($parent)};
  19         61  
57 19         3198 my %reserved_subs = map {$_ => undef} @parent_subs;
  456         630  
58 19         50 my %dup_allow_subs = map {$_ => undef} (@EXPORT_MOUSE_METHODS, 'meta', 'BUILDARGS');
  266         381  
59 19         51 for my $sub_name (@child_subs) {
60 184 100 100     425 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   24 no strict 'refs';
  3         7  
  3         103  
  7         9  
67 3     3   16 no warnings 'redefine';
  3         6  
  3         1176  
68             # Overwrite enums
69 7         11 my @enum_subs = grep {$_ =~ /^[A-Z0-9_]+$/} @child_subs;
  128         211  
70 7         10 my %ignored_subs = map {$_ => undef} ('BUILDARGS', @{$build_params{ignore}});
  8         18  
  7         15  
71 7         16 for my $sub_name (@enum_subs) {
72 21 100       43 next if exists $ignored_subs{$sub_name};
73 15         88 my ($id, @args) = $child->$sub_name;
74 15 100       98 confess "seems to be invalid argument." if scalar(@args) % 2;
75 14 50       27 confess "unique id is required for $child->$sub_name ." unless $id;
76 14         26 my %args = @args;
77              
78 14 100       39 if (exists $child->_enums->{$id}) {
79 1         11 confess "id `$id` is duplicate."
80             }
81 13         121 my $instance = $child->new(
82             id => $id,
83             %args
84             );
85 13         38 $child->_enums->{$id} = $instance;
86              
87 13         119 *{"${child}\::${sub_name}"} = sub {
88 167     167   29722 my $class = shift;
89 167 100 66     567 if ($class && $class ne $child) {
90 1         14 confess "`${child}::$sub_name` can only be called as static method of `$child`. Please call `${child}->${sub_name}`.";
91             }
92 166         653 return $instance;
93             }
94 13         56 }
95             }
96              
97 5         16 $child->meta->make_immutable;
98             }
99              
100             use overload
101             # MouseX::Types::Enum can only be applied following operators
102 3         23 'eq' => \&_equals,
103             'ne' => \&_not_equals,
104             '==' => \&_equals,
105             '!=' => \&_not_equals,
106             '""' => \&_to_string,
107 3     3   3239 ;
  3         2597  
108              
109             sub get {
110 5     5 0 2489 my ($class, $id) = @_;
111 5 100       22 confess "this is class method." if ref($class);
112 4   33     15 return $class->_enums->{$id} // confess "$id is not found."
113             }
114              
115             sub all {
116 4     4 0 1918 my ($class) = shift;
117 4 100       52 confess "this is class method." if ref($class);
118 3         11 return $class->_enums;
119             }
120              
121             sub _to_string {
122 36     36   2866 my ($self) = @_;
123 36         210 return sprintf("%s[id=%s]", ref($self), $self->id);
124             }
125              
126             sub _equals {
127 66     66   847 my ($first, $second) = @_;
128 66   100     455 return (ref($first) eq ref($second)) && ($first->id eq $second->id);
129             }
130              
131             sub _not_equals {
132 33     33   54 my ($first, $second) = @_;
133 33         60 return !_equals($first, $second);
134             }
135              
136             sub _enum_meta {
137 34     34   61 my ($class) = @_;
138 34   100     164 return $_ENUM_METAS{$class} //= {};
139             }
140              
141             sub _enums {
142 34     34   54 my ($class) = @_;
143 34   100     67 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__