File Coverage

blib/lib/WWW/Wordnik/API.pm
Criterion Covered Total %
statement 154 179 86.0
branch 49 94 52.1
condition 7 30 23.3
subroutine 29 31 93.5
pod 17 17 100.0
total 256 351 72.9


line stmt bran cond sub pod time code
1             package WWW::Wordnik::API;
2              
3 5     5   119641 use warnings;
  5         14  
  5         174  
4 5     5   30 use strict;
  5         7  
  5         171  
5 5     5   26 use Carp;
  5         16  
  5         472  
6              
7 5     5   5691 use LWP::UserAgent;
  5         306217  
  5         158  
8              
9 5     5   4148 use version; our $VERSION = qv('0.0.5');
  5         11217  
  5         31  
10              
11             use constant {
12 5         14373 API_VERSION => 4,
13             API_BASE_URL => 'http://api.wordnik.com',
14             API_KEY => 'YOUR KEY HERE',
15             API_FORMAT => 'json',
16             CACHE => 10,
17             DEBUG => 0,
18             MODULE_NAME => 'WWW::Wordnik::API',
19             USE_JSON => 0,
20 5     5   547 };
  5         11  
21              
22             sub _fields {
23 4     4   144 { server_uri => API_BASE_URL . q{/v} . API_VERSION,
24             api_key => API_KEY,
25             version => API_VERSION,
26             format => API_FORMAT,
27             cache => CACHE,
28             debug => DEBUG,
29             _formats => { json => 1, xml => 1, perl => 1 },
30             _versions => { 1 => 0, 2 => 0, 3 => 1, 4 => 1 },
31             _cache => { max => CACHE, requests => {}, data => [] },
32             _user_agent => LWP::UserAgent->new(
33             agent => 'Perl-' . MODULE_NAME . q{/} . $VERSION,
34             default_headers => HTTP::Headers->new( ':api_key' => API_KEY ),
35             ),
36             _json => USE_JSON,
37             };
38             }
39              
40             sub new {
41 4     4 1 2844 my ( $class, %args ) = @_;
42              
43 4         18 my $self = bless( _fields(), $class );
44              
45 4         13477 eval { require JSON; JSON->import() };
  4         37  
  4         32  
46 4 50       477 $self->{_json} = 'available' unless $@;
47              
48 4         14 bless $self, $class;
49              
50 4         26 while ( my ( $key, $value ) = each %args ) {
51 0 0 0     0 croak "Can't access '$key' field in class $class"
52             if !exists $self->{$key}
53             or $key =~ m/^_/;
54              
55 0         0 $self->$key($value);
56             }
57              
58 4         16 return $self;
59             }
60              
61             sub server_uri {
62 22     22 1 40 my ( $self, $uri ) = @_;
63              
64 22 100       60 if ( defined $uri ) {
65 2         6 $self->{server_uri} = $uri;
66             }
67 22         79 return $self->{server_uri};
68             }
69              
70             sub api_key {
71 2     2 1 5 my ( $self, $key ) = @_;
72              
73 2 100       6 if ( defined $key ) {
74 1         7 $self->{_user_agent}->default_headers->header( ':api_key' => $key );
75 1         77 $self->{api_key} = $key;
76             }
77 2         9 return $self->{api_key};
78             }
79              
80             sub version {
81 2     2 1 5 my ( $self, $version ) = @_;
82              
83 2 100       6 if ( defined $version ) {
84 1 50       165 croak "Unsupported api version: '$version'"
85             unless $self->{_versions}->{$version};
86 0         0 $self->{version} = $version;
87             }
88 1         4 return $self->{version};
89             }
90              
91             sub format {
92 40     40 1 644 my ( $self, $format ) = @_;
93              
94 40 100       81 if ( defined $format ) {
95 2 50       10 croak "Unsupported api format: '$format'"
96             unless $self->{_formats}->{$format};
97              
98 2 100       11 $self->_json_available
99             if 'perl' eq $format;
100              
101 2         22 $self->{format} = $format;
102             }
103 40         131 return $self->{format};
104             }
105              
106             sub cache {
107 3     3 1 11 my ( $self, $cache ) = @_;
108              
109 3 100 66     40 if ( defined $cache and $cache =~ m/\d+/ ) {
110 2         11 $self->{cache} = $self->{_cache}->{max} = $cache;
111             }
112 3         14 return $self->{cache};
113             }
114              
115             sub debug {
116 2     2 1 12 my ( $self, $debug ) = @_;
117              
118 2 50       11 if ( defined $debug ) {
119 2         5 $self->{debug} = $debug;
120             }
121 2         6 return $self->{debug};
122             }
123              
124             sub word {
125 3     3 1 45 my ( $self, $word, %args ) = @_;
126              
127 3 50       8 return unless $word;
128              
129 3         32 my %parameters = (
130             useSuggest => { true => 0, false => 1 },
131             literal => { true => 1, false => 0 },
132             );
133              
134 3         13 for ( keys %args ) {
135 2 50 33     24 croak "Invalid argument key or value: '$_'"
136             unless exists $parameters{$_}
137             and exists $parameters{$_}->{ $args{$_} };
138             }
139              
140 3         6 my $query = $word;
141 3         16 $query .= "?$_=$args{$_}" for keys %args;
142              
143 3         10 return $self->_send_request( $self->_build_request( 'word', $query ) );
144             }
145              
146             sub phrases {
147 2     2 1 7 my ( $self, $word, %args ) = @_;
148              
149 2 50       25 return unless $word;
150              
151 2         6 my %parameters = ( count => 10 );
152              
153 2         8 for ( keys %args ) {
154 1 50 33     14 croak "Invalid argument key or value: '$_'"
155             unless exists $parameters{$_}
156             and $args{$_} =~ m/\d+/;
157             }
158              
159 2         7 my $query = "$word/phrases";
160 2         8 $query .= "?$_=$args{$_}" for keys %args;
161              
162 2         8 return $self->_send_request( $self->_build_request( 'word', $query ) );
163             }
164              
165             sub definitions {
166 3     3 1 12 my ( $self, $word, %args ) = @_;
167              
168 3 50       8 return unless $word;
169              
170 3         31 my %parameters = (
171             count => 5,
172             partOfSpeech => {
173             noun => 0,
174             verb => 0,
175             adjective => 0,
176             adverb => 0,
177             idiom => 0,
178             article => 0,
179             abbreviation => 0,
180             preposition => 0,
181             prefix => 0,
182             interjection => 0,
183             suffix => 0,
184             }
185             );
186              
187 3         7 my $query = "$word/definitions";
188              
189 3         10 for ( keys %args ) {
190              
191 2 100       9 if ( 'count' eq $_ ) {
    50          
192 1 50       8 croak "Invalid argument key or value: '$_'"
193             unless $args{count} =~ m/\d/;
194 1         5 $query .= "?count=$args{count}";
195             }
196             elsif ( 'ARRAY' eq ref $args{partOfSpeech} ) {
197 1         2 for my $type ( @{ $args{partOfSpeech} } ) {
  1         2  
198 11 50       29 croak "Invalid argument key or value: '$type'"
199             unless exists $parameters{partOfSpeech}->{$type};
200             }
201 1         3 $query .= "?partOfSpeech=" . join q{,}, @{ $args{partOfSpeech} };
  1         8  
202             }
203             else {
204 0         0 croak "Parameter 'partOfSpeech' requires a reference to an array";
205             }
206             }
207              
208 3         9 return $self->_send_request( $self->_build_request( 'word', $query ) );
209             }
210              
211             sub examples {
212 1     1 1 3 my ( $self, $word ) = @_;
213              
214 1 50       3 return unless $word;
215              
216 1         4 my $query = "$word/examples";
217              
218 1         3 return $self->_send_request( $self->_build_request( 'word', $query ) );
219             }
220              
221             sub related {
222 2     2 1 6 my ( $self, $word, %args ) = @_;
223              
224 2 50       9 return unless $word;
225              
226 2         23 my %parameters = (
227             type => {
228             synonym => 0,
229             antonym => 0,
230             form => 0,
231             hyponym => 0,
232             variant => 0,
233             'verb-stem' => 0,
234             'verb-form' => 0,
235             'cross-reference' => 0,
236             'same-context' => 0,
237             },
238             limit => 1000,
239             );
240              
241 2         7 my $query = "$word/related";
242 2 100       9 $query .= '?' if keys %args;
243              
244 2 100       8 if ( exists $args{type} ) {
245 1 50       6 if ( 'ARRAY' eq ref $args{type} ) {
246 1         4 for my $type ( @{ $args{type} } ) {
  1         3  
247              
248 9 50       24 croak "Invalid argument key or value: '$type'"
249             unless exists $parameters{type}->{$type};
250             }
251 1         3 $query .= "type=" . join q{,}, @{ $args{type} };
  1         6  
252             }
253             else {
254 0         0 croak "Parameter 'type' requires a reference to an array";
255             }
256             }
257              
258 2 50       7 if ( exists $args{limit} ) {
259 0 0       0 if ( 0 >= $args{limit} ) {
260 0         0 croak "Parameter 'limit' must be a positive number";
261             }
262 0 0       0 $query .= '&' if exists $args{type};
263 0         0 $query .= "limit=$args{limit}";
264             }
265              
266 2         6 return $self->_send_request( $self->_build_request( 'word', $query ) );
267             }
268              
269             sub frequency {
270 1     1 1 2 my ( $self, $word ) = @_;
271              
272 1 50       4 return unless $word;
273              
274 1         3 my $query = "$word/frequency";
275              
276 1         3 return $self->_send_request( $self->_build_request( 'word', $query ) );
277             }
278              
279             sub punctuationFactor {
280 1     1 1 3 my ( $self, $word ) = @_;
281              
282 1 50       6 return unless $word;
283              
284 1         3 my $query = "$word/punctuationFactor";
285              
286 1         4 return $self->_send_request( $self->_build_request( 'word', $query ) );
287             }
288              
289             sub suggest {
290 3     3 1 12 my ( $self, $word, %args ) = @_;
291              
292 3 50       9 return unless $word;
293              
294 3         10 my %parameters = (
295             count => 10,
296             startAt => 0,
297             );
298              
299 3         12 for ( keys %args ) {
300 2 50 33     25 croak "Invalid argument key or value: '$_'"
301             unless exists $parameters{$_}
302             and $args{$_} =~ m/\d+/;
303             }
304              
305 3         8 my $query = "$word";
306 3         14 $query .= "?$_=$args{$_}" for keys %args;
307              
308 3         9 return $self->_send_request( $self->_build_request( 'suggest', $query ) );
309             }
310              
311             sub wordoftheday {
312 1     1 1 3 my ($self) = @_;
313              
314 1         4 return $self->_send_request( $self->_build_request('wordoftheday') );
315             }
316              
317             sub randomWord {
318 1     1 1 5 my ( $self, %args ) = @_;
319              
320 1         6 my %parameters = ( hasDictionaryDef => { true => 0, false => 1 }, );
321              
322 1         5 for ( keys %args ) {
323 1 50 33     16 croak "Invalid argument key or value: '$_'"
324             unless exists $parameters{$_}
325             and exists $parameters{$_}->{ $args{$_} };
326             }
327              
328 1         3 my $query = "randomWord";
329 1         7 $query .= "?$_=$args{$_}" for keys %args;
330              
331 1         4 return $self->_send_request( $self->_build_request( 'words', $query ) );
332             }
333              
334             ### internal methods
335              
336             sub _build_request {
337 19     19   46 my ( $self, $namespace, $query ) = @_;
338              
339 19         41 my $request = $self->server_uri . q{/} . $namespace . q{.};
340 19 100       45 $request .= 'perl' eq $self->format ? 'json' : $self->format;
341 19 100       56 $request .= defined $query ? "/$query" : q{};
342              
343 19         71 return $request;
344             }
345              
346             sub _send_request {
347 18     18   27 my ( $self, $request ) = @_;
348              
349 18 50       150 return $request if $self->{debug};
350              
351             # cache
352 0 0 0     0 if ( $self->cache and exists $self->{_cache}->{requests}->{$request} ) {
353 0         0 return ${ $self->{_cache}->{requests}->{$request} };
  0         0  
354             }
355              
356             # request
357             else {
358 0         0 my $response = $self->{_user_agent}->get($request);
359              
360 0         0 my $data = $self->_validate_response($response);
361              
362 0 0       0 $data = from_json($data)
363             if 'perl' eq $self->format;
364              
365 0         0 return $self->_cache_data( $request, $data );
366             }
367             }
368              
369             sub _validate_response {
370 0     0   0 my ( $self, $response ) = @_;
371              
372 0 0 0     0 return $response->decoded_content
373             if $response->is_success
374             or $response->is_redirect;
375              
376 0 0 0     0 croak $response->as_string
377             if ( $response->is_error
378             or $response->is_info );
379             }
380              
381             sub _pop_cache {
382 1     1   2 my ($self) = @_;
383 1         2 my $c = $self->{_cache};
384              
385 1 50 33     9 return unless $c && 'ARRAY' eq ref $c->{data};
386 1         1 my $oldest = pop @{ $c->{data} };
  1         3  
387              
388 1 50       3 return unless 'ARRAY' eq ref $oldest;
389 1         2 my ( $request, $data ) = @{$oldest};
  1         1  
390              
391 1         3 delete $c->{requests}->{$request};
392 1         7 return $data;
393             }
394              
395             sub _load_cache {
396 1     1   2 my ( $self, $request, $data ) = @_;
397              
398 1         2 my $c = $self->{_cache};
399 1 50       19 return unless $c;
400              
401 1         3 $c->{requests}->{$request} = \$data;
402              
403 1         2 unshift @{ $c->{data} }, [ $request, $data ];
  1         10  
404              
405 1         4 return $data;
406             }
407              
408             sub _cache_data {
409 0     0   0 my ( $self, $request, $data ) = @_;
410              
411 0         0 my $c = $self->{_cache};
412 0 0       0 return unless $c;
413              
414 0 0       0 $self->_pop_cache if @{ $c->{data} } >= $c->{max};
  0         0  
415              
416 0         0 return $self->_load_cache( $request, $data );
417             }
418              
419             sub _json_available {
420 1     1   1 my ($self) = @_;
421              
422 1 50       6 croak "The operation you requested requires JSON to be installed"
423             unless $self->{_json};
424             }
425             1; # Magic true value required at end of module
426             __END__