File Coverage

blib/lib/WebService/Google/Language.pm
Criterion Covered Total %
statement 131 135 97.0
branch 52 62 83.8
condition 18 25 72.0
subroutine 29 29 100.0
pod 7 7 100.0
total 237 258 91.8


line stmt bran cond sub pod time code
1             package WebService::Google::Language;
2              
3 7     7   260740 use 5.006;
  7         28  
  7         276  
4              
5 7     7   39 use strict;
  7         11  
  7         250  
6 7     7   38 use warnings;
  7         20  
  7         282  
7              
8             our $VERSION = '0.14';
9              
10 7     7   57 use Carp ();
  7         14  
  7         172  
11 7     7   7124 use JSON 2.0 ();
  7         133473  
  7         182  
12 7     7   8935 use LWP::UserAgent;
  7         367925  
  7         255  
13 7     7   108 use URI;
  7         19  
  7         209  
14              
15 7     7   47 use constant GOOGLE_DETECT_URL => 'http://ajax.googleapis.com/ajax/services/language/detect';
  7         16  
  7         551  
16 7     7   40 use constant GOOGLE_TRANSLATE_URL => 'http://ajax.googleapis.com/ajax/services/language/translate';
  7         13  
  7         292  
17 7     7   92 use constant API_VERSION => '1.0';
  7         15  
  7         603  
18 7     7   44 use constant MAX_LENGTH => 5000;
  7         12  
  7         289  
19 7     7   37 use constant URL_MAX_LENGTH => 2073;
  7         13  
  7         10447  
