File Coverage

blib/lib/Data/OptList/Object.pm
Criterion Covered Total %
statement 113 116 97.4
branch 34 36 94.4
condition 7 9 77.7
subroutine 39 41 95.1
pod 13 13 100.0
total 206 215 95.8


line stmt bran cond sub pod time code
1 5     5   1260212 use 5.010;
  5         21  
2 5     5   34 use strict;
  5         8  
  5         138  
3 5     5   25 use warnings;
  5         11  
  5         571  
4              
5             package Data::OptList::Object;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.001003';
9              
10 5     5   2754 use Exporter::Tiny qw( mkopt );
  5         28972  
  5         42  
11 5     5   1604 use List::Util 1.39 qw( first any uniqstr );
  5         103  
  5         485  
12 5     5   64 use Scalar::Util qw( blessed );
  5         9  
  5         337  
13 5     5   34 use re qw( is_regexp );
  5         14  
  5         1123  
14 5     5   2636 use namespace::autoclean;
  5         112177  
  5         24  
15              
16 5     5   422 use constant SLOT_OPTLIST => 0;
  5         13  
  5         369  
17 5     5   31 use constant SLOT_HASHREF => 1;
  5         8  
  5         247  
18 5     5   28 use constant NEXT_SLOT => 2;
  5         10  
  5         690  
19              
20             use overload (
21 2     2   931 q{bool} => sub { !!1 },
22 2     2   913 q{""} => sub { sprintf( 'OptList(%s)', join q{ }, $_[0]->KEYS ) },
23 5         112 q{0+} => 'COUNT',
24             q{%{}} => 'TO_HASHREF',
25             q{@{}} => 'TO_ARRAYREF',
26             q{qr} => 'TO_REGEXP',
27             fallback => 1,
28 5     5   36 );
  5         12  
