File Coverage

blib/lib/Astro/ADS/Query.pm
Criterion Covered Total %
statement 435 492 88.4
branch 109 154 70.7
condition 11 30 36.6
subroutine 29 32 90.6
pod 13 19 68.4
total 597 727 82.1


line stmt bran cond sub pod time code
1             package Astro::ADS::Query;
2              
3             # ---------------------------------------------------------------------------
4              
5             #+
6             # Name:
7             # Astro::ADS::Query
8              
9             # Purposes:
10             # Perl wrapper for the ADS database
11              
12             # Language:
13             # Perl module
14              
15             # Description:
16             # This module wraps the ADS online database.
17              
18             # Authors:
19             # Alasdair Allan (aa@astro.ex.ac.uk)
20              
21             # Revision:
22             # $Id: Query.pm,v 1.24 2011/07/01 bjd Exp $
23              
24             # Copyright:
25             # Copyright (C) 2001 University of Exeter. All Rights Reserved.
26              
27             #-
28              
29             # ---------------------------------------------------------------------------
30              
31             =head1 NAME
32              
33             Astro::ADS::Query - Object definining an prospective ADS query.
34              
35             =head1 SYNOPSIS
36              
37             $query = new Astro::ADS::Query( Authors => \@authors,
38             AuthorLogic => $aut_logic,
39             Objects => \@objects,
40             ObjectLogic => $obj_logic,
41             Bibcode => $bibcode,
42             Proxy => $proxy,
43             Timeout => $timeout,
44             URL => $url );
45              
46             my $results = $query->querydb();
47              
48             =head1 DESCRIPTION
49              
50             Stores information about an prospective ADS query and allows the query to
51             be made, returning an Astro::ADS::Result object.
52              
53             The object will by default pick up the proxy information from the HTTP_PROXY
54             and NO_PROXY environment variables, see the LWP::UserAgent documentation for
55             details.
56              
57             =cut
58              
59             # L O A D M O D U L E S --------------------------------------------------
60              
61 4     4   76230 use strict;
  4         9  
  4         161  
62 4     4   24 use warnings;
  4         8  
  4         134  
63 4     4   20 use vars qw/ $VERSION /;
  4         8  
  4         237  
64              
65 4     4   9610 use LWP::UserAgent;
  4         303222  
  4         138  
66 4     4   17052 use Astro::ADS::Result;
  4         13  
  4         130  
67 4     4   32 use Astro::ADS::Result::Paper;
  4         7  
  4         100  
68 4     4   3800 use Net::Domain qw(hostname hostdomain);
  4         43918  
  4         306  
69 4     4   42 use Carp;
  4         8  
  4         24184  
