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 23 73.9
pod 10 10 100.0
total 97 181 53.5


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   7   118 : sub () { 0 };
7             };
8              
9 5     5   78 use 5.010;
  5         16  
  5         171  
10 5     5   15677 use Moo;
  5         126245  
  5         43  
11 5     5   8870 use Carp;
  5         14  
  5         416  
12 5     5   29 use Scalar::Util qw/ refaddr blessed /;
  5         8  
  5         705  
13 5     5   5605 use if _TYPES, 'MooX::Types::MooseLike::Base', ':all';
  5         49  
  5         67  
14              
15             sub _swap
16             {
17             my ($x, $y, $swap) = @_;
18             $swap ? ($y, $x) : ($x, $y);
19             }
20              
21 5     5   8077 use namespace::clean;
  5         86849  
  5         43  
22              
23             BEGIN {
24 5     5   1883 $Smart::Dispatch::Table::AUTHORITY = 'cpan:TOBYINK';
25 5         792 $Smart::Dispatch::Table::VERSION = '0.005';
26             }
27              
28             use overload
29 6     6   1019 '&{}' => sub { my $x=shift; sub { $x->action($_[0]) } },
  6         38  
  6         26  
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   10054 ;
  5         5720  
  5         66  
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 18845 my ($self) = @_;
47 4         28 $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 10 my ($self) = @_;
60 4         23 my @otherwise = $self->unconditional_matches;
61 4 50       26 if (scalar @otherwise > 1)
62             {
63 0         0 carp "Too many 'otherwise' matches. Only one allowed.";
64             }
65 4 50 66     145 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 11 my ($self) = @_;
74 1         2 @{ $self->match_list };
  1         12  
75             }
76              
77             sub unconditional_matches
78             {
79 5     5 1 10 my ($self) = @_;
80 5         9 grep { $_->is_unconditional } @{ $self->match_list };
  26         78  
  5         61  
81             }
82              
83             sub conditional_matches
84             {
85 1     1 1 4 my ($self) = @_;
86 1         2 grep { !$_->is_unconditional } @{ $self->match_list };
  6         20  
  1         4  
87             }
88              
89             sub exists
90             {
91 17     17 1 893 my ($self, $value, $allow_fails) = @_;
92 17         27 foreach my $cond (@{ $self->match_list })
  17         332  
93             {
94 62 100       257 if ($cond->value_matches($value))
95             {
96 13 100 100     98 if ($allow_fails or not $cond->is_failover)
97             {
98 12         43 return $cond;
99             }
100             else
101             {
102 1         8 return;
103             }
104             }
105             }
106 4         59 return;
107             }
108              
109             sub action
110             {
111 10     10 1 2645 my ($self, $value, @args) = @_;
112 10         33 my $cond = $self->exists($value, 1);
113 10 100       152 return $cond->conduct_dispatch($value, @args) if $cond;
114 1         8 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__