20              
21              
22              
23             #
24             # constructor
25             #
26              
27             sub new {
28 13     13 1 15048 my $class = shift;
29 13         53 my $self = bless {}, $class;
30              
31 13 100       82 unshift @_, 'referer' if @_ % 2;
32 13         50 my %conf = @_;
33              
34 13         64 $self->referer(delete $conf{referer});
35              
36 12         37 for (qw'src dest key') {
37 36 100       122 if (defined(my $value = delete $conf{$_})) {
38 4         12 $self->{$_} = $value;
39             }
40             }
41              
42 12         30 for (qw'json ua') {
43 24 100       83 if (defined(my $value = delete $conf{$_})) {
44 4         30 $self->$_($value);
45             }
46             }
47 12 100       42 unless ($self->json) {
48 10         514 $self->json(JSON->new);
49             }
50 12 100       41 unless ($self->ua) {
51 10 100       220 $conf{agent} = $class . ' ' . $class->VERSION
52             unless defined $conf{agent};
53             # respect proxy environment variables (reported by IZUT)
54 10 100       67 $conf{env_proxy} = 1
55             unless exists $conf{env_proxy};
56 10         105 $self->ua(LWP::UserAgent->new(%conf));
57             }
58              
59 12         80 return $self;
60             }
61              
62              
63              
64             #
65             # public methods
66             #
67              
68             sub translate {
69 5     5 1 219665 my $self = shift;
70 5 100       28 unshift @_, 'text' if @_ % 2;
71 5         15 my %args = @_;
72 5   50     55 my $src = $args{src} || $self->{src} || '';
73 5   50     44 my $dest = $args{dest} || $self->{dest} || 'en';
74 5         34 return $self->_request($args{text}, $src . '|' . $dest);
75             }
76              
77             sub detect {
78 3     3 1 8409 my $self = shift;
79 3 100       21 unshift @_, 'text' if @_ % 2;
80 3         13 my %args = @_;
81 3         16 return $self->_request($args{text});
82             }
83              
84             *detect_language = \&detect;
85              
86             sub ping {
87 1     1 1 819 my $self = shift;
88 1         3 return $self->ua
89             ->get( GOOGLE_TRANSLATE_URL, referer => $self->referer )
90             ->is_success;
91             }
92              
93              
94              
95             #
96             # accessors
97             #
98              
99             sub json {
100 31     31 1 2690 my $self = shift;
101 31 100       85 if (@_) {
102 15         21 my $json = shift;
103 15 100 100     495 Carp::croak q{'json' requires an object based on 'JSON'}
104             unless $json && $json->isa('JSON');
105 13         31 $self->{json} = $json;
106 13         43 return $self;
107             }
108 16         67 $self->{json};
109             }
110              
111             sub referer {
112 24     24 1 3211 my $self = shift;
113 24 100       97 if (@_) {
114 17         29 my $referer = shift;
115 17 100 100     170 unless (defined $referer && $referer =~ /\S/) {
116 4         7 my $name = q{'referer'};
117 4         8 my $error = 'requires a non-empty parameter';
118 4         20 my $caller = (caller(1))[3];
119 4 100 100     518 Carp::croak $caller && $caller eq ref($self) . '::new'
120             ? "Constructor $error $name"
121             : "$name $error";
122             }
123 14         53 $self->{referer} = $referer;
124 14         32 return $self;
125             }
126 7         41 $self->{referer};
127             }
128              
129             sub ua {
130 37     37 1 584520 my $self = shift;
131 37 100       107 if (@_) {
132 15         27 my $ua = shift;
133 15 100 100     414 Carp::croak q{'ua' requires an object based on 'LWP::UserAgent'}
134             unless $ua && $ua->isa('LWP::UserAgent');
135 13         31 $self->{ua} = $ua;
136 13         55 return $self;
137             }
138 22         90 $self->{ua};
139             }
140              
141              
142              
143             #
144             # private methods and functions
145             #
146              
147             sub _request {
148 8     8   19 my ($self, $text, $langpair) = @_;
149 8 100 100     69 if (defined $text && $text =~ /\S/) {
150 4         13 _utf8_encode($text);
151 4 100       18 if (length $text > MAX_LENGTH) {
152 1         170 Carp::croak 'Google does not allow submission of text exceeding '
153             . MAX_LENGTH . ' characters in length';
154             }
155             }
156             else {
157 4         20 return;
158             }
159              
160 3         3 my ($uri, $response);
161 3         10 my @param = ( v => API_VERSION );
162 3 50       14 push @param, key => $self->{key} if defined $self->{key};
163 3 100       6 if (defined $langpair) {
164 2         14 $uri = URI->new(GOOGLE_TRANSLATE_URL);
165 2         11083 push @param, langpair => $langpair;
166             }
167             else {
168 1         8 $uri = URI->new(GOOGLE_DETECT_URL);
169             }
170 3         140 push @param, q => $text;
171 3         22 $uri->query_form(\@param);
172              
173 3         1254 my $length = length $uri;
174 3 100       26 if ($length > URL_MAX_LENGTH) {
175 2 100       7 if (defined $langpair) {
176             # POST only for translate
177 1         4 $uri->query_form( [] );
178 1         88 $response = $self->ua->post( $uri, \@param, referer => $self->referer );
179             }
180             else {
181             # detect can't be POSTed
182 1         174 Carp::croak "The length of the generated URL for this request is $length bytes and exceeds the maximum of "
183             . URL_MAX_LENGTH . ' bytes. Shorten your parameters.';
184             }
185             }
186             else {
187 1         7 $response = $self->ua->get( $uri, referer => $self->referer );
188             }
189              
190 2 100       149 if ($response->is_success) {
191 1         10 my $result = eval { $self->json->decode($response->content) };
  1         4  
192 1 50       23 if ($@) {
193 1         5 Carp::croak "Couldn't parse response from '$uri': $@";
194             }
195             else {
196 0         0 return bless $result, 'WebService::Google::Language::Result';
197             }
198             }
199             else {
200 1         16 Carp::croak "An HTTP error occured while getting '$uri': " . $response->status_line;
201             }
202             }
203              
204             sub _utf8_encode {
205 4 50   4   13 if ($] < 5.007) {
206              
207             # on Perl 5.6 the JSON 2 module (JSON::PP56) provides the missing
208             # utf8::encode function, but it seems to be broken
209             # my own UTF8 encoder is tested on ActivePerl 5.6.1.638
210              
211 7 0   7   18622 if (length $_[0] == do { use bytes; length $_[0] }) {
  7         86  
  7         40  
  0         0  
  0         0  
212 0         0 $_[0] = pack 'U*', unpack 'C*', $_[0];
213             }
214             }
215             else {
216 4         52 utf8::encode($_[0]);
217             }
218             }
219              
220              
221              
222             #
223             # convenience accessor methods to result hash
224             #
225              
226             package WebService::Google::Language::Result;
227              
228             sub error {
229 1 50 33 1   1477 $_[0]->{responseStatus} && $_[0]->{responseStatus} != 200
230             ? { code => $_[0]->{responseStatus},
231             message => $_[0]->{responseDetails},
232             }
233             : undef
234             }
235              
236 1     1   908 sub code { $_[0]->{responseStatus} }
237              
238 1     1   886 sub message { $_[0]->{responseDetails} }
239              
240             sub translation {
241 1 50   1   970 $_[0]->{responseData} ? $_[0]->{responseData}{translatedText} : undef
242             }
243              
244             sub language {
245 1 50 0 1   973 $_[0]->{responseData}
246             ? $_[0]->{responseData}{language} ||
247             $_[0]->{responseData}{detectedSourceLanguage}
248             : undef
249             }
250              
251             sub is_reliable {
252 1 50   1   870 $_[0]->{responseData} ? $_[0]->{responseData}{isReliable} : undef
253             }
254              
255             sub confidence {
256 1 50   1   882 $_[0]->{responseData} ? $_[0]->{responseData}{confidence} : undef
257             }
258              
259              
260              
261             $VERSION = eval $VERSION;
262              
263             __END__