29              
30             {
31             package Data::OptList::Object::_Pair;
32             our $AUTHORITY = 'cpan:TOBYINK';
33             our $VERSION = '0.001003';
34             use overload (
35 5         33 q{bool} => 'exists',
36             q{""} => 'key',
37             fallback => 1,
38 5     5   1283 );
  5         14  
39 65     65   9649 sub key { shift->[0] }
40 12     12   4039 sub value { shift->[1] }
41 18     18   16564 sub exists { !!1 }
42 2 100   2   364274 sub kind { ref(shift->[1]) or 'undef' }
43 0     0   0 sub TO_JSON { [ @{+shift} ] }
  0         0  
44             }
45              
46             {
47             package Data::OptList::Object::_NoValue;
48             our $AUTHORITY = 'cpan:TOBYINK';
49             our $VERSION = '0.001003';
50             our @ISA = 'Data::OptList::Object::_Pair';
51 3 100   3   10108 sub key { defined $_[0][0] ? $_[0][0] : '' }
52 1     1   3187 sub value { undef; }
53 3     3   311575 sub exists { !!0 }
54 1     1   2822 sub kind { '' }
55 0     0   0 sub TO_JSON { undef; }
56             }
57              
58             sub new {
59 29     29 1 764821 my $class = shift;
60 29 50       120 $class = ref $class if ref $class;
61              
62 29 100 100     2480 my $optlist =
    100 100        
    100 33        
63             ( @_ == 1 and 'ARRAY' eq ref $_[0] ) ? mkopt( $_[0] ) :
64             ( @_ == 1 and 'HASH' eq ref $_[0] ) ? mkopt( $_[0] ) :
65             ( @_ == 1 and blessed $_[0] and $_[0]->DOES(__PACKAGE__) and $_[0]->can('TO_LIST') ) ? mkopt( [ $_[0]->TO_LIST ] ) :
66             mkopt( \@_ );
67 29         1325 bless $_, __PACKAGE__ . '::_Pair' for @$optlist;
68              
69 29         216 my $self = bless \[ 0 .. $class->NEXT_SLOT - 1 ], $class;
70 29         184 $$self->[SLOT_OPTLIST] = $optlist;
71 29         72 $$self->[SLOT_HASHREF] = undef;
72              
73 29         175 &Internals::SvREADONLY( $_, 1 ) for @{ $$self->[SLOT_OPTLIST] };
  29         167  
74 29         110 &Internals::SvREADONLY( $_, 1 ) for $$self->[SLOT_OPTLIST];
75 29         107 &Internals::SvREADONLY( $_, 1 ) for $$self;
76              
77 29         245 return $self;
78             }
79              
80             sub ALL {
81 45     45 1 975 my $self = shift;
82              
83 45         77 return @{ $$self->[SLOT_OPTLIST] };
  45         355  
84             }
85              
86             sub COUNT {
87 4     4 1 3403 my $self = shift;
88              
89 4         9 return scalar @{ $$self->[SLOT_OPTLIST] };
  4         36  
90             }
91              
92             sub KEYS {
93 12     12 1 4508 my $self = shift;
94              
95 12         85 return map $_->[0], $self->ALL;
96             }
97              
98             sub VALUES {
99 1     1 1 848 my $self = shift;
100              
101 1         4 return map $_->[1], $self->ALL;
102             }
103              
104             sub TO_LIST {
105 5     5 1 872 my $self = shift;
106              
107             return map {
108 5         18 my ( $key, $value ) = @$_;
  16         39  
109 16 100       88 defined($value) ? ( $key => $value ) : ( $key );
110             } $self->ALL;
111             }
112              
113             sub TO_ARRAYREF {
114 8     8 1 1733 my $self = shift;
115              
116 8         47 return $$self->[SLOT_OPTLIST];
117             }
118              
119             sub TO_JSON {
120 2     2 1 857 my $self = shift;
121              
122 2         8 return [ $self->TO_LIST ];
123             }
124              
125             sub TO_HASHREF {
126 5     5 1 3229 my $self = shift;
127              
128 5 100       24 if ( not defined $$self->[SLOT_HASHREF] ) {
129             $$self->[SLOT_HASHREF] = +{ map {
130 2         10 my ( $key, $value ) = @$_;
  6         17  
131 6         51 ( $key => $value );
132             } $self->ALL };
133 2         16 &Internals::SvREADONLY( $_, 1 ) for $$self->[SLOT_HASHREF];
134             }
135              
136 5         41 return $$self->[SLOT_HASHREF];
137             }
138              
139             sub TO_REGEXP {
140 5     5 1 1795 my $self = shift;
141              
142 5         22 my $re = join q{|}, map { quotemeta($_) } uniqstr( $self->KEYS );
  10         37  
143              
144 5         134 return qr/\A(?:$re)\z/;
145             }
146              
147             sub GET {
148 44     44 1 1014 my $self = shift;
149 44         100 my $key = shift;
150 44         161 my $is_re = is_regexp $key;
151 44         120 my $is_code = ref($key) eq 'CODE';
152              
153 44 100       202 if ( wantarray ) {
    100          
154             return grep {
155 6 100       23 $is_re ? !!( $_->key =~ $key ) : $is_code ? $key->(@$_) : ( $_->key eq $key )
  18 100       90  
156             } $self->ALL;
157             }
158             elsif ( defined wantarray ) {
159             my $found = first {
160 24 100   24   91 $is_re ? !!( $_->key =~ $key ) : $is_code ? $key->(@$_) : ( $_->key eq $key )
    100          
161 9         72 } $self->ALL;
162 9 100       63 return $found if $found;
163 3 50       41 return bless [ $is_code ? undef : $key ], __PACKAGE__ . '::_NoValue';
164             }
165             else {
166 29         337 return;
167             }
168             }
169              
170             sub HAS {
171 8     8 1 916 my $self = shift;
172 8         18 my $key = shift;
173 8         26 my $is_re = is_regexp $key;
174 8         19 my $is_code = ref($key) eq 'CODE';
175              
176             return any {
177 12 100   12   52 $is_re ? !!( $_->key =~ $key ) : $is_code ? $key->(@$_) : ( $_->key eq $key )
    100          
178 8         79 } $self->ALL;
179             }
180              
181             sub MATCH {
182 4     4 1 884 my $self = shift;
183              
184 4         72 return $self->HAS( @_ );
185             }
186              
187             sub AUTOLOAD {
188 36     36   40427 my $self = shift;
189              
190 36         102 our $AUTOLOAD;
191 36         309 ( my $key = $AUTOLOAD ) =~ s/.*:://;
192              
193 36         168 return $self->GET( $key );
194             }
195              
196             1;
197              
198             __END__