File Coverage

blib/lib/DDG/Request.pm
Criterion Covered Total %
statement 70 80 87.5
branch 20 20 100.0
condition 6 8 75.0
subroutine 15 19 78.9
pod 2 4 50.0
total 113 131 86.2


line stmt bran cond sub pod time code
1             package DDG::Request;
2             our $AUTHORITY = 'cpan:DDG';
3             # ABSTRACT: A request to DuckDuckGo itself, so the query itself and parameter around the query defining him
4             $DDG::Request::VERSION = '1018';
5 10     10   134291 use Moo;
  10         73689  
  10         65  
6 10     10   12286 use utf8;
  10         39  
  10         82  
7              
8              
9             #
10             # QUERY
11             #
12             ###############################
13              
14              
15             has query_raw => (
16             is => 'ro',
17             required => 1,
18             );
19              
20             my $whitespaces = qr{\s+};
21             my $whitespaces_matches = qr{($whitespaces)};
22             my $whitespaces_dashes = qr{[\s\-]+};
23             my $non_alphanumeric_ascii = qr{[\x00-\x1f\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x81\x{a7}]+};
24              
25              
26             has query_raw_parts => (
27             is => 'ro',
28             lazy => 1,
29             builder => '_build_query_raw_parts',
30             );
31             sub _build_query_raw_parts {
32             [
33 54     54   1201 split(/$whitespaces_matches/,shift->query_raw)
34             ]
35             }
36              
37              
38             has query_parts => (
39             is => 'ro',
40             lazy => 1,
41             builder => '_build_query_parts',
42             );
43             sub _build_query_parts {
44 18     18   195 my $x;
45             [
46 52         239 grep { ( $x += length ) < 500 } # 500 matches the internal query max
47 100         377 grep { ! /$whitespaces/ }
48 107         206 grep { length }
49 18         43 @{shift->query_raw_parts}
  18         341  
50             ]
51             }
52              
53              
54             has query_parts_lc => (
55             is => 'ro',
56             lazy => 1,
57             builder => '_build_query_parts_lc',
58             );
59             sub _build_query_parts_lc {
60             [
61 0         0 map { lc }
62 0     0   0 @{shift->query_parts}
  0         0  
63             ]
64             }
65              
66              
67             has triggers => (
68             is => 'ro',
69             lazy => 1,
70             builder => '_build_triggers',
71             );
72             sub _build_triggers {
73 49     49   13328 my ( $self ) = @_;
74 49         98 my @parts = @{$self->query_raw_parts};
  49         951  
75 49 100       258 return {} if not scalar @parts;
76 48 100       163 my $x = $parts[0] eq '' ? 2 : 0;
77 48         95 my %triggers;
78 48         208 for ($x..(scalar @parts-1)) {
79 261 100       599 unless ($_ % 2) {
80 149         379 $triggers{$_} = $self->generate_triggers($parts[$_]);
81             }
82             }
83 48         405 return \%triggers;
84             }
85              
86              
87             sub generate_triggers {
88 149     149 1 337 my $part = lc $_[1];
89 149         203 my %parts;
90 149         327 ++$parts{$part};
91 149 100       411 $part =~ s/^!//go && ++$parts{$part};
92 149 100       397 $part =~ s/\?$//go && ++$parts{$part};
93             # Look for non-word characters, except single quotes, e.g. can't, John's
94 149 100       424 if ($part =~ /[^\w']/o) {
95             # The split could be part of the if but it would leave single quotes
96             # in the resulting terms.
97 10         71 my @boundary_words = split /\W+/o, $part ;
98 10         58 ++$parts{$_} for @boundary_words;
99 10         51 ++$parts{join('', @boundary_words)};
100 10         47 ++$parts{join(' ', @boundary_words)};
101             }
102 149         736 return [keys %parts];
103             }
104              
105              
106             has remainder => (
107             is => 'rwp',
108             lazy => 1
109             );
110              
111             sub generate_remainder {
112 24     24 1 65 my ( $self, $from_pos, $to_pos ) = @_;
113 24 100       79 $to_pos = $from_pos unless defined $to_pos;
114 24         42 my @query_raw_parts = @{$self->query_raw_parts};
  24         465  
115 24         269 my $max = scalar @query_raw_parts-1;
116 24         46 my $remainder = '';
117 24 100 100     191 if ( $to_pos < $max && ( $from_pos == 0 || ( $from_pos == 2 && $query_raw_parts[0] eq '' ) ) ) {
    100 100        
    100          
118 10         57 $remainder = join('',@query_raw_parts[$to_pos+1..$max]);
119 10         51 $remainder =~ s/^\s//;
120             } elsif ( $max % 2 ? $to_pos == $max-1 : $to_pos == $max ) {
121 11         55 $remainder = join('',@query_raw_parts[0..$from_pos-1]);
122 11         58 $remainder =~ s/\s$//;
123             } else {
124 3         40 my $left_remainder = join('',@query_raw_parts[0..$from_pos-1]);
125 3         14 my $right_remainder = join('',@query_raw_parts[$to_pos+1..$max]);
126 3         15 $left_remainder =~ s/\s$//;
127 3         12 $right_remainder =~ s/^\s//;
128 3         11 $remainder = $left_remainder.' '.$right_remainder;
129             }
130 24         100 $self->_set_remainder($remainder);
131 24         105 return $remainder;
132             }
133              
134              
135             has matched_trigger => (
136             is => 'ro',
137             lazy => 1,
138             builder => 1
139             );
140              
141             sub _build_matched_trigger {
142 0     0   0 my $self = shift;
143              
144 0   0     0 my $r = $self->remainder || '';
145 0         0 my $qr = $self->query_raw;
146 0         0 $qr =~ s/\s*\Q$r\E\s*//i;
147 0         0 return $qr;
148             }
149              
150              
151             has query => (
152             is => 'ro',
153             lazy => 1,
154             builder => '_build_query',
155             );
156             sub _build_query {
157 12     12   43110 join(' ',@{shift->query_parts})
  12         282  
158             }
159              
160              
161             has query_lc => (
162             is => 'ro',
163             lazy => 1,
164             builder => '_build_query_lc',
165             );
166             sub _build_query_lc {
167             lc(shift->query)
168 11     11   7287 }
169              
170              
171             has query_nowhitespace => (
172             is => 'ro',
173             lazy => 1,
174             builder => '_build_query_nowhitespace',
175             );
176             sub _build_query_nowhitespace {
177 11     11   7553 for (shift->query) {
178 11         199 s/$whitespaces//g;
179 11         96 return $_;
180             }
181             }
182              
183              
184             has query_nowhitespace_nodash => (
185             is => 'ro',
186             lazy => 1,
187             builder => '_build_query_nowhitespace_nodash',
188             );
189             sub _build_query_nowhitespace_nodash {
190 11     11   7251 for (shift->query) {
191 11         200 s/$whitespaces_dashes//g;
192 11         138 return $_;
193             }
194             }
195              
196              
197             has query_clean => (
198             is => 'ro',
199             lazy => 1,
200             builder => '_build_query_clean',
201             );
202             sub _build_query_clean {
203 11     11   7460 for (shift->query_lc) {
204 11         179 s/$non_alphanumeric_ascii//g;
205 11         78 s/$whitespaces/ /g;
206 11         93 return $_;
207             }
208             }
209              
210              
211             has words => (
212             is => 'ro',
213             lazy => 1,
214             builder => '_build_words',
215             );
216             sub _build_words {
217             [
218 11     11   366 grep { length }
  29         251  
219             split(/$whitespaces/,shift->query_clean)
220             ]
221             }
222              
223              
224             has wordcount => (
225             is => 'ro',
226             lazy => 1,
227             builder => '_build_wordcount',
228             );
229 11     11   7076 sub _build_wordcount { scalar @{shift->words} }
  11         293  
230              
231              
232             has seen_plugins => (
233             is => 'rw',
234             lazy => 1,
235             builder => '_build_seen_plugins',
236             );
237 41     41   503 sub _build_seen_plugins {[]}
238              
239             #
240             # LANGUAGE / LOCATION / IP
241             #
242             ###############################
243              
244             # DDG::Language TODO
245             has language => (
246             #isa => 'DDG::Language',
247             is => 'ro',
248             predicate => 'has_language',
249             );
250 0     0 0   sub lang { shift->language }
251              
252             has location => (
253             #isa => 'DDG::Location',
254             is => 'ro',
255             predicate => 'has_location',
256             );
257 0     0 0   sub loc { shift->location }
258              
259             1;
260              
261             __END__