File Coverage

blib/lib/Smart/Dispatch/Table.pm
Criterion Covered Total %
statement 56 88 63.6
branch 9 42 21.4
condition 5 18 27.7
subroutine 17 24 70.8
pod 10 10 100.0
total 97 182 53.3


line stmt bran cond sub pod time code
1             package Smart::Dispatch::Table;
2              
3             BEGIN {
4             *_TYPES = $ENV{PERL_SMART_DISPATCH_TYPE_CHECKS}==42
5             ? sub () { 1 }
6 5 50   5   127 : sub () { 0 };
7             };
8              
9 5     5   76 use 5.010;
  5         14  
  5         170  
10 5     5   116872 use Moo;
  5         299358  
  5         31  
11 5     5   15952 use Carp;
  5         11  
  5         406  
12 5     5   57 use Scalar::Util qw/ refaddr blessed /;
  5         10  
  5         955  
13 5     5   5432 use if _TYPES, 'MooX::Types::MooseLike::Base', ':all';
  5         48  
  5         63  
14              
15             sub _swap
16             {
17             my ($x, $y, $swap) = @_;
18             $swap ? ($y, $x) : ($x, $y);
19             }
20              
21 5     5   5205 use namespace::clean;
  5         79682  
  5         40  
22              
23             BEGIN {
24 5     5   1522 $Smart::Dispatch::Table::AUTHORITY = 'cpan:TOBYINK';
25 5         652 $Smart::Dispatch::Table::VERSION = '0.004';
26             }
27              
28             use overload
29 6     6   1159 '&{}' => sub { my $x=shift; sub { $x->action($_[0]) } },
  6     0   31  
  6         21  
30 0     0   0 '+' => sub { __PACKAGE__->make_combined(reverse _swap(@_)) },
31 0     0   0 '.' => sub { __PACKAGE__->make_combined(_swap(@_)) },
32             '+=' => 'prepend',
33             '.=' => 'append',
34             '~~' => 'exists',
35 0     0   0 'bool' => sub { 1 },
36 5     5   11852 ;
  5         5606  
  5         69  
37              
38             has match_list => (
39             (_TYPES?(isa=>ArrayRef()):()),
40             is => 'rw',
41             required => 1,
42             );
43              
44             sub BUILD
45             {
46 4     4 1 12130 my ($self) = @_;
47 4         27 $self->validate_match_list;
48             }
49              
50             sub make_combined
51             {
52 0     0 1 0 my ($class, @all) = @_;
53 0         0 my $self = $class->new(match_list => []);
54 0         0 $self->append(@all);
55             }
56              
57             sub validate_match_list
58             {
59 4     4 1 8 my ($self) = @_;
60 4         21 my @otherwise = $self->unconditional_matches;
61 4 50       22 if (scalar @otherwise > 1)
62             {
63 0         0 carp "Too many 'otherwise' matches. Only one allowed.";
64             }
65 4 50 66     171 if (@otherwise and refaddr($otherwise[0]) != refaddr($self->match_list->[-1]))
66             {
67 0         0 carp "The 'otherwise' match is not the last match.";
68             }
69             }
70              
71             sub all_matches
72             {
73 1     1 1 13 my ($self) = @_;
74 1         3 @{ $self->match_list };
  1         11  
75             }
76              
77             sub unconditional_matches
78             {
79 5     5 1 11 my ($self) = @_;
80 5         8 grep { $_->is_unconditional } @{ $self->match_list };
  26         64  
  5         58  
81             }
82              
83             sub conditional_matches
84             {
85 1     1 1 2 my ($self) = @_;
86 1         2 grep { !$_->is_unconditional } @{ $self->match_list };
  6         15  
  1         5  
87             }
88              
89             sub exists
90             {
91 17     17 1 491 my ($self, $value, $allow_fails) = @_;
92 17         24 foreach my $cond (@{ $self->match_list })
  17         51  
93             {
94 62 100       192 if ($cond->value_matches($value))
95             {
96 13 100 100     69 if ($allow_fails or not $cond->is_failover)
97             {
98 12         39 return $cond;
99             }
100             else
101             {
102 1         4 return;
103             }
104             }
105             }
106 4         33 return;
107             }
108              
109             sub action
110             {
111 10     10 1 2142 my ($self, $value, @args) = @_;
112 10         26 my $cond = $self->exists($value, 1);
113 10 100       164 return $cond->conduct_dispatch($value, @args) if $cond;
114 1         4 return;
115             }
116              
117             sub append
118             {
119 0     0 1   my $self = shift;
120 0           foreach my $other (@_)
121             {
122 0 0         next unless defined $other;
123 0 0         carp "Cannot add non-reference to dispatch table"
124             unless ref $other;
125 0 0         carp "Cannot add non-blessed reference to dispatch table"
126             unless blessed $other;
127            
128 0 0 0       if ($other->isa(__PACKAGE__))
    0 0        
    0          
129             {
130 0 0         $self->match_list([
131             $self->conditional_matches,
132             $other->conditional_matches,
133             ($self->unconditional_matches ? $self->unconditional_matches : $other->unconditional_matches),
134             ]);
135             }
136             elsif ($other->isa('Smart::Dispatch::Match')
137             and not $other->is_unconditional)
138             {
139 0           $self->match_list([
140             $self->conditional_matches,
141             $other,
142             $self->unconditional_matches,
143             ]);
144             }
145             elsif ($other->isa('Smart::Dispatch::Match')
146             and $other->is_unconditional)
147             {
148 0 0         $self->match_list([
149             $self->conditional_matches,
150             ($self->unconditional_matches ? $self->conditional_matches : $other),
151             ]);
152             }
153             else
154             {
155 0           carp sprintf("Cannot add object of type '%s' to dispatch table", ref $other);
156             }
157             }
158            
159 0           $self->validate_match_list;
160 0           return $self;
161             }
162              
163             sub prepend
164             {
165 0     0 1   my $self = shift;
166 0           foreach my $other (@_)
167             {
168 0 0         next unless defined $other;
169 0 0         carp "Cannot add non-reference to dispatch table"
170             unless ref $other;
171 0 0         carp "Cannot add non-blessed reference to dispatch table"
172             unless blessed $other;
173            
174 0 0 0       if ($other->isa(__PACKAGE__))
    0 0        
    0          
175             {
176 0 0         $self->match_list([
177             $other->conditional_matches,
178             $self->conditional_matches,
179             ($other->unconditional_matches ? $other->unconditional_matches : $self->unconditional_matches),
180             ]);
181             }
182             elsif ($other->isa('Smart::Dispatch::Match')
183             and not $other->is_unconditional)
184             {
185 0           $self->conditions([
186             $other,
187             $self->conditional_matches,
188             $self->unconditional_matches,
189             ]);
190             }
191             elsif ($other->isa('Smart::Dispatch::Match')
192             and $other->is_unconditional)
193             {
194 0           $self->conditions([
195             $self->conditional_matches,
196             $other,
197             ]);
198             }
199             else
200             {
201 0           carp sprintf("Cannot add object of type '%s' to dispatch table", ref $other);
202             }
203             }
204            
205 0           $self->validate_match_list;
206 0           return $self;
207             }
208              
209             __PACKAGE__
210             __END__