File Coverage

blib/lib/Catmandu/Importer/PubMed.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Catmandu::Importer::PubMed;
2              
3 2     2   66864 use Catmandu::Sane;
  2         236992  
  2         12  
4 2     2   596 use Moo;
  2         4  
  2         11  
5 2     2   2330 use Furl;
  2         61799  
  2         69  
6 2     2   870 use XML::LibXML::Simple qw(XMLin);
  0            
  0            
7              
8             with 'Catmandu::Importer';
9              
10              
11             # INFO:
12             # http://www.ncbi.nlm.nih.gov/books/NBK25499/
13              
14              
15             # Constants. -------------------------------------------------------------------
16              
17             use constant EUTILS_BASE => 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/';
18             use constant ESEARCH_AFFIX => 'esearch.fcgi';
19             use constant EFETCH_AFFIX => 'efetch.fcgi';
20             use constant DATABASE => 'pubmed';
21              
22              
23             # Properties. ------------------------------------------------------------------
24              
25             # required.
26             has base => (is => 'ro', default => sub { return EUTILS_BASE; });
27             has db => (is => 'ro', default => sub { return DATABASE; });
28             has term => (is => 'ro', required => 1);
29              
30             # optional.
31             has field => (is => 'ro');
32             has datetype => (is => 'ro');
33             has reldate => (is => 'ro');
34             has mindate => (is => 'ro');
35             has maxdate => (is => 'ro');
36              
37             # internal stuff.
38             has _currentRecordSet => (is => 'ro');
39             has _n => (is => 'ro');
40              
41              
42             # Internal Methods. ------------------------------------------------------------
43              
44             # Internal: Does a generic HTTP GET request.
45             #
46             # $url - The url of the resource to get.
47             #
48             # Returns the raw response body.
49             sub _request {
50             my ($self, $url) = @_;
51              
52             my $furl = Furl->new(
53             agent => 'Mozilla/5.0',
54             timeout => 10
55             );
56              
57             my $res = $furl->get($url);
58             die $res->status_line unless $res->is_success;
59              
60             return $res;
61             }
62              
63             # Internal: Converts XML to a perl hash.
64             #
65             # $url - The raw XML input.
66             #
67             # Returns a hash from the given XML.
68             sub _hashify {
69             my ($self, $in) = @_;
70              
71             my $xs = XML::LibXML::Simple->new();
72             my $out = $xs->XMLin(
73             $in,
74             ForceArray => [ 'PubmedData' ]
75             );
76              
77             return $out;
78             }
79              
80             # Internal: eSearch request (text searches).
81             #
82             # Responds to a text query with the list of matching UIDs in a given database
83             # (for later use in ESummary, EFetch or ELink), along with the term translations
84             # of the query.
85             #
86             # Returns eSearch XML document.
87             sub _eSearch {
88             my ($self) = @_;
89              
90             my $url = $self->base . ESEARCH_AFFIX
91             . '?db=' . $self->db
92             . '&term=' . $self->term
93             . '&usehistory=y';
94              
95             $url .= '&field=' . $self->field if ($self->field);
96             $url .= '&datetype=' . $self->datetype if ($self->datetype);
97             $url .= '&reldate=' . $self->reldate if ($self->reldate);
98             $url .= '&mindate=' . $self->mindate if ($self->mindate);
99             $url .= '&maxdate=' . $self->maxdate if ($self->maxdate);
100              
101             # Fetch.
102             my $res = $self->_request($url);
103              
104             return $res->{content};
105             }
106              
107             # Internal: eFetch request (data record downloads).
108             #
109             # Responds to a list of UIDs in a given database
110             # with the corresponding data records in a specified format.
111             #
112             # $webEnv - webEnv param.
113             # $queryKey - query_key param.
114             #
115             # Returns Formatted data records (e.g. abstracts, FASTA).
116             sub _eFetch {
117             my ($self, $webEnv, $queryKey) = @_;
118              
119             my $url = $self->base . EFETCH_AFFIX
120             . '?db=' . $self->db
121             . '&query_key=' . $queryKey
122             . '&WebEnv=' . $webEnv
123             . '&retmode=xml';
124              
125             my $res = $self->_request($url);
126              
127             return $res->{content};
128             }
129              
130             # Internal: gets the set of results.
131             #
132             # Returns a array representation of the resultset.
133             sub _getRecordSet {
134             my ($self) = @_;
135              
136             # fetch the eSearch xml response and extract webEnv & queryKey.
137             my $eSearchResult = $self->_eSearch();
138              
139             my $webEnv;
140             if ( $eSearchResult =~ /(\S+)<\/WebEnv>/) { $webEnv = $1; }
141             die "Couldn't extract webEnv." unless $webEnv;
142              
143             my $queryKey;
144             if ($eSearchResult =~ /(\d+)<\/QueryKey>/) { $queryKey = $1; }
145             die "Couldn't extract queryKey." unless $queryKey;
146              
147             # fetch the eFetch xml response and hashify it.
148             my $eFetchResult = $self->_eFetch($webEnv, $queryKey);
149             my $hash = $self->_hashify($eFetchResult);
150             $hash = $hash->{'PubmedArticle'};
151              
152             # return a reference to a array.
153             return \@{$hash};
154             }
155              
156             sub _nextRecord {
157             my ($self) = @_;
158              
159             # fetch recordset if we don't have one yet.
160             $self->{_currentRecordSet} = $self->_getRecordSet unless $self->_currentRecordSet;
161              
162             # return the next record.
163             return $self->{_currentRecordSet}->[$self->{_n}++];
164             }
165              
166              
167             # Public Methods. --------------------------------------------------------------
168              
169             sub generator {
170             my ($self) = @_;
171              
172             return sub {
173             $self->_nextRecord;
174             };
175             }
176              
177              
178             # PerlDoc. ---------------------------------------------------------------------
179              
180             =head1 NAME
181              
182             Catmandu::Importer::PubMed - Package that imports PubMed data.
183              
184             =head1 SYNOPSIS
185              
186             use Catmandu::Importer::PubMed;
187              
188             my %attrs = (
189             term => 'github'
190             );
191              
192             my $importer = Catmandu::Importer::PubMed->new(%attrs);
193              
194             my $n = $importer->each(sub {
195             my $hashref = $_[0];
196             # ...
197             });
198              
199             =cut
200              
201             =head1 SEE ALSO
202              
203             L
204              
205             =cut
206              
207             1;