File Coverage

blib/lib/Lingua/Lexicon/IDP.pm
Criterion Covered Total %
statement 65 67 97.0
branch 6 10 60.0
condition 3 6 50.0
subroutine 15 15 100.0
pod 3 3 100.0
total 92 101 91.0


line stmt bran cond sub pod time code
1 7     7   10719 use strict;
  7         16  
  7         365  
2             package Lingua::Lexicon::IDP;
3              
4 7     7   43 use Carp;
  7         16  
  7         561  
5 7     7   10500 use IO::File;
  7         136395  
  7         1434  
6 7     7   14321 use Memoize;
  7         29262  
  7         474  
7              
8 7     7   8915 use File::Spec::Functions qw (:DEFAULT);
  7         7119  
  7         1996  
9              
10 7     7   48 use constant MAX_TRIES => 64;
  7         14  
  7         1167  
11 7     7   41 use constant LANG_DEFAULT => "en";
  7         13  
  7         837  
12 7     7   128 use constant LANG_TRANSLATIONS => { "en" => [ "de","es","fr","it","la","pt" ] };
  7         14  
  7         6725  
13              
14             $Lingua::Lexicon::IDP::VERSION = '1.0';
15              
16             sub new {
17 7     7 1 7422 my $pkg = shift;
18              
19 7         28 my $self = {'__lang' => LANG_DEFAULT };
20 7         24 bless $self,$pkg;
21              
22 7         26 $self->_init();
23 7         27 return $self;
24             }
25              
26             sub _init {
27 7     7   15 my $self = shift;
28              
29 42         928 $self->{'__datadir'} ||=
30             join("/",
31 42         267 (grep { -d $_ }
32 77         188 map { catdir($_,split("::",__PACKAGE__)) }
33 7 50 33     109 exists $INC{"blib.pm"} ? grep {/blib/} @INC : @INC)[0],
34             "Data");
35              
36 7         18 foreach my $tr (@{LANG_TRANSLATIONS->{$self->lang()}}) {
  7         29  
37 42         221 my $datafile = join("/",
38             $self->{'__datadir'},
39             join("_",$self->lang(),"$tr.txt"));
40              
41 7     7   46 no strict "refs";
  7         16  
  7         11144  
42              
43 42         7229 *{join("::",__PACKAGE__,$tr)} = sub {
44 12     12   7248 my $self = shift;
45 12         52 return $self->_query($datafile,$_[0]);
46 42         197 };
47             }
48              
49 7         23 return 1;
50             }
51              
52             sub lang {
53 56     56 1 3920 my $self = shift;
54 56         245 return $self->{'__lang'};
55             }
56              
57             sub translations {
58 1     1 1 648 my $self = shift;
59 1         3 return LANG_TRANSLATIONS->{$self->lang()};
60             }
61              
62             sub _query {
63 12     12   23 my $self = shift;
64 12         23 my $data = shift;
65 12         21 my $word = shift;
66              
67 12 100 66     101 if ((exists($self->{'__fh'})) && ($self->{'__datafile'} ne $data)) {
68 5         33 $self->{'__fh'}->close();
69              
70 5         97 delete $self->{'__datafile'};
71 5         10 delete $self->{'__len'};
72 5         24 delete $self->{'__fh'};
73             }
74              
75 12 50       62 if (! $self->{'__fh'}) {
76 12         33 $self->{'__datafile'} = $data;
77              
78 12         135 $self->{'__fh'} = IO::File->new($self->{'__datafile'});
79              
80 12 50       1893 if (! $self->{'__fh'}) {
81 0         0 carp "Unable to create fh, $!\n";
82 0         0 return undef;
83             }
84             }
85              
86 12 50       46 if (! $self->{'__len'}) {
87 12         387 $self->{'__len'} = (stat($self->{'__datafile'}))[7];
88             }
89              
90             # For reasons I don't understand, I
91             # cant pass \*$self->{'__fh'} without
92             # generating errors....
93 12         30 my $fh = $self->{'__fh'};
94              
95 12         46 return &_do_query(\*$fh,$self->{'__len'},$word);
96             }
97              
98             sub _do_query {
99             my $fh = shift;
100             my $len = shift;
101             my $word = shift;
102              
103             #
104              
105             my $begin = 0;
106             my $end = $len;
107              
108             my $tries = 0;
109              
110             my $first = undef;
111             my $last = undef;
112              
113             my $found = 0;
114             my @translations = ();
115              
116             while (! $found) {
117              
118             if (($begin +1) == $end) {
119             return undef;
120             }
121              
122             # Just because you're paranoid
123             # Don't mean they're not after you
124              
125             if ($tries >= MAX_TRIES) {
126             carp "Tried query ".MAX_TRIES." times without success. Something is probably wrong.\n";
127             return undef;
128             }
129              
130             my $guess = int(($begin + $end) /2);
131             #print STDERR "[B] $begin [E] $end\n";
132             #print STDERR "[$tries] Guess is $guess\n";
133              
134             my $pos = $guess;
135             my $char = "";
136             my $stop = 0;
137              
138             # First thing is to back up
139             # to the start of the line
140              
141             while (! $stop) {
142             sysseek($fh,$pos,0);
143             sysread ($fh,$char,1);
144              
145             if ($char =~ /\n/) {
146             $stop = 1;
147             $pos = $pos+2;
148             }
149              
150             $pos--;
151              
152             if (! $pos) {
153             $stop = 1;
154             }
155             }
156              
157             # Next, try to see if we can find
158             # any matches at all
159              
160             $first = $pos;
161             $stop = 0;
162              
163             my $line = undef;
164             my $match = 0;
165              
166             while (! $stop) {
167             sysseek($fh,$pos,0);
168             sysread($fh,$char,1);
169              
170             # We've found the word we're
171             # looking for. Make a note of
172             # this so that we can stop
173             # performing this regex(p) and
174             # start collecting the translation.
175              
176             if ($line =~ /$word\t.*/) {
177             $match = 1;
178             $stop = 1;
179             }
180              
181             # We're not sure if we've found
182             # a match but the current line looks
183             # like it could still be the word
184             # we're looking for.
185              
186             elsif ($word =~ /^$line/) {
187             $line .= $char;
188             $pos++;
189             }
190              
191             # This is not the droid, we're looking for.
192             # The only question now is whether to look
193             # forwards or backwards.
194              
195             else {
196              
197             if ([sort ($word,$line)]->[0] eq $word) {
198             $end = $guess;
199             }
200              
201             else {
202             $begin = $guess;
203             }
204              
205             $stop = 1;
206             }
207              
208             }
209              
210             # Did not find anything.
211             # Try again
212             next unless ($match);
213              
214             # Okay, since we're doing a boolean
215             # search we have to back up to find
216             # the first instance of the word.
217              
218             $stop = 0;
219             $line = undef;
220              
221             # So far, we think that the
222             # first instance of $word is here
223             my $first_instance = $first;
224              
225             # print STDERR "FIRST INSTANCE '$first_instance'\n";
226              
227             # Back up past the newline
228             $pos = $first_instance - 2;
229              
230             # print STDERR "START AT '$pos'\n";
231              
232             while (! $stop) {
233             sysseek($fh,$pos,0);
234             sysread($fh,$char,1);
235              
236             # print STDERR "[$pos] '$char' '$line'\n";
237            
238             if ($char =~ /\n/) {
239              
240             # print STDERR "CHECKING '$line'\n";
241              
242             # Okay, well this line has an entry
243             # for $word so we'll mark it as the
244             # the first entry and keep going.
245             if ($line =~ /$word\t/) {
246             $first_instance = $pos +1;
247              
248             $line = undef;
249             $pos--;
250             }
251              
252             # Different word. Stop.
253             else { $stop = 1; }
254             }
255              
256             else {
257             $line = $char.$line;
258             $pos--;
259             }
260             }
261              
262             # Start recording.
263             # Go to the first instance.
264             $pos = $first_instance;
265              
266             $line = undef;
267             $match = 0;
268             $stop = 0;
269              
270             my $translation = undef;
271              
272             # print STDERR "START LOOKING AT '$pos'\n";
273              
274             while (! $stop) {
275             sysseek($fh,$pos,0);
276             sysread($fh,$char,1);
277              
278             # print STDERR " [$word][$match][$pos] '$line' '$translation'\n";
279              
280             # We've found the word we're
281             # looking for and now we're just
282             # reading the translation.
283              
284             if ($match) {
285              
286             # End of the line.
287             # Hello, translation.
288              
289             # Note, that we'll keep going trying
290             # to find additional translations.
291              
292             if ($char =~ /\n/) {
293              
294             push @translations, $translation;
295              
296             $line = undef;
297             $translation = undef;
298             $match = 0;
299              
300             $pos++;
301             }
302              
303             # Munge munge munge
304              
305             else {
306             $translation .= $char;
307             $pos++;
308             }
309             }
310              
311             # We've found the word we're
312             # looking for. Make a note of
313             # this so that we can stop
314             # performing this regex(p) and
315             # start collecting the translation.
316              
317             elsif ($line =~ /$word\t.*/) {
318             $match = 1;
319             }
320              
321             # We're not sure if we've found
322             # a match but the current line looks
323             # like it could still be the word
324             # we're looking for.
325              
326             elsif ($word =~ /^$line/) {
327             $line .= $char;
328             $pos++;
329             }
330              
331             # Stop.
332              
333             else {
334             $found = 1;
335             $stop = 1;
336             }
337             }
338              
339             $tries++;
340             }
341              
342             return @translations;
343             }
344              
345             END { memoize("_do_query"); }
346             return 1;
347              
348             __END__