| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Astro::Bibcode; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | =head1 NAME | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | Astro::Bibcode - Parse standardised astronomical journal bibcode | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | use Astro::Bibcode; | 
| 10 |  |  |  |  |  |  | $bib = new Astro::Bibcode( '2002MNRAS.336...14J' ); | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | print $bib->journal(),"\n"; | 
| 13 |  |  |  |  |  |  | print $bib->volume(),"\n"; | 
| 14 |  |  |  |  |  |  | print $bib->year(),"\n"; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | This module parses a standardised astronomical journal bibcode (see | 
| 19 |  |  |  |  |  |  | references at end of this documentation) and allows the individual | 
| 20 |  |  |  |  |  |  | parts to be extracted. | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | =cut | 
| 23 |  |  |  |  |  |  |  | 
| 24 | 1 |  |  | 1 |  | 2976 | use 5.006; | 
|  | 1 |  |  |  |  | 6 |  | 
|  | 1 |  |  |  |  | 55 |  | 
| 25 | 1 |  |  | 1 |  | 6 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 44 |  | 
| 26 | 1 |  |  | 1 |  | 14 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 32 |  | 
| 27 | 1 |  |  | 1 |  | 5 | use warnings::register; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 124 |  | 
| 28 | 1 |  |  | 1 |  | 5 | use Carp; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 75 |  | 
| 29 |  |  |  |  |  |  |  | 
| 30 | 1 |  |  | 1 |  | 4 | use vars qw/ $VERSION /; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 2295 |  | 
| 31 |  |  |  |  |  |  | $VERSION = sprintf("%d.%03d", q$Revision: 0.3 $ =~ /(\d+)\.(\d+)/); | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | # Some lookup tables | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | # Standard Classification codes | 
| 36 |  |  |  |  |  |  | my %CLASS = ( | 
| 37 |  |  |  |  |  |  | B => 'textbook', | 
| 38 |  |  |  |  |  |  | C => 'catalog', | 
| 39 |  |  |  |  |  |  | M => 'digited version', | 
| 40 |  |  |  |  |  |  | P => 'preprint', | 
| 41 |  |  |  |  |  |  | R => 'report or conference proceedings', | 
| 42 |  |  |  |  |  |  | T => 'thesis', | 
| 43 |  |  |  |  |  |  | U => 'unpublished', | 
| 44 |  |  |  |  |  |  | ); | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | # Note that ADS seems to use the following classifications: | 
| 47 |  |  |  |  |  |  | #  conf   Conference | 
| 48 |  |  |  |  |  |  | #  book   Book | 
| 49 |  |  |  |  |  |  | #  work   Workshop | 
| 50 |  |  |  |  |  |  | #  symp   Symposium | 
| 51 |  |  |  |  |  |  | #  rept   Reports | 
| 52 |  |  |  |  |  |  | #  meet   Meeting | 
| 53 |  |  |  |  |  |  | my %CLASS_ADS = ( | 
| 54 |  |  |  |  |  |  | proc => 'conference proceeding', # Alias for "conf" | 
| 55 |  |  |  |  |  |  | book => 'book', | 
| 56 |  |  |  |  |  |  | work => 'workshop', | 
| 57 |  |  |  |  |  |  | conf => 'conference proceeding', | 
| 58 |  |  |  |  |  |  | symp => 'symposium', | 
| 59 |  |  |  |  |  |  | rept => 'report', | 
| 60 |  |  |  |  |  |  | meet => 'meeting', | 
| 61 |  |  |  |  |  |  | ); | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | # These are populated dynamically as required | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | # Normal standardised Journal lookup | 
| 66 |  |  |  |  |  |  | my %JOURNALS; | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | # ADS conference proceedings lookup | 
| 69 |  |  |  |  |  |  | my %CONF_ADS; | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | =head1 METHODS | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | =head2 Constructor | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | =over 4 | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | =item B | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | Create a new C object. This constructor | 
| 81 |  |  |  |  |  |  | can be called in a number of ways. | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | If a single argument is provided it is assumed to be a bibcode. | 
| 84 |  |  |  |  |  |  | This code will be parsed, if the parse fails the object will not | 
| 85 |  |  |  |  |  |  | be created. | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | $bib = new Astro::Bibcode( '1995MNRAS.276.1024J' ); | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | THE REST OF THIS SECTION IS PROPOSED INTERFACE AND IS NOT IMPLEMENTED | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | If it is called without arguments an empty object will be | 
| 92 |  |  |  |  |  |  | created. Further calls to the C method or the individual | 
| 93 |  |  |  |  |  |  | components will be required to configure the object. | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | $bib = new Astro::Bibcode; | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | If a series of hash arguments are provided, the object will | 
| 99 |  |  |  |  |  |  | be configured by calling the individual accessors in turn. | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | $bib = new Astro::Bibcode( journalcode => 'ApJ', | 
| 102 |  |  |  |  |  |  | year => 2002, | 
| 103 |  |  |  |  |  |  | ); | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | NOTE THAT BIBCODE CREATION IS NOT YET IMPLEMENTED | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | =cut | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | sub new { | 
| 110 | 1 |  |  | 1 | 1 | 337 | my $proto = shift; | 
| 111 | 1 |  | 33 |  |  | 9 | my $class = ref($proto) || $proto; | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | # Create object | 
| 114 | 1 |  |  |  |  | 6 | my $bib = bless { | 
| 115 |  |  |  |  |  |  | BIBCODE => undef, | 
| 116 |  |  |  |  |  |  | YEAR => undef, | 
| 117 |  |  |  |  |  |  | JOURNALCODE => undef, | 
| 118 |  |  |  |  |  |  | CLASSFLAG => undef, | 
| 119 |  |  |  |  |  |  | VOLUME => undef, | 
| 120 |  |  |  |  |  |  | MISC => undef, | 
| 121 |  |  |  |  |  |  | PAGE => undef, | 
| 122 |  |  |  |  |  |  | INITIAL => undef, | 
| 123 |  |  |  |  |  |  | CONFCODE => undef, | 
| 124 |  |  |  |  |  |  | }, $class; | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 1 | 50 |  |  |  | 5 | if (@_) { | 
| 127 |  |  |  |  |  |  | # if we have one code it's a bibcode | 
| 128 | 0 | 0 |  |  |  | 0 | if (scalar(@_) == 1) { | 
| 129 | 0 |  |  |  |  | 0 | my $retval = $bib->bibcode( $_[0] ); | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | # if bibcode method returned undef (error in parse) | 
| 132 |  |  |  |  |  |  | # set the object to undef to indicate error | 
| 133 | 0 | 0 |  |  |  | 0 | $bib = undef unless defined $retval; | 
| 134 |  |  |  |  |  |  | } else { | 
| 135 | 0 |  |  |  |  | 0 | my %args = @_; | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | # loop over known important methods | 
| 138 | 0 |  |  |  |  | 0 | for my $k (qw| year journalcode classflag volume page initial misc |) { | 
| 139 | 0 | 0 |  |  |  | 0 | $bib->$k($args{$k}) if exists $args{$k}; | 
| 140 |  |  |  |  |  |  | } | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | } | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 1 |  |  |  |  | 3 | return $bib; | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | =back | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | =head2 Accessor Methods | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | =over 4 | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | =item B | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | Returns the bibcode associated with this object. It will be generated | 
| 158 |  |  |  |  |  |  | from the other object attributes if undefined (which it will be after | 
| 159 |  |  |  |  |  |  | something in the object has changed). | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | $bib->bibcode( '1998adass...7..216J' ); | 
| 162 |  |  |  |  |  |  | $code = $bib->bibcode; | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | Can return undef if the bibcode did not pass verification (see | 
| 165 |  |  |  |  |  |  | C). | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | =cut | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | sub bibcode { | 
| 170 | 35 |  |  | 35 | 1 | 389 | my $self = shift; | 
| 171 | 35 | 100 |  |  |  | 64 | if (@_) { | 
| 172 | 5 |  |  |  |  | 8 | my $code = shift; | 
| 173 |  |  |  |  |  |  | # Verify and store | 
| 174 | 5 |  |  |  |  | 12 | my %parts = $self->verify_bibcode( $code ); | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | # if we did not get any result; store undef and return | 
| 177 | 5 | 50 |  |  |  | 549 | if (!keys %parts) { | 
| 178 | 0 |  |  |  |  | 0 | $self->{BIBCODE} = undef; | 
| 179 | 0 |  |  |  |  | 0 | return; | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | # We did get some data. Configure the rest of the object | 
| 183 |  |  |  |  |  |  | # to match. Note that we do not go through the accessors | 
| 184 |  |  |  |  |  |  | # since they may well be configured to clear the bibcode | 
| 185 |  |  |  |  |  |  | # if they are modified and we would end up with recursion | 
| 186 | 5 |  |  |  |  | 12 | $self->{YEAR} = $parts{year}; | 
| 187 | 5 |  |  |  |  | 7 | $self->{VOLUME} = $parts{volume}; | 
| 188 | 5 |  |  |  |  | 9 | $self->{JOURNALCODE} = $parts{journalcode}; | 
| 189 | 5 |  |  |  |  | 6 | $self->{CLASSFLAG} = $parts{classflag}; | 
| 190 | 5 |  |  |  |  | 6 | $self->{MISC} = $parts{misc}; | 
| 191 | 5 |  |  |  |  | 6 | $self->{PAGE} = $parts{page}; | 
| 192 | 5 |  |  |  |  | 8 | $self->{INITIAL} = $parts{initial}; | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 5 |  |  |  |  | 10 | $self->{BIBCODE} = $self->verify_bibcode( $code ); | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 5 |  |  |  |  | 17 | return $self->{BIBCODE}; | 
| 197 |  |  |  |  |  |  | } else { | 
| 198 |  |  |  |  |  |  | # if no bibcode is defined, attempt to generate one from the object | 
| 199 | 30 | 50 |  |  |  | 58 | if (! defined $self->{BIBCODE} ) { | 
| 200 | 0 |  |  |  |  | 0 | $self->_construct_bibcode(); | 
| 201 |  |  |  |  |  |  | } | 
| 202 |  |  |  |  |  |  | } | 
| 203 | 30 |  |  |  |  | 51 | return $self->{BIBCODE}; | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | =item B | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | Year of publication. | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | $year = $bib->year; | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | =cut | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | sub year { | 
| 215 | 15 |  |  | 15 | 1 | 1520 | my $self = shift; | 
| 216 | 15 |  |  |  |  | 40 | return $self->{YEAR}; | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  |  | 
| 219 |  |  |  |  |  |  | =item B | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | The Journal code associated with this bib code. | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | For the current list of journal codes see: | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | http://simbad.u-strasbg.fr/simjnl.pl | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | See the C method in order to translate this code to a full | 
| 228 |  |  |  |  |  |  | journal name. | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | $jcode = $bib->journalcode; | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | =cut | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | sub journalcode { | 
| 235 | 25 |  |  | 25 | 1 | 1341 | my $self = shift; | 
| 236 | 25 |  |  |  |  | 62 | return $self->{JOURNALCODE}; | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | =item B | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | Classification flag of this bib code. | 
| 243 |  |  |  |  |  |  | Current allowed values are: | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | B textbook | 
| 246 |  |  |  |  |  |  | C catalog | 
| 247 |  |  |  |  |  |  | M digited version | 
| 248 |  |  |  |  |  |  | P preprint | 
| 249 |  |  |  |  |  |  | R report or conference proceedings | 
| 250 |  |  |  |  |  |  | T thesis | 
| 251 |  |  |  |  |  |  | U unpublished | 
| 252 |  |  |  |  |  |  |  | 
| 253 |  |  |  |  |  |  | and also from ADS: | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | book => 'book' | 
| 256 |  |  |  |  |  |  | work => 'workshop' | 
| 257 |  |  |  |  |  |  | conf => 'conference proceeding' | 
| 258 |  |  |  |  |  |  | symp => 'symposium' | 
| 259 |  |  |  |  |  |  | rept => 'report' | 
| 260 |  |  |  |  |  |  | meet => 'meeting' | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | Note that a null string is used to indicate a periodical. | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | $code = $bib->classflag; | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | See the C method for the translation. | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | =cut | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | sub classflag { | 
| 271 | 15 |  |  | 15 | 1 | 17 | my $self = shift; | 
| 272 | 15 |  |  |  |  | 36 | return $self->{CLASSFLAG}; | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | =item B | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | Volume number. | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | =cut | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | sub volume { | 
| 282 | 9 |  |  | 9 | 1 | 580 | my $self = shift; | 
| 283 | 9 |  |  |  |  | 22 | return $self->{VOLUME}; | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | =item B | 
| 287 |  |  |  |  |  |  |  | 
| 288 |  |  |  |  |  |  | Value of the miscellaneous field "M" used to remove ambiguity. | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | =cut | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  | sub misc { | 
| 293 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 294 | 0 |  |  |  |  | 0 | return $self->{MISC}; | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | =item B | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | Page number. | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | =cut | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | sub page { | 
| 304 | 11 |  |  | 11 | 1 | 746 | my $self = shift; | 
| 305 | 11 |  |  |  |  | 27 | return $self->{PAGE}; | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | =item B | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | Either the first initial of the first author's last name, | 
| 311 |  |  |  |  |  |  | or ":" for no author. Also can be "%" to indicate that some | 
| 312 |  |  |  |  |  |  | of the other fields may be invalid. | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | =cut | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub initial { | 
| 317 | 8 |  |  | 8 | 1 | 1145 | my $self = shift; | 
| 318 | 8 |  |  |  |  | 25 | return $self->{INITIAL}; | 
| 319 |  |  |  |  |  |  | } | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | =back | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | =head2 General Methods | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | =over 4 | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | =item B | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | Retrieve the full journal name. | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | $journal = $bib->journal; | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | Returns the code if the code can not be translated. | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | Does try to recognize ADS conference codes. | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | =cut | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | sub journal { | 
| 340 | 15 |  |  | 15 | 1 | 601 | my $self = shift; | 
| 341 | 15 |  |  |  |  | 22 | my $jcode = $self->journalcode; # Journal lookup | 
| 342 | 15 |  |  |  |  | 24 | my $confcode = $self->confcode; # Conference lookup | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | # first time through, populate the journal lookup | 
| 345 | 15 | 50 |  |  |  | 27 | $self->_populate_journals() unless keys %JOURNALS; | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | # Is it in the journal list? | 
| 348 | 15 | 100 |  |  |  | 31 | if (exists $JOURNALS{$jcode}) { | 
|  |  | 50 |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | # Straight journal lookup | 
| 350 | 10 |  |  |  |  | 21 | return $JOURNALS{$jcode}; | 
| 351 |  |  |  |  |  |  | } elsif (defined $confcode) { | 
| 352 |  |  |  |  |  |  | # It is a conference | 
| 353 | 5 |  |  |  |  | 15 | return $CONF_ADS{$confcode}; | 
| 354 |  |  |  |  |  |  | } else { | 
| 355 |  |  |  |  |  |  | # do not know | 
| 356 | 0 |  |  |  |  | 0 | return $jcode; | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  | } | 
| 359 |  |  |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | =item B | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | Retrieve the full name associated with the classification flag. | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | $class = $bib->class; | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | Returns undef if no name can be translated. | 
| 367 |  |  |  |  |  |  |  | 
| 368 |  |  |  |  |  |  | =cut | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | sub class { | 
| 371 | 15 |  |  | 15 | 1 | 1322 | my $self = shift; | 
| 372 | 15 |  |  |  |  | 31 | my $flag = $self->classflag; | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | # in some cases a "periodical" style bibcode can actually be associated | 
| 375 |  |  |  |  |  |  | # with a conference. Check this by looking to see if confcode is true | 
| 376 | 15 |  |  |  |  | 26 | my $confcode = $self->confcode; | 
| 377 |  |  |  |  |  |  |  | 
| 378 |  |  |  |  |  |  | # if confcode is defined but flag is not, we are really a recurring "conf" | 
| 379 | 15 | 100 | 100 |  |  | 60 | return "recurring conference" if defined $confcode && !$flag; | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | # Sometimes a blank classflag simply means that ADS is lying... | 
| 382 |  |  |  |  |  |  | # rather than it being a "periodical" | 
| 383 | 12 | 100 |  |  |  | 24 | if (!length($flag)) { | 
| 384 | 6 |  |  |  |  | 15 | my $journal = $self->journal; | 
| 385 | 6 | 100 |  |  |  | 17 | if ($journal =~ /thesi/i) { | 
| 386 |  |  |  |  |  |  | # it is really a thesis | 
| 387 | 3 |  |  |  |  | 16 | return "thesis"; | 
| 388 |  |  |  |  |  |  | } else { | 
| 389 |  |  |  |  |  |  | # no hint - use periodical | 
| 390 | 3 |  |  |  |  | 11 | return "periodical"; | 
| 391 |  |  |  |  |  |  | } | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  |  | 
| 394 | 6 | 50 |  |  |  | 21 | if (exists $CLASS{$flag}) { | 
|  |  | 50 |  |  |  |  |  | 
| 395 | 0 |  |  |  |  | 0 | return $CLASS{$flag}; | 
| 396 |  |  |  |  |  |  | } elsif (exists $CLASS_ADS{$flag}) { | 
| 397 | 6 |  |  |  |  | 25 | return $CLASS_ADS{$flag}; | 
| 398 |  |  |  |  |  |  | } | 
| 399 | 0 |  |  |  |  | 0 | return undef; | 
| 400 |  |  |  |  |  |  | } | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | =item B | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | Returns the ADS conference code associated with this bibcode. | 
| 405 |  |  |  |  |  |  | Returns undef if this bibcode is not associated with a conference. | 
| 406 |  |  |  |  |  |  |  | 
| 407 |  |  |  |  |  |  | $confcode = $bib->confcode; | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | In some cases (eg 2000immm.proc...77G), a "proc" classification | 
| 410 |  |  |  |  |  |  | is used when the ADS standard seems to imply "conf" instead. | 
| 411 |  |  |  |  |  |  | This is taken into account when returning the confcode. | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | =cut | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | sub confcode { | 
| 416 | 30 |  |  | 30 | 1 | 28 | my $self = shift; | 
| 417 | 30 |  |  |  |  | 49 | my $bibcode = $self->bibcode(); # For ADS conference proceedings translation | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | # Force read of DATA segment | 
| 420 | 30 | 100 |  |  |  | 63 | $self->_populate_journals unless keys %CONF_ADS; | 
| 421 |  |  |  |  |  |  |  | 
| 422 | 30 |  |  |  |  | 23 | my $confcode; | 
| 423 | 30 | 100 |  |  |  | 113 | if (exists $CONF_ADS{substr($bibcode,0,13)}) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | # Now try an exact ADS match with the first 13 characters | 
| 425 |  |  |  |  |  |  | # This gives us the journal code | 
| 426 | 10 |  |  |  |  | 18 | $confcode = substr($bibcode,0,13); | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | } elsif (exists $CONF_ADS{substr($bibcode,4,9)}) { | 
| 429 |  |  |  |  |  |  | # try ADS conference lookup without the year prefix | 
| 430 | 0 |  |  |  |  | 0 | $confcode = substr($bibcode,4,9); | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | } elsif ($bibcode =~ /proc/) { | 
| 433 |  |  |  |  |  |  | # if we have a .proc see whether .conf matches anywhere | 
| 434 | 4 |  |  |  |  | 5 | my $c = $bibcode; | 
| 435 | 4 |  |  |  |  | 10 | $c =~ s/proc/conf/; | 
| 436 | 4 | 50 |  |  |  | 12 | if (exists $CONF_ADS{substr($c,0,13)}) { | 
| 437 | 4 |  |  |  |  | 8 | $confcode = substr($c,0,13); | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  | } | 
| 440 |  |  |  |  |  |  |  | 
| 441 | 30 |  |  |  |  | 49 | return $confcode; | 
| 442 |  |  |  |  |  |  | } | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | =item B | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | Return a multi-line summary string describing the bibcode status. | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | $text = $bib->summary; | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | =cut | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | sub summary { | 
| 453 | 5 |  |  | 5 | 1 | 1434 | my $self = shift; | 
| 454 | 5 |  |  |  |  | 8 | my $str = ''; | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 5 |  |  |  |  | 14 | my @keys = qw/ class journal year volume page /; | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | # Find the max length of the key | 
| 459 | 5 |  |  |  |  | 4 | my $max = 0; | 
| 460 | 5 |  |  |  |  | 8 | for (@keys) { | 
| 461 | 25 | 100 |  |  |  | 49 | $max = length($_) if length($_) > $max; | 
| 462 |  |  |  |  |  |  | } | 
| 463 |  |  |  |  |  |  |  | 
| 464 | 5 |  |  |  |  | 7 | for my $m (@keys) { | 
| 465 | 25 |  |  |  |  | 45 | my $data = $self->$m(); | 
| 466 | 25 |  |  |  |  | 80 | $str .= sprintf("%-".$max."s : %s\n", ucfirst($m), $data); | 
| 467 |  |  |  |  |  |  | } | 
| 468 | 5 |  |  |  |  | 17 | return $str; | 
| 469 |  |  |  |  |  |  | } | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | =item B | 
| 472 |  |  |  |  |  |  |  | 
| 473 |  |  |  |  |  |  | Given a bibcode, return false if the bibcode does not seem to be | 
| 474 |  |  |  |  |  |  | valid (e.g. it is the wrong lenght, first 4 characters are not digits), | 
| 475 |  |  |  |  |  |  | returns the bibcode in scalar context. | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | $ok = $bib->verify_bibcode( '1999adass...8...11E' ); | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | In list context returns a hash consisting of the constituent (untranslated) | 
| 480 |  |  |  |  |  |  | parts of the bib code. | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | %parts = $bib->verify_bibcode( '1998SPIE.3357..548J' ); | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | Since ADS is prone to replacing & with & in Journal codes due to | 
| 485 |  |  |  |  |  |  | HTML transport, this routine will reverse this. | 
| 486 |  |  |  |  |  |  |  | 
| 487 |  |  |  |  |  |  | Note that in some special cases a bibcode can be specified such | 
| 488 |  |  |  |  |  |  | that it is known not to match all the rules (last character is a '%'). | 
| 489 |  |  |  |  |  |  | In such cases only the length of the bicode is checked. | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  | =cut | 
| 492 |  |  |  |  |  |  |  | 
| 493 |  |  |  |  |  |  | sub verify_bibcode { | 
| 494 | 10 |  |  | 10 | 1 | 10 | my $self = shift; | 
| 495 | 10 |  |  |  |  | 10 | my $bibcode = shift; | 
| 496 | 10 | 50 |  |  |  | 18 | return unless defined $bibcode; | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | # Fix HTML-ification | 
| 499 | 10 |  |  |  |  | 16 | $bibcode =~ s/&/&/; | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | # Check length | 
| 502 | 10 | 50 |  |  |  | 19 | return unless length($bibcode) == 19; | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | # Rather than one enormous pattern match, split the string | 
| 505 |  |  |  |  |  |  | # into fixed length chunks | 
| 506 | 10 |  |  |  |  | 15 | my $yyyy = substr($bibcode,0,4); | 
| 507 | 10 |  |  |  |  | 13 | my $jjjjj= substr($bibcode,4,5); | 
| 508 | 10 |  |  |  |  | 11 | my $vvvv = substr($bibcode,9,4); | 
| 509 | 10 |  |  |  |  | 11 | my $m    = substr($bibcode,13,1); | 
| 510 | 10 |  |  |  |  | 11 | my $pppp = substr($bibcode,14,4); | 
| 511 | 10 |  |  |  |  | 10 | my $a    = substr($bibcode,18,1); | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | # Verify each component and store in hash | 
| 514 | 10 |  |  |  |  | 12 | my %parts; | 
| 515 |  |  |  |  |  |  |  | 
| 516 |  |  |  |  |  |  | # Note that ADS conference proceeding extensions are still valid bibcodes | 
| 517 | 10 |  |  |  |  | 16 | $parts{year} = $self->_verify_year( $yyyy ); | 
| 518 | 10 |  |  |  |  | 22 | $parts{journalcode} = $self->_verify_journalcode( $jjjjj ); | 
| 519 |  |  |  |  |  |  |  | 
| 520 | 10 |  |  |  |  | 19 | my ($class, $vol) = $self->_verify_volume( $vvvv ); | 
| 521 | 10 |  |  |  |  | 17 | $parts{volume} = $vol; | 
| 522 | 10 |  |  |  |  | 15 | $parts{classflag} = $class; | 
| 523 |  |  |  |  |  |  |  | 
| 524 | 10 |  |  |  |  | 18 | $parts{misc} = $self->_verify_misc( $m ); | 
| 525 | 10 |  |  |  |  | 20 | $parts{page} = $self->_verify_page( $pppp ); | 
| 526 | 10 |  |  |  |  | 17 | $parts{initial} = $self->_verify_initial( $a ); | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | # Ordinarily we would return if any of the values in the hash | 
| 530 |  |  |  |  |  |  | # are undef. There is a special case if $a is "%" since this | 
| 531 |  |  |  |  |  |  | # indicates that some of them may not match. In this case | 
| 532 |  |  |  |  |  |  | # we do what we can. | 
| 533 |  |  |  |  |  |  |  | 
| 534 | 10 | 50 |  |  |  | 18 | if ($a ne "%") { | 
| 535 | 10 |  |  |  |  | 19 | for my $v (values %parts) { | 
| 536 | 70 | 50 |  |  |  | 108 | return unless defined $v; | 
| 537 |  |  |  |  |  |  | } | 
| 538 |  |  |  |  |  |  | } | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | # Return the answer | 
| 541 | 10 | 100 |  |  |  | 17 | if (!wantarray) { | 
| 542 | 5 |  |  |  |  | 18 | return $bibcode; | 
| 543 |  |  |  |  |  |  | } else { | 
| 544 | 5 |  |  |  |  | 35 | return %parts; | 
| 545 |  |  |  |  |  |  | } | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | =back | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | =begin PRIVATE__METHODS | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | Internal routines which may change and should not be used in external | 
| 553 |  |  |  |  |  |  | classes. | 
| 554 |  |  |  |  |  |  |  | 
| 555 |  |  |  |  |  |  | These are methods, although there is no expectation that subclasses | 
| 556 |  |  |  |  |  |  | will be required. | 
| 557 |  |  |  |  |  |  |  | 
| 558 |  |  |  |  |  |  | =over 4 | 
| 559 |  |  |  |  |  |  |  | 
| 560 |  |  |  |  |  |  | =item B<_construct_bibcode> | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | =cut | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | sub _construct_bibcode { | 
| 565 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 566 |  |  |  |  |  |  |  | 
| 567 | 0 |  |  |  |  | 0 | Carp::confess "Bibcode construction is not yet implemented. It may be hard."; | 
| 568 |  |  |  |  |  |  |  | 
| 569 |  |  |  |  |  |  | } | 
| 570 |  |  |  |  |  |  |  | 
| 571 |  |  |  |  |  |  | =item B<_verify_year> | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | Check the year looks okay, return false if it does not, the year | 
| 574 |  |  |  |  |  |  | if it looks okay. | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  | =cut | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | sub _verify_year { | 
| 579 | 10 |  |  | 10 |  | 10 | my $self = shift; | 
| 580 | 10 |  |  |  |  | 11 | my $year = shift; | 
| 581 | 10 | 50 |  |  |  | 37 | return (($year =~ /^\d{4}$/) ? $year : () ); | 
| 582 |  |  |  |  |  |  | } | 
| 583 |  |  |  |  |  |  |  | 
| 584 |  |  |  |  |  |  | =item B<_verify_journalcode> | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | Check that the journal code looks okay. Returns the code if okay, | 
| 587 |  |  |  |  |  |  | false otherwise. | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | Does not check to see if the journal code can be translated. | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | Trailing dots are removed from the input string. | 
| 592 |  |  |  |  |  |  |  | 
| 593 |  |  |  |  |  |  | =cut | 
| 594 |  |  |  |  |  |  |  | 
| 595 |  |  |  |  |  |  | sub _verify_journalcode { | 
| 596 | 10 |  |  | 10 |  | 12 | my $self = shift; | 
| 597 | 10 |  |  |  |  | 12 | my $jcode = shift; | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | # Clean the string | 
| 600 | 10 |  |  |  |  | 16 | $jcode = _clean_string($jcode, 'L'); | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | # Just make sure we have A-Z and & | 
| 603 | 10 | 50 |  |  |  | 41 | return ( ( $jcode =~ /^[A-Za-z&]+$/) ? $jcode : () ); | 
| 604 |  |  |  |  |  |  | } | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | =item B<_verify_volume> | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | Check that the volume and class are okay. | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | In scalar context returns the verified string (with leading | 
| 611 |  |  |  |  |  |  | dots removed). | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | ($class, $volume) = $bib->_verify_volume( $v ); | 
| 614 |  |  |  |  |  |  | $v = $bib->_verify_volume($v); | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | In list context returns two values. First is the classification | 
| 617 |  |  |  |  |  |  | flag (blank string for a periodical), second is the volume number | 
| 618 |  |  |  |  |  |  | (leasing zeroes removed). | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  | Note that since ADS does not seem to use the classification | 
| 621 |  |  |  |  |  |  | code as presented in the reference documentation, this is a bit | 
| 622 |  |  |  |  |  |  | of a hack (eg a Thesis would be expected to have class = T but | 
| 623 |  |  |  |  |  |  | instead simply uses PhDT in the journal name and not the university). | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | This means that a blank volume and class are okay and the | 
| 626 |  |  |  |  |  |  | class needs to be hacked in higher up. | 
| 627 |  |  |  |  |  |  |  | 
| 628 |  |  |  |  |  |  | =cut | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | sub _verify_volume { | 
| 631 | 10 |  |  | 10 |  | 11 | my $self = shift; | 
| 632 | 10 |  |  |  |  | 10 | my $vol = shift; | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | # Second character is important so we need to get that before | 
| 635 |  |  |  |  |  |  | # cleaning | 
| 636 | 10 |  |  |  |  | 14 | my $second = substr($vol,1,1); | 
| 637 |  |  |  |  |  |  |  | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  | # Clean the string | 
| 640 | 10 |  |  |  |  | 13 | $vol = _clean_string( $vol, 'R' ); | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | # empty is okay [need to guess later on] | 
| 643 | 10 | 50 |  |  |  | 22 | return (wantarray ? ('', '') : $vol) unless $vol; | 
|  |  | 100 |  |  |  |  |  | 
| 644 |  |  |  |  |  |  |  | 
| 645 |  |  |  |  |  |  | # Get standard classification codes | 
| 646 | 8 |  |  |  |  | 24 | my $classes = join( "", keys %CLASS); | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | # Get adass codes and form a pattern match string | 
| 649 | 8 |  |  |  |  | 24 | my $adsmatch = join("|",keys %CLASS_ADS); | 
| 650 |  |  |  |  |  |  |  | 
| 651 |  |  |  |  |  |  | # Either we are all numbers | 
| 652 | 8 | 100 |  |  |  | 171 | if ($vol =~ /^\d+$/) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 653 |  |  |  |  |  |  | # periodical. Test calling context | 
| 654 | 4 | 50 |  |  |  | 11 | return (wantarray ? ('',$vol) : $vol ); | 
| 655 |  |  |  |  |  |  | } elsif ($vol =~ /([$classes])(\d\d)$/) { | 
| 656 |  |  |  |  |  |  | # We are a classification other than a published journal | 
| 657 |  |  |  |  |  |  | # with multi-volume | 
| 658 | 0 |  |  |  |  | 0 | my $c = $1; | 
| 659 | 0 |  |  |  |  | 0 | my $num = $2; | 
| 660 |  |  |  |  |  |  | # strip leading zero | 
| 661 | 0 |  |  |  |  | 0 | $num =~ s/^0+//g; | 
| 662 |  |  |  |  |  |  |  | 
| 663 |  |  |  |  |  |  | # return the result (checking for context) | 
| 664 | 0 | 0 |  |  |  | 0 | return (wantarray ? ($c, $num) : $vol); | 
| 665 |  |  |  |  |  |  |  | 
| 666 |  |  |  |  |  |  | } elsif ($second =~ /^([$classes])$/) { | 
| 667 | 0 |  |  |  |  | 0 | my $class = $1; | 
| 668 | 0 | 0 |  |  |  | 0 | return (wantarray ? ($class, '') : $vol ); | 
| 669 |  |  |  |  |  |  | } elsif ($vol =~ /^($adsmatch)$/) { | 
| 670 | 4 | 50 |  |  |  | 21 | return (wantarray ? ($1, '') : $vol); | 
| 671 |  |  |  |  |  |  | } | 
| 672 |  |  |  |  |  |  | # bad code | 
| 673 | 0 |  |  |  |  | 0 | return; | 
| 674 |  |  |  |  |  |  | } | 
| 675 |  |  |  |  |  |  |  | 
| 676 |  |  |  |  |  |  | =item B<_verify_misc> | 
| 677 |  |  |  |  |  |  |  | 
| 678 |  |  |  |  |  |  | Verify the misc field which is used to break ambiguity. | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | L     letter section in periodical | 
| 681 |  |  |  |  |  |  | p     pink MNRAS pages | 
| 682 |  |  |  |  |  |  | a-z   issue number in same volume | 
| 683 |  |  |  |  |  |  | A-K   issue designations within same volume | 
| 684 |  |  |  |  |  |  | Q-Z   articles on same page | 
| 685 |  |  |  |  |  |  | A-Z   For theses, first initial of author | 
| 686 |  |  |  |  |  |  | E     "ephemeral". These are temporary bibcodes | 
| 687 |  |  |  |  |  |  | submitted prior to publication [ADS-specific] | 
| 688 |  |  |  |  |  |  |  | 
| 689 |  |  |  |  |  |  | Fundamentally, any letter matches or a ".". | 
| 690 |  |  |  |  |  |  |  | 
| 691 |  |  |  |  |  |  | To be truly accurate the verification requires the | 
| 692 |  |  |  |  |  |  | journal name and classification flag. | 
| 693 |  |  |  |  |  |  |  | 
| 694 |  |  |  |  |  |  | =cut | 
| 695 |  |  |  |  |  |  |  | 
| 696 |  |  |  |  |  |  | sub _verify_misc { | 
| 697 | 10 |  |  | 10 |  | 9 | my $self = shift; | 
| 698 | 10 |  |  |  |  | 8 | my $m = shift; | 
| 699 |  |  |  |  |  |  |  | 
| 700 |  |  |  |  |  |  | # a . is fine | 
| 701 | 10 | 50 |  |  |  | 51 | return "" if $m eq "."; | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | # Now pattern match | 
| 704 | 0 | 0 |  |  |  | 0 | return ( ($m =~ /^[A-Za-z]$/) ? $m : ()); | 
| 705 |  |  |  |  |  |  | } | 
| 706 |  |  |  |  |  |  |  | 
| 707 |  |  |  |  |  |  |  | 
| 708 |  |  |  |  |  |  | =item B<_verify_page> | 
| 709 |  |  |  |  |  |  |  | 
| 710 |  |  |  |  |  |  | Verifies the page number. Returns the page number with leading "." | 
| 711 |  |  |  |  |  |  | removed. Returns false on error. | 
| 712 |  |  |  |  |  |  |  | 
| 713 |  |  |  |  |  |  | =cut | 
| 714 |  |  |  |  |  |  |  | 
| 715 |  |  |  |  |  |  | sub _verify_page { | 
| 716 | 10 |  |  | 10 |  | 9 | my $self = shift; | 
| 717 | 10 |  |  |  |  | 13 | my $page = shift; | 
| 718 | 10 |  |  |  |  | 14 | $page = _clean_string( $page, 'R'); | 
| 719 | 10 | 50 |  |  |  | 39 | return (($page =~ /^\d+$/) ? $page : () ); | 
| 720 |  |  |  |  |  |  | } | 
| 721 |  |  |  |  |  |  |  | 
| 722 |  |  |  |  |  |  | =item B<_verify_initial> | 
| 723 |  |  |  |  |  |  |  | 
| 724 |  |  |  |  |  |  | Check that the initial is valid. In addition to letters, | 
| 725 |  |  |  |  |  |  | ':' indicates that there is no author, '%' indicates that | 
| 726 |  |  |  |  |  |  | the code may be dodgy. | 
| 727 |  |  |  |  |  |  |  | 
| 728 |  |  |  |  |  |  | =cut | 
| 729 |  |  |  |  |  |  |  | 
| 730 |  |  |  |  |  |  | sub _verify_initial { | 
| 731 | 10 |  |  | 10 |  | 10 | my $self = shift; | 
| 732 | 10 |  |  |  |  | 10 | my $i = shift; | 
| 733 | 10 | 50 |  |  |  | 32 | return ( ($i =~ /^[A-Za-z:%]$/) ? $i : () ); | 
| 734 |  |  |  |  |  |  | } | 
| 735 |  |  |  |  |  |  |  | 
| 736 |  |  |  |  |  |  | =item B<_populate_journals> | 
| 737 |  |  |  |  |  |  |  | 
| 738 |  |  |  |  |  |  | Populate the internal journal code to journal name lookup table. | 
| 739 |  |  |  |  |  |  |  | 
| 740 |  |  |  |  |  |  | Also populates the ADS conference proceedings table. | 
| 741 |  |  |  |  |  |  |  | 
| 742 |  |  |  |  |  |  | =cut | 
| 743 |  |  |  |  |  |  |  | 
| 744 |  |  |  |  |  |  | sub _populate_journals { | 
| 745 | 1 |  |  | 1 |  | 2 | my $self = shift; | 
| 746 |  |  |  |  |  |  |  | 
| 747 |  |  |  |  |  |  | # Buffer for concatenating journals that go over a single line | 
| 748 | 1 |  |  |  |  | 1 | my $jbuff = ''; | 
| 749 |  |  |  |  |  |  |  | 
| 750 |  |  |  |  |  |  | # Current journal code in "scope" | 
| 751 | 1 |  |  |  |  | 2 | my $current; | 
| 752 |  |  |  |  |  |  |  | 
| 753 |  |  |  |  |  |  | # Read from data handle | 
| 754 | 1 |  |  |  |  | 6 | while (my $line = ) { | 
| 755 | 1238 | 50 |  |  |  | 2097 | next if $line =~ /^\#/; | 
| 756 |  |  |  |  |  |  |  | 
| 757 |  |  |  |  |  |  | # This means we are at the end of the journals | 
| 758 | 1238 | 100 |  |  |  | 1835 | last if $line =~ /^=cut/; | 
| 759 |  |  |  |  |  |  |  | 
| 760 |  |  |  |  |  |  | # Code is first 7 characters | 
| 761 | 1237 |  |  |  |  | 1326 | my $code = substr($line,0,7); | 
| 762 | 1237 |  |  |  |  | 2780 | $code =~ s/\s+$//; | 
| 763 |  |  |  |  |  |  |  | 
| 764 |  |  |  |  |  |  | # Get the translation. Remove newline. remove trailing and leading space | 
| 765 | 1237 |  |  |  |  | 1668 | my $fullname = substr($line,7); | 
| 766 | 1237 |  |  |  |  | 1324 | chomp($fullname); | 
| 767 | 1237 |  |  |  |  | 2492 | $fullname =~ s/^\s+//; | 
| 768 | 1237 |  |  |  |  | 2626 | $fullname =~ s/\s+$//; | 
| 769 |  |  |  |  |  |  |  | 
| 770 |  |  |  |  |  |  | # Do we have a code? If yes, clear previous buffer | 
| 771 | 1237 | 100 |  |  |  | 2075 | if (length($code)) { | 
| 772 |  |  |  |  |  |  | # Update the new current value | 
| 773 | 918 |  |  |  |  | 925 | my $old = $current; | 
| 774 | 918 |  |  |  |  | 851 | $current = $code; | 
| 775 |  |  |  |  |  |  |  | 
| 776 |  |  |  |  |  |  | # if we have a previous entry, store it and reset the buffers | 
| 777 | 918 | 100 | 66 |  |  | 3776 | $JOURNALS{$old} = $jbuff if ($old && $jbuff); | 
| 778 | 918 |  |  |  |  | 1003 | $jbuff = ''; | 
| 779 |  |  |  |  |  |  |  | 
| 780 |  |  |  |  |  |  | } | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | # Append to buffer, making sure we have a space if concatenating | 
| 783 | 1237 | 100 |  |  |  | 1760 | $jbuff .= " " if $jbuff; | 
| 784 | 1237 |  |  |  |  | 3581 | $jbuff .= $fullname; | 
| 785 |  |  |  |  |  |  |  | 
| 786 |  |  |  |  |  |  | } | 
| 787 |  |  |  |  |  |  |  | 
| 788 |  |  |  |  |  |  | # Leftover | 
| 789 | 1 | 50 | 33 |  |  | 9 | $JOURNALS{$current} = $jbuff if ($current && $jbuff); | 
| 790 |  |  |  |  |  |  |  | 
| 791 |  |  |  |  |  |  | # Now try to populate the ADS lookup (if we have it in DATA | 
| 792 |  |  |  |  |  |  | # ADS bibcode is first 13 characters | 
| 793 | 1 |  |  |  |  | 4 | while (my $line = ) { | 
| 794 | 4226 | 50 |  |  |  | 6940 | next if $line =~ /^\#/; | 
| 795 | 4226 | 100 |  |  |  | 6224 | next if length($line) < 14; | 
| 796 | 4225 |  |  |  |  | 4416 | my $bcode = substr($line,0,13); | 
| 797 | 4225 |  |  |  |  | 5713 | my $conf  = substr($line,14); | 
| 798 | 4225 |  |  |  |  | 3743 | chomp($conf); | 
| 799 | 4225 |  |  |  |  | 9806 | $conf =~ s/^\s+//; | 
| 800 | 4225 |  |  |  |  | 16467 | $CONF_ADS{$bcode} = $conf; | 
| 801 |  |  |  |  |  |  | } | 
| 802 |  |  |  |  |  |  |  | 
| 803 | 1 |  |  |  |  | 6 | return; | 
| 804 |  |  |  |  |  |  | } | 
| 805 |  |  |  |  |  |  |  | 
| 806 |  |  |  |  |  |  | =back | 
| 807 |  |  |  |  |  |  |  | 
| 808 |  |  |  |  |  |  | =end PRIVATE__METHODS | 
| 809 |  |  |  |  |  |  |  | 
| 810 |  |  |  |  |  |  | =cut | 
| 811 |  |  |  |  |  |  |  | 
| 812 |  |  |  |  |  |  | # Really really private helper subs | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | # This subroutine cleans the supplied bibcode substring | 
| 815 |  |  |  |  |  |  | # Remove "spaces" from the string (ie ".") | 
| 816 |  |  |  |  |  |  |  | 
| 817 |  |  |  |  |  |  | # Arg 1: The substring | 
| 818 |  |  |  |  |  |  | # Arg 2: Justification for the string "L" or "R" | 
| 819 |  |  |  |  |  |  |  | 
| 820 |  |  |  |  |  |  | sub _clean_string { | 
| 821 | 30 |  |  | 30 |  | 30 | my $str = shift; | 
| 822 | 30 |  |  |  |  | 31 | my $j = uc(shift); | 
| 823 |  |  |  |  |  |  |  | 
| 824 | 30 | 100 |  |  |  | 61 | if ($j eq 'L') { | 
|  |  | 50 |  |  |  |  |  | 
| 825 | 10 |  |  |  |  | 30 | $str =~ s/\.+$//g; | 
| 826 |  |  |  |  |  |  | } elsif ($j eq 'R') { | 
| 827 | 20 |  |  |  |  | 38 | $str =~ s/^\.+//g; | 
| 828 |  |  |  |  |  |  | } else { | 
| 829 | 0 |  |  |  |  | 0 | croak "Internal error: Justification string was '$j' not L or R"; | 
| 830 |  |  |  |  |  |  | } | 
| 831 | 30 |  |  |  |  | 52 | return $str; | 
| 832 |  |  |  |  |  |  | } | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  |  | 
| 835 |  |  |  |  |  |  |  | 
| 836 |  |  |  |  |  |  | =head1 REFERENCES | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | Details on the bibcode standard can be obtained from | 
| 839 |  |  |  |  |  |  |  | 
| 840 |  |  |  |  |  |  | http://cdsweb.u-strasbg.fr/simbad/refcode.html | 
| 841 |  |  |  |  |  |  |  | 
| 842 |  |  |  |  |  |  | A complete description of the reference coding has been published as a | 
| 843 |  |  |  |  |  |  | chapter of the book "Information & On-Line Data in Astronomy", 1995, | 
| 844 |  |  |  |  |  |  | D. Egret and M. A. Albrecht (Eds), Kluwer Acad. Publ. | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  | ADS seems to use non-standard bibcodes for meetings and conferences: | 
| 847 |  |  |  |  |  |  |  | 
| 848 |  |  |  |  |  |  | http://adsabs.harvard.edu/abs_doc/conferences.html | 
| 849 |  |  |  |  |  |  |  | 
| 850 |  |  |  |  |  |  | ADS Journal codes are here: | 
| 851 |  |  |  |  |  |  |  | 
| 852 |  |  |  |  |  |  | http://adsabs.harvard.edu/abs_doc/all_journals.html | 
| 853 |  |  |  |  |  |  |  | 
| 854 |  |  |  |  |  |  | but are not currently used. | 
| 855 |  |  |  |  |  |  |  | 
| 856 |  |  |  |  |  |  | =head1 NOTES | 
| 857 |  |  |  |  |  |  |  | 
| 858 |  |  |  |  |  |  | Currently the lookup tables for the journal translation and ADS conference | 
| 859 |  |  |  |  |  |  | proceedings are embedded in the module. There is no facility for triggering | 
| 860 |  |  |  |  |  |  | a remote update from the referenced web sites or for easily updating a | 
| 861 |  |  |  |  |  |  | configuration file as new codes are issued. This will probably change in | 
| 862 |  |  |  |  |  |  | future releases. | 
| 863 |  |  |  |  |  |  |  | 
| 864 |  |  |  |  |  |  | =head1 AUTHOR | 
| 865 |  |  |  |  |  |  |  | 
| 866 |  |  |  |  |  |  | Tim Jenness Etjenness@cpan.orgE | 
| 867 |  |  |  |  |  |  |  | 
| 868 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 869 |  |  |  |  |  |  |  | 
| 870 |  |  |  |  |  |  | Copyright (C) 2004 Tim Jenness and the Particle Physics and | 
| 871 |  |  |  |  |  |  | Astronomy Research Council. | 
| 872 |  |  |  |  |  |  |  | 
| 873 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it under | 
| 874 |  |  |  |  |  |  | the terms of the GNU General Public License as published by the Free Software | 
| 875 |  |  |  |  |  |  | Foundation; either version 2 of the License, or (at your option) any later | 
| 876 |  |  |  |  |  |  | version. | 
| 877 |  |  |  |  |  |  |  | 
| 878 |  |  |  |  |  |  | This program is distributed in the hope that it will be useful,but WITHOUT ANY | 
| 879 |  |  |  |  |  |  | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | 
| 880 |  |  |  |  |  |  | PARTICULAR PURPOSE. See the GNU General Public License for more details. | 
| 881 |  |  |  |  |  |  |  | 
| 882 |  |  |  |  |  |  | You should have received a copy of the GNU General Public License along with | 
| 883 |  |  |  |  |  |  | this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
| 884 |  |  |  |  |  |  | Place,Suite 330, Boston, MA  02111-1307, USA | 
| 885 |  |  |  |  |  |  |  | 
| 886 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 887 |  |  |  |  |  |  |  | 
| 888 |  |  |  |  |  |  | L | 
| 889 |  |  |  |  |  |  |  | 
| 890 |  |  |  |  |  |  | =cut | 
| 891 |  |  |  |  |  |  |  | 
| 892 |  |  |  |  |  |  | 1; | 
| 893 |  |  |  |  |  |  |  | 
| 894 |  |  |  |  |  |  | # Note that some entries have been added that were not found on | 
| 895 |  |  |  |  |  |  | # the CDS list but were found in some papers on ADS | 
| 896 |  |  |  |  |  |  | # | 
| 897 |  |  |  |  |  |  | #   OLEB | 
| 898 |  |  |  |  |  |  | # | 
| 899 |  |  |  |  |  |  | __DATA__ |