70              
71             '$Revision: 1.26 $ ' =~ /.*:\s(.*)\s\$/ && ($VERSION = $1);
72              
73             # C L A S S A T T R I B U T E S ------------------------------------------
74             {
75             my $_ads_mirror = 'cdsads.u-strasbg.fr'; # this is the default mirror site
76             sub ads_mirror {
77 13     13 0 31 my ($class, $new_mirror) = @_;
78 13 100       48 $_ads_mirror = $new_mirror if @_ > 1;
79 13         45 return $_ads_mirror;
80             }
81             }
82              
83             # C O N S T R U C T O R ----------------------------------------------------
84              
85             =head1 REVISION
86              
87             $Id: Query.pm,v 1.25 2013/08/06 bjd Exp $
88             $Id: Query.pm,v 1.24 2009/07/01 bjd Exp $
89             $Id: Query.pm,v 1.22 2009/05/01 bjd Exp $
90             $Id: Query.pm,v 1.21 2002/09/23 21:07:49 aa Exp $
91              
92             =head1 METHODS
93              
94             =head2 Constructor
95              
96             =over 4
97              
98             =item B
99              
100             Create a new instance from a hash of options
101              
102             $query = new Astro::ADS::Query( Authors => \@authors,
103             AuthorLogic => $aut_logic,
104             Objects => \@objects,
105             ObjectLogic => $obj_logic,
106             Bibcode => $bibcode,
107             Proxy => $proxy,
108             Timeout => $timeout,
109             URL => $url );
110              
111             returns a reference to an ADS query object.
112              
113             =cut
114              
115             sub new {
116 9     9 1 197 my $proto = shift;
117 9   33     68 my $class = ref($proto) || $proto;
118              
119             # bless the query hash into the class
120 9         97 my $block = bless { OPTIONS => {},
121             URL => undef,
122             QUERY => undef,
123             FOLLOWUP => undef,
124             USERAGENT => undef,
125             BUFFER => undef }, $class;
126              
127             # Configure the object
128             # does nothing if no arguments supplied
129 9         51 $block->configure( @_ );
130              
131 9         42 return $block;
132              
133             }
134              
135             # Q U E R Y M E T H O D S ------------------------------------------------
136              
137             =back
138              
139             =head2 Accessor Methods
140              
141             =over 4
142              
143             =item B
144              
145             Returns an Astro::ADS::Result object for an inital ADS query
146              
147             $results = $query->querydb();
148              
149             =cut
150              
151             sub querydb {
152 5     5 1 20003882 my $self = shift;
153              
154             # call the private method to make the actual ADS query
155 5         35 $self->_make_query();
156              
157             # check for failed connect
158 5 50       328 return unless defined $self->{BUFFER};
159              
160             # return an Astro::ADS::Result object
161 5         32 return $self->_parse_query();
162              
163             }
164              
165             =item B
166              
167             Returns an Astro::ADS::Result object for a followup query, e.g. CITATIONS,
168             normally called using accessor methods from an Astro::ADS::Paper object, but
169             can be called directly.
170              
171             $results = $query->followup( $bibcode, $link_type );
172              
173             returns undef if no arguements passed. Possible $link_type values are AR,
174             CITATIONS, REFERENCES and TOC.
175              
176             =cut
177              
178             sub followup {
179 3     3 1 7 my $self = shift;
180              
181             # return unless we have arguments
182 3 50       14 return unless @_;
183              
184 3         8 my $bibcode = shift;
185 3         6 my $link_type = shift;
186              
187             # call the private method to make the actual ADS query
188 3         13 $self->_make_followup( $bibcode, $link_type );
189              
190             # check for failed connect
191 3 50       114 return unless defined $self->{BUFFER};
192              
193             # return an Astro::ADS::Result object
194 3         24 return $self->_parse_query();
195              
196             }
197              
198             =item B
199              
200             Return (or set) the current proxy for the ADS request.
201              
202             $query->proxy( 'http://wwwcache.ex.ac.uk:8080/' );
203             $proxy_url = $query->proxy();
204              
205             =cut
206              
207             sub proxy {
208 9     9 1 18367 my $self = shift;
209              
210             # grab local reference to user agent
211 9         24 my $ua = $self->{USERAGENT};
212              
213 9 100       30 if (@_) {
214 2         5 my $proxy_url = shift;
215 2         10 $ua->proxy('http', $proxy_url );
216             }
217              
218             # return the current proxy
219 9         247 return $ua->proxy('http');
220              
221             }
222              
223             =item B
224              
225             Return (or set) the current timeout in seconds for the ADS request.
226              
227             $query->timeout( 30 );
228             $proxy_timeout = $query->timeout();
229              
230             =cut
231              
232             sub timeout {
233 2     2 1 566 my $self = shift;
234              
235             # grab local reference to user agent
236 2         5 my $ua = $self->{USERAGENT};
237              
238 2 100       8 if (@_) {
239 1         4 my $time = shift;
240 1         6 $ua->timeout( $time );
241             }
242              
243             # return the current timeout
244 2         17 return $ua->timeout();
245              
246             }
247              
248             =item B
249              
250             Return (or set) the current base URL for the ADS query.
251              
252             $url = $query->url();
253             $query->url( "adsabs.harvard.edu" );
254              
255             if not defined the default URL is cdsads.u-strasbg.fr
256              
257             As of v1.24, this method sets a class attribute to keep it
258             consistant across all objects. Not terribly thread safe, but
259             at least you know where your query is going.
260              
261             =cut
262              
263             sub url {
264 3     3 1 5 my $self = shift;
265 3         5 my $class = ref($self); # now re-implemented as a class attribute
266              
267             # SETTING URL
268 3 100       11 if (@_) {
269              
270             # set the url option
271 1         2 my $base_url = shift;
272 1         5 $class->ads_mirror( $base_url );
273 1 50       4 if( defined $base_url ) {
274 1         5 $self->{QUERY} = "http://$base_url/cgi-bin/nph-abs_connect?";
275 1         4 $self->{FOLLOWUP} = "http://$base_url/cgi-bin/nph-ref_query?";
276             }
277             }
278              
279             # RETURNING URL
280 3         12 return $class->ads_mirror();
281             }
282              
283             =item B
284              
285             Returns the user agent tag sent by the module to the ADS server.
286              
287             $agent_tag = $query->agent();
288              
289             =cut
290              
291             sub agent {
292 12     12 1 7607 my $self = shift;
293 12         20 my $string = shift;
294 12 100       40 if (defined $string) {
295 7         32 my $agent = $self->{USERAGENT}->agent();
296 7         519 $agent =~ s/(\d+)\s(\[.*\]\s*)?\(/$1 [$string] (/;
297 7         31 return $self->{USERAGENT}->agent($agent);
298             }
299             else {
300 5         79 return $self->{USERAGENT}->agent();
301             }
302             }
303              
304             # O T H E R M E T H O D S ------------------------------------------------
305              
306             =item B
307              
308             Return (or set) the current authors defined for the ADS query.
309              
310             @authors = $query->authors();
311             $first_author = $query->authors();
312             $query->authors( \@authors );
313              
314             if called in a scalar context it will return the first author.
315              
316             =cut
317              
318             sub authors {
319 5     5 0 2269 my $self = shift;
320              
321             # SETTING AUTHORS
322 5 100       13 if (@_) {
323              
324             # clear the current author list
325 2         2 ${$self->{OPTIONS}}{"author"} = "";
  2         5  
326              
327             # grab the new list from the arguements
328 2         3 my $author_ref = shift;
329              
330             # make a local copy to use for regular expressions
331 2         8 my @author_list = @$author_ref;
332              
333             # mutilate it and stuff it into the author list OPTION
334 2         5 for my $i ( 0 ... $#author_list ) {
335 6         19 $author_list[$i] =~ s/\s/\+/g;
336              
337 6 100       15 if ( $i eq 0 ) {
338 2         3 ${$self->{OPTIONS}}{"author"} = $author_list[$i];
  2         4  
339             } else {
340 4         10 ${$self->{OPTIONS}}{"author"} =
  4         8  
341 4         6 ${$self->{OPTIONS}}{"author"} . ";" . $author_list[$i];
342             }
343             }
344             }
345              
346             # RETURNING AUTHORS
347 5         7 my $author_line = ${$self->{OPTIONS}}{"author"};
  5         9  
348 5         19 $author_line =~ s/\+/ /g;
349 5         55 my @authors = split(/;/, $author_line);
350              
351 5 100       22 return wantarray ? @authors : $authors[0];
352             }
353              
354             =item B
355              
356             Return (or set) the logic when dealing with multiple authors for a search,
357             possible values for this parameter are OR, AND, SIMPLE, BOOL and FULLMATCH.
358              
359             $author_logic = $query->authorlogic();
360             $query->authorlogic( "AND" );
361              
362             if called with no arguements, or invalid arguements, then the method will
363             return the current logic.
364              
365             =cut
366              
367             sub authorlogic {
368 2     2 0 531 my $self = shift;
369              
370 2 50       9 if (@_) {
371              
372 2         4 my $logic = shift;
373 2 0 66     15 if ( $logic eq "OR" || $logic eq "AND" || $logic eq "SIMPLE" ||
      33        
      33        
      0        
374             $logic eq "BOOL" || $logic eq "FULLMATCH" ) {
375              
376             # set the new logic
377 2         2 ${$self->{OPTIONS}}{"aut_logic"} = $logic;
  2         9  
378             }
379             }
380              
381 2         3 return ${$self->{OPTIONS}}{"aut_logic"};
  2         7  
382             }
383              
384             =item B
385              
386             Return (or set) the current objects defined for the ADS query.
387              
388             @objects = $query->objects();
389             $query->objects( \@objects );
390              
391             =cut
392              
393             sub objects {
394 4     4 0 61 my $self = shift;
395              
396             # SETTING AUTHORS
397 4 100       13 if (@_) {
398              
399             # clear the current object list
400 3         4 ${$self->{OPTIONS}}{"object"} = "";
  3         8  
401              
402             # grab the new list from the arguements
403 3         5 my $object_ref = shift;
404              
405             # make a local copy to use for regular expressions
406 3         10 my @object_list = @$object_ref;
407              
408             # mutilate it and stuff it into the object list OPTION
409 3         9 for my $i ( 0 ... $#object_list ) {
410 10         36 $object_list[$i] =~ s/\s/\+/g;
411              
412 10 100       24 if ( $i eq 0 ) {
413 3         5 ${$self->{OPTIONS}}{"object"} = $object_list[$i];
  3         9  
414             } else {
415 7         20 ${$self->{OPTIONS}}{"object"} =
  7         18  
416 7         9 ${$self->{OPTIONS}}{"object"} . ";" . $object_list[$i];
417             }
418             }
419             }
420              
421             # RETURNING OBJECTS
422 4         8 my $object_line = ${$self->{OPTIONS}}{"object"};
  4         8  
423 4         15 $object_line =~ s/\+/ /g;
424 4         17 my @objects = split(/;/, $object_line);
425              
426 4         13 return @objects;
427              
428             }
429              
430             =item B
431              
432             Return (or set) the logic when dealing with multiple objects in a search,
433             possible values for this parameter are OR, AND, SIMPLE, BOOL and FULLMATCH.
434              
435             $obj_logic = $query->objectlogic();
436             $query->objectlogic( "AND" );
437              
438             if called with no arguements, or invalid arguements, then the method will
439             return the current logic.
440              
441             =cut
442              
443             sub objectlogic {
444 2     2 0 1088 my $self = shift;
445              
446 2 50       10 if (@_) {
447              
448 2         5 my $logic = shift;
449 2 0 33     20 if ( $logic eq "OR" || $logic eq "AND" || $logic eq "SIMPLE" ||
      33        
      33        
      0        
450             $logic eq "BOOL" || $logic eq "FULLMATCH" ) {
451              
452             # set the new logic
453 2         3 ${$self->{OPTIONS}}{"obj_logic"} = $logic;
  2         6  
454             }
455             }
456              
457 2         4 return ${$self->{OPTIONS}}{"obj_logic"};
  2         7  
458             }
459              
460             =item B
461              
462             Return (or set) the current bibcode used for the ADS query.
463              
464             $bibcode = $query->bibcode();
465             $query->bibcode( "1996PhDT........42J" );
466              
467             =cut
468              
469             sub bibcode {
470 2     2 0 5 my $self = shift;
471              
472             # SETTING BIBCODE
473 2 50       7 if (@_) {
474              
475             # set the bibcode option
476 2         4 ${$self->{OPTIONS}}{"bibcode"} = shift;
  2         5  
477             }
478              
479             # RETURNING BIBCODE
480 2         2 return ${$self->{OPTIONS}}{"bibcode"};
  2         7  
481             }
482              
483              
484             =item B
485              
486             Return (or set) the current starting month of the ADS query.
487              
488             $start_month = $query->startmonth();
489             $query->startmonth( "01" );
490              
491             =cut
492              
493             sub startmonth {
494 2     2 1 278 my $self = shift;
495              
496             # SETTING STARTING MONTH
497 2 100       7 if (@_) {
498              
499             # set the starting month option
500 1         3 ${$self->{OPTIONS}}{"start_mon"} = shift;
  1         5  
501             }
502              
503             # RETURNING STARTING MONTH
504 2         4 return ${$self->{OPTIONS}}{"start_mon"};
  2         10  
505              
506             }
507              
508             =item B
509              
510             Return (or set) the current end month of the ADS query.
511              
512             $end_month = $query->endmonth();
513             $query->endmonth( "12" );
514              
515             =cut
516              
517             sub endmonth {
518 2     2 1 5 my $self = shift;
519              
520             # SETTING END MONTH
521 2 100       9 if (@_) {
522              
523             # set the end month option
524 1         3 ${$self->{OPTIONS}}{"end_mon"} = shift;
  1         4  
525             }
526              
527             # RETURNING END MONTH
528 2         5 return ${$self->{OPTIONS}}{"end_mon"};
  2         9  
529              
530             }
531              
532             =item B
533              
534             Return (or set) the current starting year of the ADS query.
535              
536             $start_year = $query->startyear();
537             $query->start_year( "2001" );
538              
539             =cut
540              
541             sub startyear {
542 2     2 1 6 my $self = shift;
543              
544             # SETTING START YEAR
545 2 100       9 if (@_) {
546              
547             # set the starting year option
548 1         2 ${$self->{OPTIONS}}{"start_year"} = shift;
  1         4  
549             }
550              
551             # RETURNING START YEAR
552 2         3 return ${$self->{OPTIONS}}{"start_year"};
  2         10  
553              
554             }
555              
556             =item B
557              
558             Return (or set) the current end year of the ADS query.
559              
560             $end_year = $query->endyear();
561             $query->end_year( "2002" );
562              
563             =cut
564              
565             sub endyear {
566 2     2 1 5 my $self = shift;
567              
568             # SETTING END YEAR
569 2 100       8 if (@_) {
570              
571             # set the end year option
572 1         3 ${$self->{OPTIONS}}{"end_year"} = shift;
  1         6  
573             }
574              
575             # RETURNING END YEAR
576 2         4 return ${$self->{OPTIONS}}{"end_year"};
  2         10  
577              
578             }
579              
580             =item B
581              
582             Return (or set) whether refereed, non-refereed (OTHER) or all bibilographic sources (ALL) are returned.
583              
584             $query->journal( "REFEREED" );
585             $query->journal( "OTHER" );
586             $query->journal( "ALL" );
587            
588             $journals = $query->journal();
589              
590             the default is ALL bibilographic sources
591              
592             =cut
593              
594             sub journal {
595 0     0 1 0 my $self = shift;
596              
597             # SETTING END YEAR
598 0 0       0 if (@_) {
599              
600 0         0 my $source = shift;
601            
602 0 0       0 if ( $source eq "REFEREED" ) {
    0          
603 0         0 ${$self->{OPTIONS}}{"jou_pick"} = "NO";
  0         0  
604             } elsif ( $source eq "OTHER" ) {
605 0         0 ${$self->{OPTIONS}}{"jou_pick"} = "EXCL";
  0         0  
606             } else {
607 0         0 ${$self->{OPTIONS}}{"jou_pick"} = "ALL";
  0         0  
608             }
609              
610             }
611              
612             # RETURNING END YEAR
613 0         0 return ${$self->{OPTIONS}}{"jou_pick"};
  0         0  
614              
615             }
616              
617             # C O N F I G U R E -------------------------------------------------------
618              
619             =back
620              
621             =head2 General Methods
622              
623             =over 4
624              
625             =item B
626              
627             Configures the object, takes an options hash as an argument
628              
629             $query->configure( %options );
630              
631             Does nothing if the array is not supplied.
632              
633             =cut
634              
635             sub configure {
636 9     9 1 19 my $self = shift;
637 9         24 my $class = ref($self);
638              
639             # CONFIGURE DEFAULTS
640             # ------------------
641              
642             # define the default base URL
643 9         47 my $default_url = $class->ads_mirror();
644            
645             # define the query URLs
646 9         56 $self->{QUERY} = "http://$default_url/cgi-bin/nph-abs_connect?";
647 9         33 $self->{FOLLOWUP} = "http://$default_url/cgi-bin/nph-ref_query?";
648              
649            
650             # Setup the LWP::UserAgent
651 9         57 my $HOST = hostname();
652 9         31873 my $DOMAIN = hostdomain();
653 9         407 $self->{USERAGENT} = new LWP::UserAgent( timeout => 30 );
654 9         277091 $self->{USERAGENT}->agent("Astro::ADS/$VERSION ($HOST.$DOMAIN)");
655              
656             # Grab Proxy details from local environment
657 9         540 $self->{USERAGENT}->env_proxy();
658              
659             # configure the default options
660 9         59200 ${$self->{OPTIONS}}{"db_key"} = "AST";
  9         52  
661 9         19 ${$self->{OPTIONS}}{"sim_query"} = "YES";
  9         35  
662 9         23 ${$self->{OPTIONS}}{"aut_xct"} = "NO";
  9         27  
663 9         18 ${$self->{OPTIONS}}{"aut_logic"} = "OR";
  9         30  
664 9         14 ${$self->{OPTIONS}}{"obj_logic"} = "OR";
  9         28  
665 9         14 ${$self->{OPTIONS}}{"author"} = "";
  9         29  
666 9         21 ${$self->{OPTIONS}}{"object"} = "";
  9         28  
667 9         15 ${$self->{OPTIONS}}{"keyword"} = "";
  9         38  
668 9         14 ${$self->{OPTIONS}}{"start_mon"} = "";
  9         31  
669 9         15 ${$self->{OPTIONS}}{"start_year"} = "";
  9         26  
670 9         19 ${$self->{OPTIONS}}{"end_mon"} = "";
  9         71  
671 9         14 ${$self->{OPTIONS}}{"end_year"} = "";
  9         28  
672 9         14 ${$self->{OPTIONS}}{"ttl_logic"} = "OR";
  9         32  
673 9         14 ${$self->{OPTIONS}}{"title"} = "";
  9         23  
674 9         17 ${$self->{OPTIONS}}{"txt_logic"} = "OR";
  9         22  
675 9         17 ${$self->{OPTIONS}}{"text"} = "";
  9         36  
676 9         17 ${$self->{OPTIONS}}{"nr_to_return"} = "100";
  9         30  
677 9         17 ${$self->{OPTIONS}}{"start_nr"} = "1";
  9         24  
678 9         11 ${$self->{OPTIONS}}{"start_entry_day"} = "";
  9         27  
679 9         12 ${$self->{OPTIONS}}{"start_entry_mon"} = "";
  9         22  
680 9         16 ${$self->{OPTIONS}}{"start_entry_year"} = "";
  9         29  
681 9         13 ${$self->{OPTIONS}}{"min_score"} = "";
  9         21  
682 9         14 ${$self->{OPTIONS}}{"jou_pick"} = "ALL";
  9         25  
683 9         14 ${$self->{OPTIONS}}{"ref_stems"} = "";
  9         22  
684 9         15 ${$self->{OPTIONS}}{"data_and"} = "ALL";
  9         26  
685 9         13 ${$self->{OPTIONS}}{"group_and"} = "ALL";
  9         23  
686 9         15 ${$self->{OPTIONS}}{"sort"} = "SCORE";
  9         25  
687 9         16 ${$self->{OPTIONS}}{"aut_syn"} = "YES";
  9         24  
688 9         15 ${$self->{OPTIONS}}{"ttl_syn"} = "YES";
  9         23  
689 9         12 ${$self->{OPTIONS}}{"txt_syn"} = "YES";
  9         25  
690 9         12 ${$self->{OPTIONS}}{"aut_wt"} = "1.0";
  9         23  
691 9         15 ${$self->{OPTIONS}}{"obj_wt"} = "1.0";
  9         39  
692 9         16 ${$self->{OPTIONS}}{"ttl_wt"} = "0.3";
  9         30  
693 9         17 ${$self->{OPTIONS}}{"txt_wt"} = "3.0";
  9         23  
694 9         17 ${$self->{OPTIONS}}{"aut_wgt"} = "YES";
  9         22  
695 9         12 ${$self->{OPTIONS}}{"obj_wgt"} = "YES";
  9         27  
696 9         13 ${$self->{OPTIONS}}{"ttl_wgt"} = "YES";
  9         24  
697 9         16 ${$self->{OPTIONS}}{"txt_wgt"} = "YES";
  9         21  
698 9         27 ${$self->{OPTIONS}}{"ttl_sco"} = "YES";
  9         28  
699 9         16 ${$self->{OPTIONS}}{"txt_sco"} = "YES";
  9         25  
700 9         25 ${$self->{OPTIONS}}{"version"} = "1";
  9         24  
701 9         14 ${$self->{OPTIONS}}{"bibcode"} = "";
  9         22  
702              
703             # Set the data_type option to PORTABLE so our regular expressions work!
704             # Set the return format to LONG so we get full abstracts!
705 9         15 ${$self->{OPTIONS}}{"data_type"} = "PORTABLE";
  9         23  
706 9         15 ${$self->{OPTIONS}}{"return_fmt"} = "LONG";
  9         23  
707              
708             # CONFIGURE FROM ARGUEMENTS
709             # -------------------------
710              
711             # return unless we have arguments
712 9 100       50 return unless @_;
713              
714             # grab the argument list
715 5         21 my %args = @_;
716              
717             # Loop over the allowed keys and modify the default query options
718 5         16 for my $key (qw / Authors AuthorLogic Objects ObjectLogic Bibcode
719             StartMonth EndMonth StartYear EndYear Journal
720             Proxy Timeout URL/ ) {
721 65         75 my $method = lc($key);
722 65 100       178 $self->$method( $args{$key} ) if exists $args{$key};
723             }
724              
725             }
726              
727             # T I M E A T T H E B A R --------------------------------------------
728              
729             =back
730              
731             =begin __PRIVATE_METHODS__
732              
733             =head2 Private methods
734              
735             These methods are for internal use only.
736              
737             =over 4
738              
739             =item B<_make_query>
740              
741             Private function used to make an ADS query. Should not be called directly,
742             since it does not parse the results. Instead use the querydb() assessor method.
743              
744             =cut
745              
746             sub _make_query {
747 5     5   13 my $self = shift;
748              
749             # grab the user agent
750 5         22 my $ua = $self->{USERAGENT};
751              
752             # clean out the buffer
753 5         20 $self->{BUFFER} = "";
754              
755             # grab the base URL
756 5         21 my $URL = $self->{QUERY};
757 5         10 my $options = "";
758              
759             # loop round all the options keys and build the query
760 5         12 foreach my $key ( keys %{$self->{OPTIONS}} ) {
  5         128  
761             # some bibcodes have & and needs to be made "web safe"
762 220         231 my $websafe_option = ${$self->{OPTIONS}}{$key};
  220         1875  
763 220         305 $websafe_option =~ s/&/%26/g;
764 220         1214 $options = $options . "&$key=$websafe_option";
765              
766             }
767              
768             # build final query URL
769 5         188 $URL = $URL . $options;
770            
771             # build request
772 5         272 my $request = new HTTP::Request('GET', $URL);
773              
774             # grab page from web
775 5         13445 my $reply = $ua->request($request);
776              
777 5 50       10507135 if ( ${$reply}{"_rc"} eq 200 ) {
  5 0       40  
  0         0  
778            
779             # stuff the page contents into the buffer
780 5         12 $self->{BUFFER} = ${$reply}{"_content"};
  5         662  
781            
782             } elsif ( ${$reply}{"_rc"} eq 500 ) {
783            
784             # we may have a network unreachable, or we may have a no reference
785             # selected error returned by ADS (go figure)
786              
787 0         0 $self->{BUFFER} = ${$reply}{"_content"};
  0         0  
788 0         0 my @buffer = split( /\n/,$self->{BUFFER});
789 0         0 chomp @buffer;
790            
791             # assume we have an error unless we can prove otherwise
792 0         0 my $error_flag = 1;
793            
794 0         0 foreach my $line ( 0 ... $#buffer ) {
795 0 0       0 if( $buffer[$line] =~ "No reference selected" ) {
796            
797             # increment the counter and drop out of the loop
798 0         0 $line = $#buffer;
799 0         0 $error_flag = 0;
800             }
801             }
802            
803             # we definately have an error
804 0 0       0 if( $error_flag ) {
805 0         0 $self->{BUFFER} = undef;
806 0         0 my $proxy_string = undef;
807 0 0       0 if ($proxy_string = $ua->proxy('http')) { substr($proxy_string, 0, 0) = ' using proxy '; }
  0         0  
808 0         0 else { $proxy_string = ' (no proxy)'; }
809 0         0 croak("Error ${$reply}{_rc}: Failed to establish network connection to $URL",
  0         0  
810             $proxy_string, "\n");
811             }
812            
813             } else {
814 0         0 $self->{BUFFER} = undef;
815 0         0 my $proxy_string = undef;
816 0 0       0 if ($proxy_string = $ua->proxy('http')) { substr($proxy_string, 0, 0) = ' using proxy '; }
  0         0  
817 0         0 else { $proxy_string = ' (no proxy)'; }
818 0         0 croak("Error ${$reply}{_rc}: Failed to establish network connection to $URL",
  0         0  
819             $proxy_string, "\n");
820             }
821            
822            
823             }
824              
825             =item B<_make_followup>
826              
827             Private function used to make a followup ADS query, e.g. REFERNCES, called
828             from the followup() assessor method. Should not be called directly.
829              
830             =cut
831              
832             sub _make_followup {
833 3     3   6 my $self = shift;
834              
835             # grab the user agent
836 3         15 my $ua = $self->{USERAGENT};
837              
838             # clean out the buffer
839 3         6 $self->{BUFFER} = "";
840              
841             # grab the base URL
842 3         7 my $URL = $self->{FOLLOWUP};
843              
844             # which paper?
845 3         7 my $bibcode = shift;
846 3         11 $bibcode =~ s/&/%26/g; # make ampersands websafe
847              
848             # which followup?
849 3         5 my $refs = shift;
850              
851             # which database?
852 3         4 my $db_key = ${$self->{OPTIONS}}{"db_key"};
  3         10  
853 3         4 my $data_type = ${$self->{OPTIONS}}{"data_type"};
  3         9  
854 3         5 my $fmt = ${$self->{OPTIONS}}{"return_fmt"};
  3         7  
855              
856             # build the final query URL
857 3         16 $URL = $URL . "bibcode=$bibcode&refs=$refs&db_key=$db_key&data_type=$data_type&return_fmt=$fmt";
858              
859             # build request
860 3         33 my $request = new HTTP::Request('GET', $URL);
861              
862             # grab page from web
863 3         11592 my $reply = $ua->request($request);
864              
865 3 50       12033404 if ( ${$reply}{"_rc"} eq 200 ) {
  3         98  
866             # stuff the page contents into the buffer
867 3         12 $self->{BUFFER} = ${$reply}{"_content"};
  3         2750749  
868             } else {
869 0         0 $self->{BUFFER} = undef;
870 0         0 my $proxy_string = undef;
871 0 0       0 if ($proxy_string = $ua->proxy('http')) { substr($proxy_string, 0, 0) = ' using proxy '; }
  0         0  
872 0         0 else { $proxy_string = ' (no proxy) '; }
873 0         0 croak("Error ${$reply}{_rc}: Failed to establish network connection to $URL" .
  0         0  
874             $proxy_string . $self->{BUFFER} ."\n");
875             }
876             }
877              
878             =item B<_parse_query>
879              
880             Private function used to parse the results returned in an ADS query. Should
881             not be called directly. Instead use the querydb() assessor method to make and
882             parse the results.
883              
884             =cut
885              
886             sub _parse_query {
887 8     8   24 my $self = shift;
888              
889             # get a local copy of the current BUFFER
890 8         10110 my @buffer = split( /\n/,$self->{BUFFER});
891 8         888 chomp @buffer;
892              
893             # create an Astro::ADS::Result object to hold the search results
894 8         154 my $result = new Astro::ADS::Result();
895              
896             # create a temporary object to hold papers
897 8         18 my $paper;
898              
899             # loop round the returned buffer and stuff the contents into Paper objects
900 8         13 my ( $next, $counter );
901 8         16 $next = $counter = 0;
902 8         41 foreach my $line ( 0 ... $#buffer ) {
903              
904             # R Bibcode
905             # T Title
906             # A Author List
907             # F Affiliations
908             # J Journal Reference
909             # D Publication Date
910             # K Keywords
911             # G Origin
912             # I Outbound Links
913             # U Document URL
914             # O Object name
915             # B Abstract
916             # S Score
917              
918             # NO ABSTRACTS
919 10213 100       46924 if( $buffer[$line] =~ "Retrieved 0 abstracts" ) {
920              
921             # increment the counter and drop out of the loop
922 1         3 $line = $#buffer;
923            
924             }
925            
926             # NO ABSTRACT (HTML version)
927 10213 50       21805 if( $buffer[$line] =~ "No reference selected" ) {
928            
929             # increment the counter and drop out of the loop
930 0         0 $line = $#buffer;
931             }
932            
933             # NEW PAPER
934 10213 100       22064 if( substr( $buffer[$line], 0, 2 ) eq "%R" ) {
935              
936 232         345 $counter = $line;
937 232         595 my $tag = substr( $buffer[$counter], 1, 1 );
938              
939             # grab the bibcode
940 232         523 my $bibcode = substr( $buffer[$counter], 2 );
941 232         1969 $bibcode =~ s/\s+//g;
942              
943             # New Astro::ADS::Result::Paper object
944 232         1148 $paper = new Astro::ADS::Result::Paper( Bibcode => $bibcode );
945              
946 232         300 $counter++;
947              
948             # LOOP THROUGH PAPER
949 232         429 my ( @title, @authors, @affil, @journal, @pubdate, @keywords,
950             @origin, @links, @url, @object, @abstract, @score );
951 232   100     2488 while ( $counter <= $#buffer &&
952             substr( $buffer[$counter], 0, 2 ) ne "%R" ) {
953              
954              
955             # grab the tags
956 9936 100       28355 if( substr( $buffer[$counter], 0, 1 ) eq "%" ) {
957 3477         7789 $tag = substr( $buffer[$counter], 1, 1 );
958             }
959              
960             # ckeck for each tag and stuff the contents into the paper object
961              
962             # TITLE
963             # -----
964 9936 100       26557 if( $tag eq "T" ) {
965              
966             #do we have the start of an title block?
967 309 100       725 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
968              
969             # push the end of line substring onto array
970 231         529 push ( @title, substr( $buffer[$counter], 3 ) );
971              
972             } else {
973              
974             # push the entire line onto the array
975 78         161 push (@title, $buffer[$counter] );
976              
977             }
978             }
979              
980             # AUTHORS
981             # -------
982 9936 100       22601 if( $tag eq "A" ) {
983              
984             #do we have the start of an author block?
985 372 100       791 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
986              
987             # push the end of line substring onto array
988 232         563 push ( @authors, substr( $buffer[$counter], 3 ) );
989              
990             } else {
991              
992             # push the entire line onto the array
993 140         247 push (@authors, $buffer[$counter] );
994              
995             }
996             }
997              
998             # AFFILIATION
999             # -----------
1000 9936 100       19597 if( $tag eq "F" ) {
1001              
1002             #do we have the start of an affil block?
1003 1241 100       2779 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1004              
1005             # push the end of line substring onto array
1006 164         454 push ( @affil, substr( $buffer[$counter], 3 ) );
1007              
1008             } else {
1009              
1010             # push the entire line onto the array
1011 1077         2432 push (@affil, $buffer[$counter] );
1012              
1013             }
1014             }
1015              
1016             # JOURNAL REF
1017             # -----------
1018 9936 100       18152 if( $tag eq "J" ) {
1019              
1020             #do we have the start of an journal block?
1021 366 100       735 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1022              
1023             # push the end of line substring onto array
1024 232         546 push ( @journal, substr( $buffer[$counter], 3 ) );
1025              
1026             } else {
1027              
1028             # push the entire line onto the array
1029 134         230 push (@journal, $buffer[$counter] );
1030              
1031             }
1032             }
1033              
1034             # PUBLICATION DATE
1035             # ----------------
1036 9936 100       22659 if( $tag eq "D" ) {
1037              
1038             #do we have the start of an publication date block?
1039 232 50       508 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1040              
1041             # push the end of line substring onto array
1042 232         497 push ( @pubdate, substr( $buffer[$counter], 3 ) );
1043              
1044             } else {
1045              
1046             # push the entire line onto the array
1047 0         0 push (@pubdate, $buffer[$counter] );
1048              
1049             }
1050             }
1051              
1052             # KEYWORDS
1053             # --------
1054 9936 100       27244 if( $tag eq "K" ) {
1055              
1056             #do we have the start of an keyword block?
1057 332 100       661 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1058              
1059             # push the end of line substring onto array
1060 157         329 push ( @keywords, substr( $buffer[$counter], 3 ) );
1061              
1062             } else {
1063              
1064             # push the entire line onto the array
1065 175         1496 push (@keywords, $buffer[$counter] );
1066              
1067             }
1068             }
1069              
1070             # ORIGIN
1071             # ------
1072 9936 100       26935 if( $tag eq "G" ) {
1073              
1074             #do we have the start of an origin block?
1075 232 50       500 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1076              
1077             # push the end of line substring onto array
1078 232         506 push ( @origin, substr( $buffer[$counter], 3 ) );
1079              
1080             } else {
1081              
1082             # push the entire line onto the array
1083 0         0 push (@origin, $buffer[$counter] );
1084              
1085             }
1086             }
1087              
1088             # LINKS
1089             # -----
1090 9936 100       20082 if( $tag eq "I" ) {
1091              
1092             #do we have the start of an author block?
1093 1601 100       3194 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1094              
1095             # push the end of line substring onto array
1096 284         667 push ( @links, substr( $buffer[$counter], 3 ) );
1097              
1098             } else {
1099              
1100             # push the entire line onto the array
1101 1317         2492 push (@links, $buffer[$counter] );
1102              
1103             }
1104             }
1105              
1106             # URL
1107             # ---
1108 9936 100       18121 if( $tag eq "U" ) {
1109              
1110             #do we have the start of an URL block?
1111 232 50       522 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1112              
1113             # push the end of line substring onto array
1114 232         602 push ( @url, substr( $buffer[$counter], 3 ) );
1115              
1116             } else {
1117              
1118             # push the entire line onto the array
1119 0         0 push (@url, $buffer[$counter] );
1120              
1121             }
1122             }
1123              
1124             # OBJECT
1125             # ------
1126 9936 100       20994 if( $tag eq "O" ) {
1127              
1128             #do we have the start of an title block?
1129 3 50       131 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1130              
1131             # push the end of line substring onto array
1132 3         8 push ( @object, substr( $buffer[$counter], 3 ) );
1133              
1134             } else {
1135              
1136             # push the entire line onto the array
1137 0         0 push (@object, $buffer[$counter] );
1138              
1139             }
1140             }
1141              
1142             # ABSTRACT
1143             # --------
1144 9936 100       18376 if( $tag eq "B" ) {
1145              
1146             #do we have the start of an title block?
1147 3505 100       7707 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1148              
1149             # push the end of line substring onto array
1150 232         898 push ( @abstract, substr( $buffer[$counter], 3 ) );
1151              
1152             } else {
1153              
1154             # push the entire line onto the array
1155 3273         8171 push (@abstract, $buffer[$counter] );
1156              
1157             }
1158             }
1159              
1160             # SCORE
1161             # -----
1162 9936 100       17268 if( $tag eq "S" ) {
1163              
1164             #do we have the start of an title block?
1165 232 50       800 if ( substr( $buffer[$counter], 0, 1 ) eq "%") {
1166              
1167             # push the end of line substring onto array
1168 232         636 push ( @score, substr( $buffer[$counter], 3 ) );
1169              
1170             } else {
1171              
1172             # push the entire line onto the array
1173 0         0 push (@score, $buffer[$counter] );
1174              
1175             }
1176             }
1177              
1178              
1179             # set the next paper increment
1180 9936         13283 $next = $counter;
1181             # increment the line counter
1182 9936         78452 $counter++;
1183              
1184             }
1185              
1186             # PUSH TITLE INTO PAPER OBJECT
1187             # ----------------------------
1188 232         729 chomp @title;
1189 232         365 my $title_line = "";
1190 232         604 for my $i ( 0 ... $#title ) {
1191             # drop it onto one line
1192 309         1059 $title_line = $title_line . $title[$i];
1193             }
1194 232 100       1833 $paper->title( $title_line ) if defined $title[0];
1195              
1196             # PUSH AUTHORS INTO PAPER OBJECT
1197             # ------------------------------
1198 232         465 chomp @authors;
1199 232         322 my $author_line = "";
1200 232         502 for my $i ( 0 ... $#authors ) {
1201             # drop it onto one line
1202 372         858 $author_line = $author_line . $authors[$i];
1203             }
1204             # get rid of leading spaces before author names
1205 232         1972 $author_line =~ s/;\s+/;/g;
1206              
1207 232         2544 my @paper_authors = split( /;/, $author_line );
1208 232 50       1149 $paper->authors( \@paper_authors ) if defined $authors[0];
1209              
1210             # PUSH AFFILIATION INTO PAPER OBJECT
1211             # ----------------------------------
1212 232         927 chomp @affil;
1213 232         310 my $affil_line = "";
1214 232         512 for my $i ( 0 ... $#affil ) {
1215             # drop it onto one line
1216 1241         2807 $affil_line = $affil_line . $affil[$i];
1217             }
1218             # grab each affiliation from its brackets
1219 232         2508 $affil_line =~ s/\w\w\(//g;
1220              
1221 232         4750 my @paper_affil = split( /\), /, $affil_line );
1222 232 100       1437 $paper->affil( \@paper_affil ) if defined $affil[0];
1223              
1224             # PUSH JOURNAL INTO PAPER OBJECT
1225             # ------------------------------
1226 232         7529 chomp @journal;
1227 232         330 my $journal_ref = "";
1228 232         479 for my $i ( 0 ... $#journal ) {
1229             # drop it onto one line
1230 366         1063 $journal_ref = $journal_ref . $journal[$i];
1231             }
1232 232 50       1223 $paper->journal( $journal_ref ) if defined $journal[0];
1233              
1234             # PUSH PUB DATE INTO PAPER OBJECT
1235             # -------------------------------
1236 232         373 chomp @pubdate;
1237 232         336 my $pub_date = "";
1238 232         497 for my $i ( 0 ... $#pubdate ) {
1239             # drop it onto one line
1240 232         618 $pub_date = $pub_date . $pubdate[$i];
1241             }
1242 232 50       992 $paper->published( $pub_date ) if defined $pubdate[0];
1243              
1244             # PUSH KEYWORDS INTO PAPER OBJECT
1245             # -------------------------------
1246 232         418 chomp @keywords;
1247 232         547 my $key_line = "";
1248 232         442 for my $i ( 0 ... $#keywords ) {
1249             # drop it onto one line
1250 332         636 $key_line = $key_line . $keywords[$i];
1251             }
1252             # get rid of excess spaces
1253 232         1113 $key_line =~ s/, /,/g;
1254              
1255 232         1631 my @paper_keys = split( /,/, $key_line );
1256 232 100       920 $paper->keywords( \@paper_keys ) if defined $keywords[0];
1257              
1258             # PUSH ORIGIN INTO PAPER OBJECT
1259             # -----------------------------
1260 232         374 chomp @origin;
1261 232         303 my $origin_line = "";
1262 232         429 for my $i ( 0 ... $#origin) {
1263             # drop it onto one line
1264 232         537 $origin_line = $origin_line . $origin[$i];
1265             }
1266 232 50       1014 $paper->origin( $origin_line ) if defined $origin[0];
1267              
1268             # PUSH LINKS INTO PAPER OBJECT
1269             # ----------------------------
1270 232         1163 chomp @links;
1271 232         303 my $links_line = "";
1272 232         445 for my $i ( 0 ... $#links ) {
1273             # drop it onto one line
1274 1601         3181 $links_line = $links_line . $links[$i];
1275             }
1276             # annoying complex reg exp to get rid of formatting
1277 232         3546 $links_line =~ s/:.*?;\s*/;/g;
1278              
1279 232         3085 my @paper_links = split( /;/, $links_line );
1280 232 50       1114 $paper->links( \@paper_links ) if defined $links[0];
1281              
1282             # PUSH URL INTO PAPER OBJECT
1283             # --------------------------
1284 232         524 chomp @url;
1285 232         314 my $url_line = "";
1286 232         705 for my $i ( 0 ... $#url ) {
1287             # drop it onto one line
1288 232         660 $url_line = $url_line . $url[$i];
1289             }
1290             # get rid of trailing spaces
1291 232         775 $url_line =~ s/\s+$//;
1292 232 50       898 $paper->url( $url_line ) if defined $url[0];
1293              
1294             # PUSH OBJECT INTO PAPER OBJECT
1295             # -----------------------------
1296 232         349 chomp @object;
1297 232         316 my $object_line = "";
1298 232         1650 for my $i ( 0 ... $#object ) {
1299             # drop it onto one line
1300 3         11 $object_line = $object_line . $object[$i];
1301             }
1302 232 100       550 $paper->object( $object_line ) if defined $object[0];
1303              
1304             # PUSH ABSTRACT INTO PAPER OBJECT
1305             # -------------------------------
1306 232         1723 chomp @abstract;
1307 232         482 for my $i ( 0 ... $#abstract ) {
1308             # get rid of trailing spaces
1309 3505         17570 $abstract[$i] =~ s/\s+$//;
1310             }
1311 232 50       1523 $paper->abstract( \@abstract ) if defined $abstract[0];
1312              
1313             # PUSH SCORE INTO PAPER OBJECT
1314             # ----------------------------
1315 232         379 chomp @score;
1316 232         1516 my $score_line = "";
1317 232         651 for my $i ( 0 ... $#score ) {
1318             # drop it onto one line
1319 232         529 $score_line = $score_line . $score[$i];
1320             }
1321 232 50       1049 $paper->score( $score_line ) if defined $score[0];
1322              
1323              
1324             }
1325              
1326             # Increment the line counter to the correct index for the next paper
1327 10213         10344 $line += $next;
1328              
1329             # Push the new paper onto the Astro::ADS::Result object
1330             # -----------------------------------------------------
1331 10213 100       20390 $result->pushpaper($paper) if defined $paper;
1332 10213         25282 $paper = undef;
1333              
1334             }
1335              
1336             # return an Astro::ADS::Result object, or undef if no abstracts returned
1337 8         1165 return $result;
1338              
1339             }
1340              
1341             =item B<_dump_raw>
1342              
1343             Private function for debugging and other testing purposes. It will return
1344             the raw output of the last ADS query made using querydb().
1345              
1346             =cut
1347              
1348             sub _dump_raw {
1349 0     0     my $self = shift;
1350              
1351             # split the BUFFER into an array
1352 0           my @portable = split( /\n/,$self->{BUFFER});
1353 0           chomp @portable;
1354              
1355 0           return @portable;
1356             }
1357              
1358             =item B<_dump_options>
1359              
1360             Private function for debugging and other testing purposes. It will return
1361             the current query options as a hash.
1362              
1363             =cut
1364              
1365             sub _dump_options {
1366 0     0     my $self = shift;
1367              
1368 0           return %{$self->{OPTIONS}};
  0            
1369             }
1370              
1371             =back
1372              
1373             =end __PRIVATE_METHODS__
1374              
1375             =head1 BUGS
1376              
1377             =over
1378              
1379             =item #35645 filed at rt.cpan.org (Ampersands)
1380              
1381             Older versions can't handle ampersands in the bibcode, such as A&A for Astronomy & Astrophysics.
1382             Fixed for queries in 1.22 - 5/2009.
1383             Fixed for references in 1.23 - Boyd Duffee Eb dot duffee at isc dot keele dot ac dot ukE, 7/2011.
1384              
1385             =back
1386              
1387              
1388             =head1 COPYRIGHT
1389              
1390             Copyright (C) 2001 University of Exeter. All Rights Reserved.
1391              
1392             This program was written as part of the eSTAR project and is free software;
1393             you can redistribute it and/or modify it under the terms of the GNU Public
1394             License.
1395              
1396             =head1 AUTHORS
1397              
1398             Alasdair Allan Eaa@astro.ex.ac.ukE,
1399              
1400             =cut
1401              
1402             # L A S T O R D E R S ------------------------------------------------------
1403              
1404             1;