File Coverage

blib/lib/DDG/Block.pm
Criterion Covered Total %
statement 74 83 89.1
branch 21 30 70.0
condition n/a
subroutine 13 15 86.6
pod 5 8 62.5
total 113 136 83.0


line stmt bran cond sub pod time code
1             package DDG::Block;
2             our $AUTHORITY = 'cpan:DDG';
3             # ABSTRACT: Block to bundle plugins with triggers
4             $DDG::Block::VERSION = '1018';
5 10     10   85579 use Moo::Role;
  10         27290  
  10         71  
6 10     10   4650 use Carp;
  10         28  
  10         806  
7 10     10   1162 use Class::Load ':all';
  10         40143  
  10         1895  
8 10     10   4276 use POSIX qw(strftime);
  10         58557  
  10         88  
9              
10             requires qw(
11             request
12             );
13              
14             sub BUILD {
15 3     3 0 25 my ( $self ) = @_;
16 3         80 $self->_plugin_objs;
17             $self->trace('Loaded block',
18             ref $self,
19             map {
20 3 100       12 $_.':'.( $self->$_ ? 1 : 0 ),
  9         101  
21             } qw( return_one allow_missing_plugins allow_duplicate ),
22             );
23             }
24              
25              
26             has plugins => (
27             #isa => 'ArrayRef[Str|HashRef]',
28             is => 'ro',
29             lazy => 1,
30             builder => '_build_plugins',
31             );
32              
33 0     0   0 sub _build_plugins { die (ref shift)." requires plugins" }
34              
35              
36             has allow_missing_plugins => (
37             #isa => 'Bool',
38             is => 'ro',
39             default => sub { 0 },
40             );
41              
42              
43             has return_one => (
44             #isa => 'Bool',
45             is => 'ro',
46             default => sub { 1 },
47             );
48              
49              
50             has allow_duplicate => (
51             #isa => 'Bool',
52             is => 'ro',
53             default => sub { 0 },
54             );
55              
56              
57             has debug_trace => (
58             #isa => 'Bool',
59             is => 'ro',
60             default => sub { defined $ENV{DDG_BLOCK_TRACE} && $ENV{DDG_BLOCK_TRACE} ? 1 : 0 },
61             );
62              
63             sub trace {
64 596     596 0 926 my $self = shift;
65 596 50       1688 return unless $self->debug_trace;
66 0 0       0 print STDERR ("[".$self->trace_name."] ",join(" ",map { defined $_ ? $_ : 'undef' } @_),"\n");
  0         0  
67             }
68              
69 0     0 0 0 sub trace_name { ref(shift) }
70              
71              
72             has before_build => (
73             #isa => 'CodeRef',
74             is => 'ro',
75             predicate => 'has_before_build',
76             );
77              
78              
79             has after_build => (
80             #isa => 'CodeRef',
81             is => 'ro',
82             predicate => 'has_after_build',
83             );
84              
85              
86             has _plugin_objs => (
87             # like ArrayRef[ArrayRef[$trigger,DDG::Block::Plugin]]',
88             is => 'ro',
89             lazy => 1,
90             builder => '_build__plugin_objs',
91             );
92 34     34 1 722 sub plugin_objs { shift->_plugin_objs }
93              
94             sub _build__plugin_objs {
95 16     16   249 my ( $self ) = @_;
96 16         43 my @plugin_objs;
97 16         38 for (@{$self->plugins}) {
  16         351  
98 36         245 my $class;
99             my %args;
100 36 50       113 if (ref $_ eq 'HASH') {
101 0 0       0 croak "require a class key in hash" unless defined $_->{class};
102 0         0 $class = delete $_->{class};
103 0         0 %args = %{$_};
  0         0  
104             } else {
105 36         76 $class = $_;
106             }
107 36         64 my $plugin;
108 36 50       94 if (ref $class) {
109 0         0 $plugin = $class;
110             } else {
111 36 100       148 unless (try_load_class($class)) {
112 3 100       917 if ($self->allow_missing_plugins) {
113 2 100       9 if (ref $self->allow_missing_plugins eq 'CODE') {
114 1         5 $self->allow_missing_plugins->($self,$class);
115             }
116             } else {
117 1         16 die "Can't load plugin ".$class;
118             }
119 2         20 next;
120             }
121 33         7671 $args{block} = $self;
122 33 100       173 if ($self->has_before_build) {
123 8         26 for ($class) {
124 8         49 $self->before_build->($self,$class);
125             }
126             }
127 33         10028 $plugin = $class->new(\%args);
128             }
129 33 100       22284 if ($self->has_after_build) {
130 8         29 for ($plugin) {
131 8         48 $self->after_build->($self,$plugin);
132             }
133             }
134 33         6870 my @triggers = $self->get_triggers_of_plugin($plugin);
135 33 100       115 @triggers = $self->empty_trigger unless @triggers;
136 33         67 my @parsed_triggers;
137 33         81 for (@triggers) {
138 33         113 push @parsed_triggers, $self->parse_trigger($_);
139             }
140 33 50       184 push @plugin_objs, [
141             \@parsed_triggers,
142             $plugin,
143             ] if @parsed_triggers;
144             }
145 15         102 return \@plugin_objs;
146             }
147              
148              
149             has only_plugin_objs => (
150             is => 'ro',
151             lazy => 1,
152             builder => '_build_only_plugin_objs',
153             );
154             sub _build_only_plugin_objs {
155 1     1   52 my ( $self ) = @_;
156 1         3 my @plugins;
157 1         2 for (@{$self->_plugin_objs}) {
  1         28  
158 2         18 push @plugins, $_->[1];
159             }
160 1         6 return \@plugins;
161             }
162              
163              
164 31     31 1 60 sub get_triggers_of_plugin { shift; shift->get_triggers }
  31         145  
165              
166              
167 30     30 1 55 sub parse_trigger { shift; shift; }
  30         93  
168              
169              
170 2     2 1 6 sub empty_trigger { return undef }
171              
172              
173             sub handle_request_matches {
174 46     46 1 159 my ( $self, $plugin, $request, @args ) = @_;
175 46         124 my $plugin_class = ref $plugin;
176 46         227 $self->trace('Handle request matches:',$plugin_class,"'".$request->query_raw."'",@args);
177 46 50       187 unless ($self->allow_duplicate) {
178 46 100       146 if (grep { $_ eq $plugin_class } @{$request->seen_plugins}) {
  5         42  
  46         1039  
179 1         106 $self->trace("The request already saw",$plugin_class);
180 1         4 return ();
181             }
182             }
183 45         88 push @{$request->seen_plugins}, $plugin_class;
  45         731  
184 45         458 my @results = $plugin->handle_request_matches($request, @args);
185 45         549 $self->trace("Got",scalar @results,"results");
186 45         169 return @results;
187             }
188              
189             around request => sub {
190             my $orig = shift;
191             my ( $self, $request ) = @_;
192             $self->trace( "Query raw:", "'".$request->query_raw."'" );
193             my @results = $orig->(@_);
194             $self->trace( "Query", "'".$request->query_raw."'", "produced", scalar @results, "results" );
195             return @results;
196             };
197              
198             1;
199              
200             __END__