File Coverage

blib/lib/Object/Enum.pm
Criterion Covered Total %
statement 100 100 100.0
branch 34 38 89.4
condition 12 16 75.0
subroutine 24 24 100.0
pod 6 6 100.0
total 176 184 95.6


line stmt bran cond sub pod time code
1             package Object::Enum;
2             $Object::Enum::VERSION = '0.074';
3 5     5   89856 use strict;
  5         11  
  5         213  
4 5     5   29 use warnings;
  5         11  
  5         160  
5 5     5   147 use 5.006001;
  5         22  
  5         214  
6              
7 5     5   29 use Carp ();
  5         7  
  5         105  
8 5     5   12689 use Sub::Install ();
  5         12163  
  5         129  
9              
10 5         5525 use base qw(
11             Class::Data::Inheritable
12             Class::Accessor::Fast
13 5     5   42 );
  5         11  
14              
15             __PACKAGE__->mk_classdata($_) for (
16             '_values',
17             '_unset',
18             '_default',
19             '_readonly',
20             );
21              
22             __PACKAGE__->mk_accessors(
23             'value',
24             );
25              
26             __PACKAGE__->_unset(1);
27              
28             use overload (
29 5         42 q{""} => '_stringify',
30             fallback => 1,
31 5     5   51339 );
  5         3438  
32              
33 5         60 use Sub::Exporter -setup => {
34             exports => [ Enum => \&_build_enum ],
35 5     5   5471 };
  5         48702  
