File Coverage

blib/lib/I22r/Translate/Request.pm
Criterion Covered Total %
statement 129 140 92.1
branch 33 48 68.7
condition 26 31 83.8
subroutine 21 21 100.0
pod 2 13 15.3
total 211 253 83.4


line stmt bran cond sub pod time code
1             package I22r::Translate::Request;
2 24     24   20373 use Moose;
  24         9984323  
  24         231  
3 24     24   180435 use Carp;
  24         56  
  24         49260  
4              
5             our $VERSION = '0.96';
6              
7             has _config => ( is => 'rw', isa => 'HashRef',
8             default => sub { {} } );
9             has results => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
10             has src => ( is => 'ro', isa => 'Str', required => 1 );
11             has dest => ( is => 'ro', isa => 'Str', required => 1 );
12             has text => ( is => 'rw', isa => 'HashRef', required => 1 );
13             has start => ( is => 'ro', isa => 'Int', default => sub { time } );
14             has logger => ( is => 'rw' );
15              
16             # TODO: return_type validation: simple, object, hash
17             has return_type => ( is => 'ro', isa => 'Str', default => 'simple' );
18              
19             # TODO: backend validation:
20             has backend => ( is => 'rw', default => undef );
21              
22             our %filters_loaded = ();
23              
24             sub BUILDARGS {
25 29     29 1 177 my ($class, %opts) = @_;
26 29         83 my $config = { };
27 29         174 foreach my $key (keys %opts) {
28 98 100 100     640 if ($key eq 'src' || $key eq 'dest' || $key eq 'text') {
      100        
29 81         205 $config->{$key} = $opts{$key};
30             } else {
31 18         100 $config->{_config}{$key} = $opts{$key};
32             }
33             }
34 28         1528 return $config;
35             }
36              
37             sub BUILD {
38 26     27 0 65 my $self = shift;
39 26         45 $self->{otext} = { %{$self->text} };
  26         1080  
40             }
41              
42             sub config {
43 79     79 1 1372 my ($self, $key) = @_;
44 79         3209 my $r = $self->_config->{$key};
45 79 100       264 return $r if defined $r;
46              
47 52 100       2072 if ($self->backend) {
48 35         1235 $r = $self->_config->{ $self->backend . '::' . $key };
49 35 50       99 return $r if defined $r;
50 35         1255 $r = $self->backend->config($key);
51 35 100       161 return $r if defined $r;
52             }
53              
54 41         181 return $I22r::Translate::config{$key};
55             }
56              
57             sub translations_complete {
58 21     21 0 37 my $self = shift;
59 21         30 foreach my $id (keys %{$self->text}) {
  21         773  
60 50 100       1973 if (!defined $self->results->{$id}) {
61 3         15 return 0;
62             }
63             }
64 18         102 return 1;
65             }
66              
67             sub otext {
68 36     36 0 186 my $self = shift;
69 36         123 return $self->{otext};
70             }
71              
72             # return results in accordance with the desired return_type
73             sub return_results {
74 21     21 0 35 my $self = shift;
75 21   100     78 my $return_type = $self->config('return_type') // 'simple';
76              
77 21 100       86 if ($return_type eq 'object') {
78 7         9 return %{ $self->results };
  7         258  
79             }
80 14 100       47 if ($return_type eq 'hash') {
81             return map {
82 2         55 $_ => $self->results->{$_}->to_hash
83 2         2 } keys %{$self->results};
  2         54  
84             }
85 12 50 50     87 if ($return_type eq 'simple' || 1) {
86             return map {
87 30         1154 $_ => $self->results->{$_}->text
88 12         28 } keys %{$self->results};
  12         474  
89             }
90             }
91              
92             ##########################################################
93             #
94             # Filter methods
95             #
96             ##########################################################
97              
98             sub get_filters {
99 21     21 0 45 my $self = shift;
100 21   100     122 my $f1 = $I22r::Translate::config{filter} // [];
101 21   66     967 my $f2 = ($self->backend && $self->backend->config('filter')) // [];
      100        
102 21   100     783 my $f3 = $self->_config->{'filter'} // [];
103 21         102 return [ map { to_filter($_) } @$f1, @$f2, @$f3 ];
  16         45  
104             }
105              
106             sub to_filter {
107 16     16 0 26 my $filter = shift;
108 16         29 my @args = ();
109 16 50       44 if ('ARRAY' eq ref $filter) {
110 0         0 ($filter, @args) = @$filter;
111             }
112 16 50       38 if (ref $filter) {
113 0         0 return $filter;
114             }
115 16 50       72 if ($filter !~ /::/) {
116 16         40 $filter = "I22r::Translate::Filter::" . $filter;
117             }
118              
119 16     2   1308 my $f = eval "use $filter; $filter->new( \@args )";
  2     2   1318  
  2     2   7  
  2     2   89  
  2     2   598  
  2     2   6  
  2         73  
  2         13  
  2         3  
  2         56  
  2         11  
  2         3  
  2         65  
  2         14  
  2         3  
  2         63  
  2         13  
  2         7  
  2         48  
120 16 50       3138 if ($@) {
121             # what should we do when filter fails to load? croak or just carp?
122 0         0 carp "error loading filter $filter: $@\n";
123             }
124 16         126 return $f;
125              
126             # TODO - assert $filter fulfills the I22r::Translate::Filter role
127             }
128              
129             sub apply_filters {
130 21     21 0 41 my $self = shift;
131 21         29 $self->{otext} = { %{$self->text} };
  21         746  
132              
133             # apply filters to $self->text for any input
134             # that doesn't have a result (in $self->results )
135             my @filter_targets = grep {
136 54         2367 !defined $self->results->{$_}
137 21         50 } keys %{$self->text};
  21         716  
138              
139 21 50       82 if (@filter_targets == 0) {
140 0         0 $self->{filter_targets} = [];
141 0         0 $self->{filters} = [];
142 0         0 return;
143             }
144 21         56 $self->{filter_targets} = \@filter_targets;
145 21         145 $self->{filters} = $self->get_filters;
146              
147 21         45 foreach my $filter ( @{$self->{filters}} ) {
  21         93  
148             I22r::Translate->log(
149 16 50       132 $self->{logger}, " applying filter: ",
150             ref($filter) ? ref($filter) : "$filter" );
151 16         42 foreach my $id (@filter_targets) {
152 36         136 $filter->apply( $self, $id );
153             }
154             }
155             }
156              
157             sub unapply_filters {
158 21     21 0 63 my $self = shift;
159 21         34 my @targets = @{$self->{filter_targets}};
  21         82  
160 21         40 foreach my $filter ( reverse @{ $self->{filters} } ) {
  21         74  
161             I22r::Translate->log(
162 16 50       115 $self->{logger}, " removing filter: ",
163             ref($filter) ? ref($filter) : "$filter");
164 16         42 foreach my $id (@targets) {
165 36         117 $filter->unapply( $self, $id );
166             }
167             }
168 21         55 foreach my $id (@targets) {
169 54         2309 $self->text->{$id} = $self->{otext}{$id};
170 54 100       2201 if (defined($self->results->{$id})) {
171 47         1806 $self->results->{$id}{otext} = $self->text->{$id};
172             }
173             }
174 21         65 delete $self->{filter_targets};
175 21         112 delete $self->{filters};
176             }
177              
178             ##########################################################
179             #
180             # time out methods
181             #
182             ##########################################################
183              
184             sub timed_out {
185 42     42 0 21003124 my $self = shift;
186 42         2007 my $elapsed = time - $self->start;
187 42 100 100     1625 if ($self->_config->{timeout} && $elapsed >= $self->_config->{timeout}) {
188             I22r::Translate->log($self->{logger},
189 2         25 "request timed out after ${elapsed}s");
190 2         14 return 1;
191             }
192              
193 40 100 100     230 if ($I22r::Translate::config{timeout} &&
194             $elapsed >= $I22r::Translate::config{timeout}) {
195             I22r::Translate->log($self->{logger},
196 4         40 "request timed out after ${elapsed}s");
197 4         19 return 1;
198             }
199              
200 36 50 33     1371 if ($self->backend && $self->backend->config('timeout')) {
201 0 0       0 if ($self->{backend_start}) {
202 0         0 $elapsed = time - $self->{backend_start};
203             }
204 0 0       0 if ($elapsed >= $self->backend->config('timeout')) {
205             I22r::Translate->log($self->{logger},
206 0         0 "request timed out after ${elapsed}s");
207 0         0 return 1;
208             }
209             }
210 36         99 return;
211             }
212              
213             ##########################################################
214             #
215             # Callback functions
216             #
217             ##########################################################
218              
219             sub get_callbacks {
220 21     21 0 40 my $self = shift;
221             my @callbacks = ($self->_config->{callback},
222             $self->backend
223             && $self->backend->config("callback"),
224 21   66     922 $I22r::Translate::config{callback});
225 21         100 return grep defined, @callbacks;
226             }
227              
228             sub invoke_callbacks {
229 21     21 0 58 my ($self, @ids) = @_;
230 21         83 $DB::single = 1;
231 21 50       113 return if !@ids;
232 21         77 my @callbacks = $self->get_callbacks;
233 21 100       96 return if ! @callbacks;
234             I22r::Translate->log( $self->{logger},
235 1         12 "invoking callbacks on inputs ",
236             "@ids" );
237 1         3 foreach my $id (@ids) {
238 1         2 foreach my $callback (@callbacks) {
239 3         90 $callback->( $self, $self->results->{$id} );
240             }
241             }
242             }
243              
244             ##########################################################
245              
246             __PACKAGE__->meta->make_immutable;
247             1;
248              
249             __END__
250              
251             TODO:
252              
253             src_enc, dest_enc
254              
255             return_type validation
256              
257             backend validation, must be undef or fulfill I22r::Translate::Backend role
258              
259             new_result($id, $translated_text) method so the backends don't need to
260             call the I22r::Translate::Result constructor ??
261              
262             #'
263              
264             =head1 NAME
265              
266             I22r::Translate::Request - translation request object
267              
268             =head1 DESCRIPTION
269              
270             Internal translation request object for the L<I22r::Translation>
271             distribution. If you're not developing a backend or a filter for
272             this distribution, you can stop reading now.
273              
274             Otherwise, you'll just need to know that a new C<I22r::Translate::Request>
275             object is created when you call one of the
276             L<I22r::Translate::translate_xxx|I22r::Translate/"translate_string">
277             methods.
278              
279             =head1 METHODS
280              
281             =head2 src
282              
283             =head2 dest
284              
285             The source and target languages for the translation request.
286              
287             =head2 text
288              
289             A hash reference whose values are the source strings to be
290             translated. If the request was created from a C<translate_string>
291             or C<translate_list> call, the inputs are still put into a hash
292             reference.
293              
294             =head2 _config
295              
296             All other inputs to C<I22r::Translate::translate_xxx> are put
297             into a configuration hash for the request, accessible through
298             the C<_config> method.
299              
300             =head2 config
301              
302             A special method that examines the current request's configuration,
303             configuration for the current backend (see L<"backend">), and the
304             global configuration from L<I22r::Translate>.
305              
306             =head2 backend
307              
308             Get or set the name of the active backend. The C<I22r::Translate>
309             translation process will iterate through available, qualified
310             backends until all of the inputs have been translated.
311              
312             =head2 results
313              
314             A hashref for translation results. Each key should be the same as
315             a key in L<< $request->text|"text" >>, and the value is an
316             L<I22r::Translate::Result> object.
317              
318             =head1 MORE DEVELOPER NOTES
319              
320             If you are writing a new L<filter|I22r::Translate::Filter>,
321             you will want your C<apply> method to operate on an element
322             of C<< $request->text >> (say, C<< $request->text->{$key} >>,
323             and your C<unapply> method to operate on the corresponding
324             C<< $request->results->{$key}->text >>.
325              
326             In a backend, you'll want to pass the values in
327             C<< $request->text >> the translation engine, and populate
328             C<< $request->results >> with the results of the translation.
329              
330             =head1 SEE ALSO
331              
332             L<I22r::Translate>
333              
334             =cut