File Coverage

blib/lib/Astro/NED/Response/Objects.pm
Criterion Covered Total %
statement 70 85 82.3
branch 8 14 57.1
condition 8 12 66.6
subroutine 12 13 92.3
pod 5 5 100.0
total 103 129 79.8


line stmt bran cond sub pod time code
1             # --8<--8<--8<--8<--
2             #
3             # Copyright (C) 2007 Smithsonian Astrophysical Observatory
4             #
5             # This file is part of Astro::NED::Query
6             #
7             # Astro::NED::Query is free software: you can redistribute it and/or modify
8             # it under the terms of the GNU General Public License as published by
9             # the Free Software Foundation, either version 3 of the License, or (at
10             # your option) any later version.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             # GNU General Public License for more details.
16             #
17             # You should have received a copy of the GNU General Public License
18             # along with this program. If not, see .
19             #
20             # -->8-->8-->8-->8--
21              
22             package Astro::NED::Response::Objects;
23              
24 6     6   22388 use 5.006;
  6         20  
  6         317  
25 6     6   32 use strict;
  6         14  
  6         191  
26 6     6   35 use warnings;
  6         13  
  6         201  
27 6     6   36 use Carp;
  6         16  
  6         619  
28              
29             our $VERSION = '0.30';
30              
31 6     6   4273 use Astro::NED::Response::Fields;
  6         16  
  6         243  
32 6     6   5000 use Astro::NED::Response::Object;
  6         21  
  6         68  
33              
34              
35             #---------------------------------------------------------------------------
36              
37             sub new
38             {
39 4     4 1 47 my $class = shift;
40 4   33     43 $class = ref $class || $class;
41              
42 4         24 my $self = {
43             curr_object => -1,
44             objects => [],
45             };
46 4         14 bless $self, $class;
47              
48 4         16 return $self;
49             }
50              
51             #---------------------------------------------------------------------------
52              
53             sub objects {
54 3     3 1 20 my ( $self ) = @_;
55              
56 3         6 return @{$self->{objects}};
  3         31  
57             }
58              
59             sub nobjects {
60 3     3 1 1844 my ( $self ) = @_;
61              
62 3         8 return scalar @{$self->{objects}};
  3         29  
63             }
64              
65             sub addobject
66             {
67 0     0 1 0 my ( $self, @objects ) = @_;
68              
69 0         0 croak( __PACKAGE__, '->addobject: object is not of type Astro::NED::Response::Object' )
70 0 0       0 if grep { ! $_->isa( 'Astro::NED::Response::Object' ) } @objects;
71              
72 0         0 push @{$self->{objects}}, @objects;
  0         0  
73              
74 0         0 return $self->nobjects;
75             }
76              
77              
78             #---------------------------------------------------------------------------
79              
80              
81             sub parseHTML
82             {
83 4     4 1 5819 require HTML::LinkExtor;
84 4         14677 require HTML::TableParser;
85              
86 4         824518 my $self = shift;
87              
88             # don't do this, as we don't want to copy the passed data.
89             # my $html = shift;
90              
91             # first get list of links
92 4         43 my $p = HTML::LinkExtor->new;
93 4         637 $p->parse( $_[0]);
94              
95             ## no critic (AccessOfPrivateData)
96             # HTML::LinkExtor returns a list of arrayrefs, not objects.
97 4         9061 my @links = grep { /search_type=Obj_id/i } map { $_->[2] } $p->links ;
  112         275  
  112         222  
98             ## use critic
99              
100 4         57 my @cols;
101             my @colnames;
102              
103             # HTML::Parser does its own funky handling of exceptions, which causes
104             # exceptions in handlers to be printed and then rethrown. work around
105             # that by keeping track of our exceptions excplicily and by using
106             # $p->eof;
107 0         0 my $error;
108              
109             $p = HTML::TableParser->new(
110             [{
111             cols => qr/Object Type/,
112             DecodeNBSP => 1,
113              
114             hdr => sub {
115              
116 4     4   10812 my %used;
117 4         8 for my $colname ( @{$_[2]} )
  4         15  
118             {
119             ## no critic (AccessOfPrivateData)
120             # @Fields is a list of arrayrefs, not objects.
121 79         204 my @matches = Astro::NED::Response::Fields::match( $colname );
122             ## use critic
123              
124             # A table column can't match more than one field, unless
125             # it's the Row No. column, which is in there twice.
126 79 50       173 if ( 1 == @matches )
127             {
128 79         96 my $match = $matches[0];
129             ## no critic (AccessOfPrivateData)
130 79         144 my $name = $match->{name};
131             ## use critic
132              
133 79 50 66     222 if ( exists $used{$name} && $name ne 'No' )
134             {
135 0         0 $error = "internal error; matched $match->{name} to more than one column in NED table: " .
136             "$used{$name}, $colname \n";
137 0         0 $p->eof;
138             }
139              
140 79         189 $used{$name} = $colname;
141 79         306 push @colnames, $name;
142             }
143             else
144             {
145 0 0       0 if ( 0 == @matches )
146             {
147 0         0 $error = "internal error: could not recognize column '$colname' in NED table\n";
148 0         0 $p->eof;
149             }
150             else
151             {
152             ## no critic (AccessOfPrivateData)
153 0         0 $error = "internal error: multiple matches for column '$colname' in NED table: " .
154 0         0 join (", ", map { $_->{name} } @matches ) . "\n";
155 0         0 $p->eof;
156             ## use critic
157             }
158              
159             }
160              
161             }
162             },
163              
164             row => sub {
165 11     11   13328 my %data;
166 11 100 100     14 @data{@colnames} = map { $_ eq '' || $_ eq '...' ? undef : $_ } @{$_[2]};
  219         971  
  11         26  
167 11         51 $data{InfoLink} = shift @links;
168 11         30 $data{Name} =~ s/^[*]//;
169              
170 11         109 my $object = Astro::NED::Response::Object->new( \%data );
171              
172 11         254 eval {
173 11         42 Astro::NED::Response::Fields::check( \%data );
174             };
175              
176 11 100       35 if ( $@ )
177             {
178 1         8 $error = "error parsing NED output: $@" . "for object:\n" . $object->dumpstr("\t");
179 1         15 $@ = '';
180 1         8 $p->eof;
181             }
182              
183 11         19 push @{$self->{objects}}, $object;
  11         102  
184             },
185              
186 4         182 Trim => 1,
187             }]
188             );
189              
190 4         1188 eval { $p->parse( $_[0] ) };
  4         207  
191 4 100 66     633 if ( $@ || $error )
192             {
193 1         6 $error .= $@;
194 1         161 Carp::croak( __PACKAGE__, ': ', $error );
195             }
196              
197 3         21 return;
198             }
199              
200             #---------------------------------------------------------------------------
201              
202              
203             1;
204             __END__