File Coverage

blib/lib/Bio/Tools/EUtilities.pm
Criterion Covered Total %
statement 224 384 58.3
branch 110 258 42.6
condition 24 70 34.2
subroutine 43 63 68.2
pod 50 51 98.0
total 451 826 54.6


line stmt bran cond sub pod time code
1             package Bio::Tools::EUtilities;
2             $Bio::Tools::EUtilities::VERSION = '1.77';
3 13     13   1138086 use utf8;
  13         328  
  13         75  
4 13     13   411 use strict;
  13         27  
  13         258  
5 13     13   61 use warnings;
  13         24  
  13         371  
6 13     13   66 use base qw(Bio::Root::IO Bio::Tools::EUtilities::EUtilDataI);
  13         27  
  13         8003  
7 13     13   10789 use XML::Simple;
  13         118457  
  13         88  
8              
9             # ABSTRACT: NCBI eutil XML parsers.
10             # AUTHOR: Chris Fields
11             # OWNER: 2006-2013 Chris Fields
12             # LICENSE: Perl_5
13              
14              
15              
16              
17             {
18              
19             my %DATA_MODULE = (
20             'esearch' => 'Query',
21             'egquery' => 'Query',
22             'espell' => 'Query',
23             'epost' => 'Query',
24             'elink' => 'Link',
25             'einfo' => 'Info',
26             'esummary' => 'Summary',
27             );
28              
29             sub new {
30 44     44 1 201 my($caller,@args) = @_;
31 44   33     253 my $class = ref $caller || $caller;
32 44 100       246 if ($class =~ m{Bio::Tools::EUtilities::(\S+)}) {
33 22         152 my ($self) = $class->SUPER::new(@args);
34 22         6037 $self->_initialize(@args);
35 22         199 return $self;
36             } else {
37 22         106 my %param = @args;
38 22         102 @param{ map { lc $_ } keys %param } = values %param; # lowercase keys
  44         166  
39 22   33     108 my $eutil = $param{'-eutil'} || $class->throw("Need eutil to make instance");
40 22 50       130 return unless( $class->_load_eutil_module( $DATA_MODULE{$eutil}) );
41 22         319 return "Bio::Tools::EUtilities::$DATA_MODULE{$eutil}"->new(-datatype => lc $DATA_MODULE{$eutil},
42             -eutil => $eutil,
43             @args);
44             }
45             }
46              
47             sub _initialize {
48 22     22   112 my ($self, @args) = @_;
49 22         150 my ($response, $pobj, $type, $eutil, $cache, $lazy) =
50             $self->_rearrange([qw(RESPONSE
51             PARAMETERS
52             DATATYPE
53             EUTIL
54             CACHE_RESPONSE
55             LAZY)], @args);
56 22   50     963 $lazy ||= 0;
57 22   50     112 $cache ||= 0;
58 22         184 $self->datatype($type);
59 22         141 $self->eutil($eutil);
60             # lazy parsing only implemented for elink and esummary (where returned data
61             # can be quite long). Also, no point to parsing lazily when the data is
62             # already in memory in an HTTP::Response object, so turn it off and chunk
63             # the Response object after parsing.
64 22 50       73 $response && $self->response($response);
65 22 50       64 $pobj && $self->parameter_base($pobj);
66 22         128 $self->cache_response($cache);
67 22 100 100     162 $lazy = 0 if ($response) || ($eutil ne 'elink' && $eutil ne 'esummary');
      66        
68             # setting parser to 'lazy' mode is permanent (can't reset later)
69 22         58 $self->{'_lazy'} = $lazy;
70 22         76 $self->{'_parsed'} = 0;
71             }
72              
73             }
74              
75              
76             sub cache_response {
77 44     44 1 134 my ($self, $cache) = @_;
78 44 100       130 if (defined $cache) {
79 22 50       107 $self->{'_cache_response'} = ($cache) ? 1 : 0;
80             }
81 44         146 return $self->{'_cache_response'};
82             }
83              
84              
85             sub response {
86 22     22 1 69 my ($self, $response) = @_;
87 22 50       73 if ($response) {
88 0 0 0     0 $self->throw('Not an HTTP::Response object') unless (ref $response && $response->isa('HTTP::Response'));
89 0         0 $self->{'_response'} = $response;
90             }
91 22         120 return $self->{'_response'};
92             }
93              
94              
95             sub parameter_base {
96 34     34 1 917 my ($self, $pb) = @_;
97 34 100       70 if ($pb) {
98 4 50 33     57 $self->throw('Not an Bio::ParameterBaseI object') unless (ref $pb && $pb->isa('Bio::ParameterBaseI'));
99 4 50 33     29 $self->warn('Not an Bio::Tools::EUtilities::EUtilParameters object; may experience some turbulence...') unless (ref $pb && $pb->isa('Bio::Tools::EUtilities::EUtilParameters'));
100 4         24 $self->{'_parameter_base'} = $pb;
101             }
102 34         269 return $self->{'_parameter_base'};
103             }
104              
105              
106             sub data_parsed {
107 188     188 1 649 return shift->{'_parsed'};
108             }
109              
110              
111             sub is_lazy {
112 83     83 1 237 return shift->{'_lazy'};
113             }
114              
115              
116             {
117             my %EUTIL_DATA = (
118             'esummary' => [qw(DocSum Item)],
119             'epost' => [],
120             'egquery' => [],
121             'einfo' => [qw(Field Link)],
122             'elink' => [qw(LinkSet LinkSetDb LinkSetDbHistory IdUrlSet
123             Id IdLinkSet ObjUrl Link LinkInfo)],
124             'espell' => [qw(Original Replaced)],
125             'esearch' => [qw(Id ErrorList WarningList)],
126             );
127              
128             sub parse_data {
129 22     22 1 48 my $self = shift;
130 22         86 my $eutil = $self->eutil;
131 22         161 my $xs = XML::Simple->new();
132 22 50       1679 my $response = $self->response ? $self->response :
    50          
133             $self->_fh ? $self->_fh :
134             $self->throw('No response or stream specified');
135              
136 22         288 my $data;
137 22 100 33     328 if ($eutil eq 'espell') {
    50          
138 1         5 $data = $self->_fix_espell($response);
139             } elsif ($response && $response->isa("HTTP::Response")) {
140 0         0 $data = $response->content;
141             } else {
142 21         50 $data = $response;
143             }
144 22         127 my $simple = $xs->XMLin($data, ForceArray => $EUTIL_DATA{$eutil});
145              
146             ## The ERROR element is #PCDATA only, so it can only have one text
147             ## element. However, it can still have zero text elements in
148             ## which case it will be a reference to an empty hash.
149 22 50 66     2242029 if (defined $simple->{ERROR} && ! ref($simple->{ERROR})) {
150             ## Some errors may not be fatal but there doesn't seem to be a
151             ## way for us to know. So we warn.
152 0         0 $self->warn("NCBI $eutil error: " . $simple->{ERROR});
153             }
154              
155              
156 22 50       152 if ($simple->{InvalidIdList}) {
157 0         0 $self->warn("NCBI $eutil error: Invalid ID List".$simple->{InvalidIdList});
158 0         0 return;
159             }
160 22 50 33     234 if ($simple->{ErrorList} || $simple->{WarningList}) {
161 0 0       0 my @errorlist = @{ $simple->{ErrorList} } if $simple->{ErrorList};
  0         0  
162 0 0       0 my @warninglist = @{ $simple->{WarningList} } if $simple->{WarningList};
  0         0  
163 0         0 my ($err_warn);
164 0         0 for my $error (@errorlist) {
165 0         0 my $messages = join("\n\t",map {"$_ [".$error->{$_}.']'}
166 0         0 grep {!ref $error->{$_}} keys %$error);
  0         0  
167 0         0 $err_warn .= "Error : $messages";
168             }
169 0         0 for my $warn (@warninglist) {
170 0         0 my $messages = join("\n\t",map {"$_ [".$warn->{$_}.']'}
171 0         0 grep {!ref $warn->{$_}} keys %$warn);
  0         0  
172 0         0 $err_warn .= "Warnings : $messages";
173             }
174 0         0 chomp($err_warn);
175 0         0 $self->warn("NCBI $eutil Errors/Warnings:\n".$err_warn)
176             # don't return as some data may still be useful
177             }
178 22 50       132 delete $self->{'_response'} unless $self->cache_response;
179 22         70 $self->{'_parsed'} = 1;
180 22         131 $self->_add_data($simple);
181             }
182              
183             # implemented only for elink/esummary, still experimental
184              
185             sub parse_chunk {
186 0     0 0 0 my $self = shift;
187 0         0 my $eutil = $self->eutil;
188 0 0       0 my $tag = $eutil eq 'elink' ? 'LinkSet' :
    0          
189             $eutil eq 'esummary' ? 'DocSum' :
190             $self->throw("Only eutil elink/esummary use parse_chunk()");
191 0         0 my $xs = XML::Simple->new();
192 0 0       0 if ($self->response) {
193 0         0 $self->throw("Lazy parsing not implemented for HTTP::Response data yet");
194 0 0 0     0 delete $self->{'_response'} if !$self->cache_response && $self->data_parsed;
195             } else { # has to be a file/filehandle
196 0         0 my $fh = $self->_fh;
197 0         0 my ($chunk, $seendoc, $line);
198             CHUNK:
199 0         0 while ($line = <$fh>) {
200 0 0 0     0 next unless $seendoc || $line =~ m{^<$tag>};
201 0         0 $seendoc = 1;
202 0         0 $chunk .= $line;
203 0 0       0 last if $line =~ m{^};
204             }
205 0 0       0 if (!defined $line) {
206 0         0 $self->{'_parsed'} = 1;
207 0         0 return;
208             }
209             $self->_add_data(
210 0         0 $xs->XMLin($chunk, forcearray => $EUTIL_DATA{$eutil}, KeepRoot => 1)
211             );
212             }
213             }
214              
215             }
216              
217              
218             sub to_string {
219 0     0 1 0 my $self = shift;
220 0 0 0     0 $self->parse_data if ($self->can('parse_data') && !$self->data_parsed);
221 0         0 return sprintf("%-20s:%s\n\n", 'EUtil', $self->eutil);
222             }
223              
224              
225             sub print_all {
226 0     0 1 0 my ($self, @args) = @_;
227 0         0 $self->_print_handler(@args);
228             }
229              
230              
231              
232              
233             sub get_ids {
234 23     23 1 837 my ($self, $request) = @_;
235 23         88 my $eutil = $self->eutil;
236 23 50       75 if ($self->is_lazy) {
237 0         0 $self->warn('get_ids() not implemented when using lazy mode');
238 0         0 return;
239             }
240 23 50       72 $self->parse_data unless $self->data_parsed;
241 23 100       143 if ($eutil eq 'esearch') {
    100          
    100          
    100          
242 2 50       7 return $self->{'_id'} ? @{ $self->{'_id'} } : ();
  2         15  
243             } elsif ($eutil eq 'elink') {
244 15         32 my @ids;
245 15 100       37 if ($request) {
246 4 50       10 if (ref $request eq 'CODE') {
247 0         0 push @ids, map {$_->get_ids }
248 0         0 grep { $request->($_) } $self->get_LinkSets;
  0         0  
249             } else {
250             push @ids,
251 14         19 map { @{$_->[0]} }
  14         27  
252 16         26 grep {grep { $_ eq $request } @{$_->[1]}}
  156         240  
  16         24  
253 4         11 map {[[$_->get_ids], [$_->get_databases]]} $self->get_LinkSets;
  16         42  
254             }
255             } else {
256 11 50       47 $self->warn('Multiple database present, IDs will be globbed together')
257             if $self->get_linked_databases > 1;
258 11         34 push @ids, map {$_->get_ids } $self->get_LinkSets;
  42         101  
259             }
260 15         131 return @ids;
261             } elsif ($eutil eq 'esummary') {
262 2 50       7 unless (exists $self->{'_id'}) {
263 2         5 push @{$self->{'_id'}}, map {$_->get_id } $self->get_DocSums;
  2         16  
  7         18  
264             }
265 2         5 return @{$self->{'_id'}};
  2         15  
266             } elsif (my $pb = $self->parameter_base) {
267 1         33 my $ids = $pb->id;
268 1 50       4 return $ids ? @{$ids} : ();
  1         6  
269             } else {
270             return ()
271 3         16 }
272             }
273              
274              
275             sub get_database {
276 16     16 1 102 return ($_[0]->get_databases)[0];
277             }
278              
279              
280             sub get_db {
281 8     8 1 192 return shift->get_database;
282             }
283              
284              
285             sub get_databases {
286 51     51 1 9158 my ($self, $db) = @_;
287 51 100       156 $self->parse_data unless $self->data_parsed;
288 51         335 my $eutil = $self->eutil;
289 51         103 my @dbs;
290 51 100 100     376 if ($eutil eq 'einfo' || $eutil eq 'espell') {
    100          
    100          
    100          
291             @dbs = $self->{'_dbname'} ||
292 12   66     73 $self->{'_database'} ||
293             $self->get_available_databases;
294             } elsif ($eutil eq 'egquery') {
295 3         15 @dbs = map {$_->get_database} ($self->get_GlobalQueries);
  105         179  
296             } elsif ($eutil eq 'elink') {
297             # only unique dbs
298 24         40 my %tmp;
299 114         251 @dbs = sort grep {!$tmp{$_}++}
300 24         114 map {($_->get_databases)} $self->get_LinkSets;
  92         217  
301             } elsif ($self->parameter_base) {
302 5 50       13 if ($self->parameter_base->eutil eq 'elink') {
303 0         0 @dbs = $self->parameter_base->dbfrom;
304             } else {
305 5         15 @dbs = $self->parameter_base->db;
306             }
307             }
308 51         407 return @dbs;
309             }
310              
311              
312             sub get_dbs {
313 3     3 1 14 return shift->get_databases;
314             }
315              
316              
317             sub next_History {
318 4     4 1 15 my $self = shift;
319 4 100       18 $self->parse_data unless $self->data_parsed;
320             $self->{'_histories_it'} = $self->generate_iterator('histories')
321 4 50       53 if (!exists $self->{'_histories_it'});
322 4         16 my $hist = $self->{'_histories_it'}->();
323             }
324              
325              
326             sub next_cookie {
327 0     0 1 0 return shift->next_History;
328             }
329              
330              
331             sub get_Histories {
332 0     0 1 0 my $self = shift;
333 0 0       0 $self->parse_data unless $self->data_parsed;
334 0 0       0 ref $self->{'_histories'} ? return @{ $self->{'_histories'} } : return ();
  0         0  
335             }
336              
337              
338             sub get_count {
339 6     6 1 29 my ($self, $db) = @_;
340 6 100       22 $self->parse_data unless $self->data_parsed;
341             # egquery
342 6 100       25 if ($self->datatype eq 'multidbquery') {
343 3 50       8 if (!$db) {
344 0         0 $self->warn('Must specify database to get count from');
345 0         0 return;
346             }
347 3         9 my ($gq) = grep {$_->get_database eq $db} $self->get_GlobalQueries;
  105         180  
348 3 50       16 $gq && return $gq->get_count;
349 0         0 $self->warn("Unknown database $db");
350 0         0 return;
351             } else {
352 3   100     29 return $self->{'_count'} || scalar($self->get_ids);
353             }
354             }
355              
356              
357             sub get_term {
358 6     6 1 19 my ($self, @args) = @_;
359 6 50       18 $self->parse_data unless $self->data_parsed;
360             $self->{'_term'} ? $self->{'_term'} :
361 6 100       35 $self->{'_query'} ? $self->{'_query'} :
    100          
    100          
362             $self->parameter_base ? $self->parameter_base->term :
363             return;
364             }
365              
366              
367             sub get_translation_from {
368 3     3 1 11 my $self = shift;
369 3 50       10 $self->parse_data unless $self->data_parsed;
370 3         15 return $self->{'_translation'}->{'From'};
371             }
372              
373              
374             sub get_translation_to {
375 3     3 1 10 my $self = shift;
376 3 50       10 $self->parse_data unless $self->data_parsed;
377 3         14 return $self->{'_translation'}->{'To'};
378             }
379              
380              
381             sub get_retstart {
382 3     3 1 2121 my $self = shift;
383 3 50       9 $self->parse_data unless $self->data_parsed;
384 3         15 return $self->{'_retstart'};
385             }
386              
387              
388             sub get_retmax {
389 3     3 1 10 my $self = shift;
390 3 50       9 $self->parse_data unless $self->data_parsed;
391 3         16 return $self->{'_retmax'};
392             }
393              
394              
395             sub get_query_translation {
396 0     0 1 0 my $self = shift;
397 0 0       0 $self->parse_data unless $self->data_parsed;
398 0         0 return $self->{'_querytranslation'};
399             }
400              
401              
402             sub get_corrected_query {
403 3     3 1 9 my $self = shift;
404 3 50       9 $self->parse_data unless $self->data_parsed;
405 3         14 return $self->{'_correctedquery'};
406             }
407              
408              
409             sub get_replaced_terms {
410 4     4 1 11 my $self = shift;
411 4 50       12 $self->parse_data unless $self->data_parsed;
412 4 50 66     29 if ($self->{'_spelledquery'} && $self->{'_spelledquery'}->{Replaced}) {
413             ref $self->{'_spelledquery'}->{Replaced} ?
414 2 50       8 return @{ $self->{'_spelledquery'}->{Replaced} } : return ();
  2         16  
415             }
416             }
417              
418              
419             sub next_GlobalQuery {
420 0     0 1 0 my $self = shift;
421 0 0       0 $self->parse_data unless $self->data_parsed;
422             $self->{'_globalqueries_it'} = $self->generate_iterator('globalqueries')
423 0 0       0 if (!exists $self->{'_globalqueries_it'});
424 0         0 $self->{'_globalqueries_it'}->();
425             }
426              
427              
428             sub get_GlobalQueries {
429 8     8 1 26 my $self = shift;
430 8 50       22 $self->parse_data unless $self->data_parsed;
431 8 100       26 ref $self->{'_globalqueries'} ? return @{ $self->{'_globalqueries'} } : return ();
  7         25  
432             }
433              
434              
435             sub print_GlobalQueries {
436 0     0 1 0 my ($self, @args) = @_;
437 0         0 $self->_print_handler(@args, -type => 'GlobalQuery');
438             }
439              
440              
441             sub next_DocSum {
442 0     0 1 0 my $self = shift;
443 0 0 0     0 if(!$self->data_parsed && !$self->is_lazy) {
444 0         0 $self->parse_data;
445             }
446             $self->{'_docsums_it'} = $self->generate_iterator('docsums')
447 0 0       0 if (!exists $self->{'_docsums_it'});
448 0         0 $self->{'_docsums_it'}->();
449             }
450              
451              
452             sub get_DocSums {
453 4     4 1 9 my $self = shift;
454 4 50       12 if ($self->is_lazy) {
455 0         0 $self->warn('get_DocSums() not implemented when using lazy mode');
456 0         0 return ();
457             }
458 4 50       10 $self->parse_data unless $self->data_parsed;
459 4 50       15 return ref $self->{'_docsums'} ? @{ $self->{'_docsums'} } : return ();
  4         48  
460             }
461              
462              
463             sub print_DocSums {
464 0     0 1 0 my ($self, @args) = @_;
465 0         0 $self->_print_handler(@args, -type => 'DocSum');
466             }
467              
468              
469             sub get_available_databases {
470 3     3 1 13 my $self = shift;
471 3 100       9 $self->parse_data unless $self->data_parsed;
472             ($self->{'_available_databases'}) ?
473 3 50       11 return @{($self->{'_available_databases'})} :
  3         25  
474             return ();
475             }
476              
477              
478             sub get_record_count {
479 2     2 1 6 my $self = shift;
480 2 50       7 $self->parse_data unless $self->data_parsed;
481 2         10 return $self->{'_count'}
482             }
483              
484              
485             sub get_last_update {
486 2     2 1 4 my $self = shift;
487 2 50       7 $self->parse_data unless $self->data_parsed;
488 2         14 return $self->{'_lastupdate'}
489             }
490              
491              
492             sub get_menu_name {
493 2     2 1 6 my $self = shift;
494 2 50       6 $self->parse_data unless $self->data_parsed;
495             exists $self->{'_menuname'} ? return $self->{'_menuname'} :
496 2 50       15 exists $self->{'_menu'} ? return $self->{'_menu'} :
    100          
497             return;
498             }
499              
500              
501             sub get_description {
502 2     2 1 6 my $self = shift;
503 2 50       7 $self->parse_data unless $self->data_parsed;
504 2         10 return $self->{'_description'};
505             }
506              
507              
508             sub next_FieldInfo {
509 0     0 1 0 my $self = shift;
510 0 0       0 $self->parse_data unless $self->data_parsed;
511             $self->{'_fieldinfo_it'} = $self->generate_iterator('fieldinfo')
512 0 0       0 if (!exists $self->{'_fieldinfo_it'});
513 0         0 $self->{'_fieldinfo_it'}->();
514             }
515              
516              
517             sub get_FieldInfo {
518 2     2 1 6 my $self = shift;
519 2 50       5 $self->parse_data unless $self->data_parsed;
520 2 100       9 return ref $self->{'_fieldinfo'} ? @{ $self->{'_fieldinfo'} } : return ();
  1         7  
521             }
522              
523             *get_FieldInfos = \&get_FieldInfo;
524              
525              
526             sub next_LinkInfo {
527 0     0 1 0 my $self = shift;
528 0 0       0 $self->parse_data unless $self->data_parsed;
529             $self->{'_linkinfo_it'} = $self->generate_iterator('linkinfo')
530 0 0       0 if (!exists $self->{'_linkinfo_it'});
531 0         0 $self->{'_linkinfo_it'}->();
532             }
533              
534              
535             sub get_LinkInfo {
536 2     2 1 561 my $self = shift;
537 2 50       8 $self->parse_data unless $self->data_parsed;
538 2 100       10 return ref $self->{'_linkinfo'} ? @{ $self->{'_linkinfo'} } : return ();
  1         8  
539             }
540              
541             *get_LinkInfos = \&get_LinkInfo;
542              
543              
544             sub print_FieldInfo {
545 0     0 1 0 my ($self, @args) = @_;
546 0         0 $self->_print_handler(@args, -type => 'FieldInfo');
547             }
548              
549              
550             sub print_LinkInfo {
551 0     0 1 0 my ($self, @args) = @_;
552 0         0 $self->_print_handler(@args, -type => 'LinkInfo');
553             }
554              
555              
556             sub next_LinkSet {
557 0     0 1 0 my $self = shift;
558             #$self->parse_data unless $self->data_parsed;
559 0 0 0     0 if(!$self->data_parsed && !$self->is_lazy) {
560 0         0 $self->parse_data;
561             }
562             $self->{'_linksets_it'} = $self->generate_iterator('linksets')
563 0 0       0 if (!exists $self->{'_linksets_it'});
564 0         0 $self->{'_linksets_it'}->();
565             }
566              
567              
568             # add support for retrieval of data if lazy parsing is enacted
569              
570             sub get_LinkSets {
571 52     52 1 93 my $self = shift;
572 52 50       131 if ($self->is_lazy) {
573 0         0 $self->warn('get_LinkSets() not implemented when using lazy mode');
574 0         0 return ();
575             }
576 52 50       130 $self->parse_data unless $self->data_parsed;
577 52 50       130 return ref $self->{'_linksets'} ? @{ $self->{'_linksets'} } : return ();
  52         187  
578             }
579              
580              
581             sub print_LinkSets {
582 0     0 1 0 my ($self, @args) = @_;
583 0         0 $self->_print_handler(@args, -type => 'LinkSet');
584             }
585              
586              
587             sub get_linked_databases {
588 11     11 1 25 my $self = shift;
589 11 50       29 return $self->get_databases if $self->eutil eq 'elink';
590 0         0 return ();
591             }
592              
593              
594             {
595             my %VALID_ITERATORS = (
596             'globalqueries' => 'globalqueries',
597             'fieldinfo' => 'fieldinfo',
598             'fieldinfos' => 'fieldinfo',
599             'linkinfo' => 'linkinfo',
600             'linkinfos' => 'linkinfo',
601             'linksets' => 'linksets',
602             'docsums' => 'docsums',
603             'histories' => 'histories'
604             );
605              
606              
607             sub rewind {
608 0     0 1 0 my ($self, $arg) = ($_[0], lc $_[1]);
609 0         0 my $eutil = $self->eutil;
610 0 0       0 if ($self->is_lazy) {
611 0         0 $self->warn('rewind() not implemented yet when running in lazy mode');
612 0         0 return;
613             }
614 0   0     0 $arg ||= 'all';
615 0 0       0 if (exists $VALID_ITERATORS{$arg}) {
    0          
616 0         0 delete $self->{'_'.$arg.'_it'};
617             } elsif ($arg eq 'all') {
618 0         0 for my $it (values %VALID_ITERATORS){
619             delete $self->{'_'.$it.'_it'} if
620 0 0       0 exists $self->{'_'.$it.'_it'};
621 0         0 map {$_->rewind('all')} $self->get_LinkSets;
  0         0  
622 0         0 map {$_->rewind('all')} $self->get_DocSums;
  0         0  
623             }
624             }
625             }
626              
627              
628             sub generate_iterator {
629 4     4 1 16 my ($self, $obj) = @_;
630 4 50       25 if (!$obj) {
    50          
631 0         0 $self->throw('Must provide object type to iterate');
632             } elsif (!exists $VALID_ITERATORS{$obj}) {
633 0         0 $self->throw("Unknown object type [$obj]");
634             }
635 4         28 my $cb = $self->callback;
636 4 50       17 if ($self->is_lazy) {
637 0 0       0 my $type = $self->eutil eq 'esummary' ? '_docsums' : '_linksets';
638 0         0 $self->{$type} = [];
639             return sub {
640 0 0   0   0 if (!@{$self->{$type}}) {
  0         0  
641 0         0 $self->parse_chunk; # fill the queue
642             }
643 0         0 while (my $obj = shift @{$self->{$type}}) {
  0         0  
644 0 0       0 if ($cb) {
645 0 0       0 ($cb->($obj)) ? return $obj : next;
646             } else {
647 0         0 return $obj;
648             }
649             }
650 0         0 undef;
651             }
652 0         0 } else {
653 4         15 my $loc = '_'.$VALID_ITERATORS{$obj};
654 4         7 my $index = $#{$self->{$loc}};
  4         15  
655 4         10 my $current = 0;
656             return sub {
657 4     4   31 while ($current <= $index) {
658 2 50       14 if ($cb) {
659 0 0       0 if (my $d = $cb->($self->{$loc}->[$current])) {
660 0         0 return $self->{$loc}->[$current++] }
661             else {
662 0         0 $current++;
663 0         0 next;
664             }
665             } else {
666 2         14 return $self->{$loc}->[$current++]
667             }
668             }
669 2         7 undef;
670             }
671 4         31 }
672             }
673              
674             }
675              
676              
677             sub callback {
678 4     4 1 12 my ($self, $cb) = @_;
679 4 50       13 if ($cb) {
680 0 0       0 delete $self->{'_cb'} if ($cb eq 'reset');
681 0 0       0 return if ref $cb ne 'CODE';
682 0         0 $self->{'_cb'} = $cb;
683             }
684 4         14 return $self->{'_cb'};
685             }
686              
687             # Object printing methods
688              
689             {
690             my $DEF_HANDLER = sub {
691             my $obj = shift;
692             return $obj->to_string."\n";
693             };
694              
695             my %HANDLER = (
696             'DocSum' => 1,
697             'FieldInfo' => 1,
698             'LinkInfo' => 1,
699             'GlobalQuery' => 1,
700             'LinkSet' => 1,
701             'all' => 1,
702             );
703              
704             sub _print_handler {
705 0     0   0 my $self = shift;
706 0         0 my ($file, $fh, $cb, $wrap, $type, $all) = $self->_rearrange([qw(FILE FH CB WRAP TYPE ALL)], @_);
707 0   0     0 $type ||= 'all';
708              
709             # default formatting delegates to_string
710 0 0       0 if (!$cb) {
711             $self->throw("Type $type not registered with print handler, exiting...")
712 0 0       0 if !exists($HANDLER{$type});
713 0         0 $cb = $DEF_HANDLER;
714             } else {
715 0 0       0 $self->throw("Callback must be a code reference") if ref $cb ne 'CODE';
716             }
717              
718 0   0     0 $file ||= $fh;
719 0 0 0     0 $self->throw("Have defined both file and filehandle; only use one!") if $file && $fh;
720 0 0       0 my $io = ($file) ? Bio::Root::IO->new(-input => $file, -flush => 1) :
721             Bio::Root::IO->new(-flush => 1); # defaults to STDOUT
722              
723 0 0       0 if ($type eq 'all') {
724 0         0 my $string = $cb->($self);
725 0 0       0 $io->_print($string) if $string;
726             } else {
727             # set up iterator
728 0         0 my $it = "next_$type";
729 0 0       0 $self->throw("Unknown iterator method $it") unless $self->can($it);
730 0         0 while (my $obj = $self->$it) {
731 0         0 my $string = $cb->($obj);
732 0 0       0 $io->_print($string) if $string;
733             }
734             }
735 0         0 $io->close;
736             }
737             }
738              
739             # Private methods
740              
741             sub _seekable {
742 0     0   0 return shift->{'_seekable'}
743             }
744              
745             # fixes odd bad XML issue espell data (still present 6-24-07)
746              
747             sub _fix_espell {
748 1     1   3 my ($self, $response) = @_;
749 1         2 my $temp;
750 1         3 my $type = ref($response);
751 1 50       3 if ($type eq 'GLOB') {
    0          
752 1         47 $temp .= $_ for <$response>;
753             } elsif ($type eq 'HTTP::Response') {
754 0         0 $temp = $response->content;
755             } else {
756 0         0 $self->throw("Unrecognized ref type $type");
757             }
758 1 50       7 if ($temp =~ m{^}) {
759 0         0 $self->throw("NCBI espell nonrecoverable error: HTML content returned")
760             }
761 1         4 $temp =~ s{(.*?)}{$1};
762 1         4 return $temp;
763             }
764              
765             sub _load_eutil_module {
766 22     22   77 my ($self, $class) = @_;
767 22         44 my $ok;
768 22         68 my $module = "Bio::Tools::EUtilities::" . $class;
769              
770 22         43 eval {
771 22         209 $ok = $self->_load_module($module);
772             };
773 22 50       3150 if ( $@ ) {
774 0         0 print STDERR <
775             $self: data module $module cannot be found
776             Exception $@
777             For more information about the EUtilities system please see the EUtilities docs.
778             END
779             ;
780             }
781 22         90 return $ok;
782             }
783              
784             1;
785              
786             __END__