36              
37             sub _build_enum {
38 3     3   577 my ($class, undef, $arg) = @_;
39 3 100   11   17 return sub { $class->new({ %$arg, %{shift || {} } }) };
  11         3089  
  11         95  
40             }
41              
42             =head1 NAME
43              
44             Object::Enum - replacement for C<< if ($foo eq 'bar') >>
45              
46             =head1 SYNOPSIS
47              
48             use Object::Enum qw(Enum);
49              
50             my $color = Enum([ qw(red yellow green) ]);
51             # ... later
52             if ($color->is_red) {
53             # it can't be yellow or green
54              
55             =head1 EXPORTS
56              
57             See L for ways to customize this module's
58             exports.
59              
60             =head2 Enum
61              
62             An optional shortcut for C<< Object::Enum->new >>.
63              
64             =head1 CLASS METHODS
65              
66             =head2 new
67              
68             my $obj = Object::Enum->new(\@values);
69             # or
70             $obj = Object::Enum->new(\%arg);
71              
72             Return a new Object::Enum, with one or more sets of possible
73             values.
74              
75             The simplest case is to pass an arrayref, which returns an
76             object capable of having any one of the given values or of
77             being unset.
78              
79             The more complex cases involve passing a hashref, which may
80             have the following keys:
81              
82             =over
83              
84             =item * unset
85              
86             whether this object can be 'unset' (defaults to true)
87              
88             =item * default
89              
90             this object's default value is (defaults to undef)
91              
92             =item * values
93              
94             an arrayref, listing the object's possible values (at least
95             one required)
96              
97             =item * readonly
98              
99             boolean value to indicate if the object is read-only. If set
100             to read-only the objects C and C methods become ineffectual.
101              
102             =back
103              
104             =cut
105              
106             my $id = 0;
107             sub _generate_class {
108 11     11   19 my $class = shift;
109 5     5   2412 no strict 'refs';
  5         11  
  5         3788  
110 11         58 my $gen = sprintf "%s::obj_%08d", $class, ++$id;
111 11         18 push @{$gen."::ISA"}, $class;
  11         381  
112 11         46 return $gen;
113             }
114              
115             sub _mk_values {
116 11     11   40 my $class = shift;
117 11         16 for my $value (keys %{ $class->_values }) {
  11         34  
118             Sub::Install::install_sub({
119             into => $class,
120             as => "set_$value",
121 8     8   1499 code => sub { $_[0]->value($value); return $_[0] },
  8         79  
122 23         843 });
123             Sub::Install::install_sub({
124             into => $class,
125             as => "is_$value",
126 14   50 14   3463 code => sub { (shift->value || '') eq $value },
127 23 50       1866 }) unless $class->can("is_$value");
128             }
129             }
130              
131             sub new {
132 14     14 1 1420 my ($class, $arg) = @_;
133 14   50     39 $arg ||= [];
134 14 100       51 if (ref $arg eq 'ARRAY') {
135 2         6 $arg = { values => $arg };
136             }
137              
138 14 100       20 unless (@{$arg->{values} || []}) {
  14 100       68  
139 1         227 Carp::croak("at least one possible value must be provided");
140             }
141              
142 13 100       49 exists $arg->{unset} or $arg->{unset} = 1;
143 13 100       40 exists $arg->{default} or $arg->{default} = undef;
144 13 100       41 exists $arg->{readonly} or $arg->{readonly} = 0;
145              
146 13 100 66     44 if (!$arg->{unset} && !defined $arg->{default}) {
147 1         195 Carp::croak("must supply a defined default for 'unset' to be false");
148             }
149              
150 12 100 100     45 if (defined($arg->{default}) && ! grep {
  14         62  
151 7         14 $_ eq $arg->{default}
152             } @{$arg->{values}}) {
153 1         179 Carp::croak("default value must be listed in 'values' or undef");
154             }
155              
156 11         38 my $gen = $class->_generate_class;
157 11         241 $gen->_unset($arg->{unset});
158 11         479 $gen->_default($arg->{default});
159 11         1362 $gen->_readonly($arg->{readonly});
160 11         342 $gen->_values({ map { $_ => 1 } @{$arg->{values}} });
  23         123  
  11         63  
161 11         362 $gen->_mk_values;
162              
163             # constructors shouldn't call cloners
164             #return $gen->spawn;
165 11         678 return $gen->_curried;
166             }
167              
168             sub _stringify {
169 9     9   637 my $self = shift;
170 9 50       32 return '(undef)' unless defined $self->value;
171 9         60 return $self->value;
172             }
173              
174             =head1 OBJECT METHODS
175              
176             =head2 spawn
177              
178             =head2 clone
179              
180             my $new = $obj->clone;
181              
182             my $new = $obj->clone($value);
183              
184             Create a new Enum from an existing object, using the same arguments as were
185             originally passed to C<< new >> when that object was created.
186              
187             An optional value may be passed in; this is identical to (but more convenient
188             than) calling C with the same argument on the newly cloned object.
189              
190             This method was formerly named C. That name will still work but is
191             deprecated.
192              
193             =cut
194              
195             sub _curried {
196 18     18   30 my $class = shift;
197 18 100 66     84 my $self = bless {
198             value => ref($class)? $class->value : $class->_default,
199             } => ref($class) || $class;
200 18 100       766 $self->value(@_) if @_;
201              
202 18         86 return $self;
203             }
204              
205             sub clone {
206 7     7 1 1852 my $self = shift->_curried(@_);
207 7 100       24 $self->_readonly(0)
208             if $self->_readonly;
209              
210 7         76 return $self;
211             }
212              
213 5     5   1607 BEGIN { *spawn = \&clone }
214              
215             =head2 readonly
216              
217             my $obj = $obj->readonly(\@values, $value)
218              
219             Creates a read-only enum object, also known as immutable. When enum objects are created
220             with this C<< set_* >> methods, and the C method will become ineffectual.
221              
222             If you want a mutable version, simply clone the immutable version
223              
224             my $new_obj = $readonly_obj->clone;
225             $new_obj->set_red;
226              
227             =cut
228              
229             sub readonly {
230 1     1 1 5493 my $class = shift;
231 1         3 my $values = shift;
232 1         4 my $value = shift;
233              
234 1 50       7 $values = []
235             unless ref($values) eq 'ARRAY';
236              
237 1         8 return $class->new({
238             values => $values,
239             default => $value,
240             readonly => 1
241             });
242             }
243              
244             =head2 value
245              
246             The current value as a string (or undef)
247              
248             Note: don't pass in undef; use the L method instead.
249              
250             =cut
251              
252             sub value {
253 59     59 1 1647 my $self = shift;
254 59 100 100     186 if (@_ && !$self->_readonly) {
255 10         101 my $val = shift;
256 10 50       41 Carp::croak("object $self cannot be set to undef") unless defined $val;
257 10 100       31 unless ($self->_values->{$val}) {
258 1         11 Carp::croak("object $self cannot be set to '$val'");
259             }
260 9         107 return $self->_value_accessor($val);
261             }
262 49         185 return $self->_value_accessor;
263             }
264              
265             =head2 values
266              
267             The possible values for this object
268              
269             =cut
270              
271             sub values {
272 1     1 1 487 my $self = shift;
273 1         2 return keys %{ $self->_values };
  1         5  
274             }
275              
276             =head2 unset
277              
278             Unset the object's value (set to undef)
279              
280             =cut
281              
282             sub unset {
283 3     3 1 315 my $self = shift;
284 3 100       11 unless ($self->_unset) {
285 2         203 Carp::croak("object $self cannot be unset");
286             }
287 1         24 $self->_value_accessor(undef);
288             }
289              
290             =head2 is_*
291              
292             =head2 set_*
293              
294             Automatically generated from the values passed into C<< new
295             >>.
296              
297             None of these methods take any arguments.
298              
299             The C<< set_* >> methods are chainable; that is, they return
300             the object on which they were called. This lets you do useful things like:
301              
302             use Object::Enum Enum => { -as => 'color', values => [qw(red blue)] };
303              
304             print color->set_red->value; # prints 'red'
305              
306             =cut
307              
308             =head1 AUTHOR
309              
310             Hans Dieter Pearcey, C<< >>
311              
312             =head1 BUGS
313              
314             Please report any bugs or feature requests to
315             C, or through the web interface at
316             L.
317             I will be notified, and then you'll automatically be notified of progress on
318             your bug as I make changes.
319              
320             =head1 SUPPORT
321              
322             You can find documentation for this module with the perldoc command.
323              
324             perldoc Object::Enum
325              
326             You can also look for information at:
327              
328             =over 4
329              
330             =item * AnnoCPAN: Annotated CPAN documentation
331              
332             L
333              
334             =item * CPAN Ratings
335              
336             L
337              
338             =item * RT: CPAN's request tracker
339              
340             L
341              
342             =item * Search CPAN
343              
344             L
345              
346             =item * GitHub
347              
348             L
349              
350             =back
351              
352             =head1 ACKNOWLEDGEMENTS
353              
354             =head1 COPYRIGHT & LICENSE
355              
356             Copyright 2006 Hans Dieter Pearcey, all rights reserved.
357              
358             This program is free software; you can redistribute it and/or modify it
359             under the same terms as Perl itself.
360              
361             =cut
362              
363             1; # End of Object::Enum