C0 code coverage information
Generated on Tue Oct 16 11:40:48 -0400 2007 with rcov 0.8.0
Code reported as executed by Ruby looks like this...
and this: this line is also marked as covered.
Lines considered as run by rcov, but not reported by Ruby, look like this,
and this: these lines were inferred by rcov (using simple heuristics).
Finally, here's a line marked as not executed.
1 # Copyright (C) 2005-2006 Laurent Sansonetti
2 # Copyright (C) 2007 Laurent Sansonetti and Marco Costantini
3 #
4 # Alexandria is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 2 of the
7 # License, or (at your option) any later version.
8 #
9 # Alexandria is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public
15 # License along with Alexandria; see the file COPYING. If not,
16 # write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 # Boston, MA 02111-1307, USA.
18
19 $Z3950_DEBUG = $DEBUG
20
21 require 'zoom'
22 require 'marc'
23
24 module Alexandria
25 class BookProviders
26 class Z3950Provider < AbstractProvider
27 include GetText
28 GetText.bindtextdomain(Alexandria::TEXTDOMAIN, nil, nil, "UTF-8")
29
30 def initialize(name="Z3950", fullname="Z39.50")
31 super
32 prefs.add("hostname", _("Hostname"), "")
33 prefs.add("port", _("Port"), 7090)
34 prefs.add("database", _("Database"), "")
35 prefs.add("record_syntax", _("Record syntax"), "USMARC", ["USMARC", "UNIMARC", "SUTRS"])
36 prefs.add("username", _("Username"), "", nil, false)
37 prefs.add("password", _("Password"), "", nil, false)
38 prefs.add("charset", _("Charset encoding"), "ISO-8859-1")
39 end
40
41 def search(criterion, type)
42 prefs.read
43 criterion = criterion.convert(prefs['charset'], "UTF-8")
44
45 # We only decode MARC at the moment.
46 # SUTRS needs to be decoded separately, because each Z39.50 server has a
47 # different one.
48 unless marc?
49 raise NoResultsError
50 end
51
52 isbn = type == SEARCH_BY_ISBN ? criterion : nil
53 criterion = Library.canonicalise_isbn(criterion) if type == SEARCH_BY_ISBN
54 conn_count = type == SEARCH_BY_ISBN ? 1 : 10 # results to retrieve
55 resultset = search_records(criterion, type, conn_count)
56 puts "total #{resultset.length}" if $Z3950_DEBUG
57 raise NoResultsError if resultset.length == 0
58 results = books_from_marc(resultset, isbn)
59 type == SEARCH_BY_ISBN ? results.first : results
60 end
61
62 def url(book)
63 nil
64 end
65
66 #######
67 private
68 #######
69
70
71 def books_from_marc(resultset, isbn)
72
73 results = []
74 resultset[0..9].each do |record|
75 marc_txt = record.render(prefs['record_syntax'], 'USMARC')
76 puts marc_txt if $Z3950_DEBUG
77 marc_txt = marc_txt.convert("UTF-8", prefs['charset'])
78 marc = MARC::Record.new(marc_txt)
79
80 if $Z3950_DEBUG
81 puts "Parsing MARC"
82 puts "title: #{marc.title}"
83 puts "authors: #{marc.authors.join(', ')}"
84 puts "isbn: #{marc.isbn}, #{isbn}"
85 puts "publisher: #{marc.publisher}"
86 puts "publish year: #{marc.publish_year}" if marc.respond_to?(:publish_year)
87 puts "edition: #{marc.edition}"
88 end
89
90 next if marc.title.nil? # or marc.authors.empty?
91
92 isbn = isbn or marc.isbn
93 isbn = Library.canonicalise_ean(isbn)
94
95 book = Book.new(marc.title, marc.authors,
96 isbn,
97 (marc.publisher or ""),
98 marc.respond_to?(:publish_year) \
99 ? marc.publish_year.to_i : nil,
100 (marc.edition or ""))
101 results << [book]
102 end
103 return results
104 end
105
106 def marc?
107 /MARC$/.match(prefs['record_syntax'])
108 end
109
110 def search_records(criterion, type, conn_count)
111 options = {}
112 unless prefs['username'].empty? or prefs['password'].empty?
113 options['user'] = prefs['username']
114 options['password'] = prefs['password']
115 end
116 hostname, port = prefs['hostname'], prefs['port'].to_i
117 puts "hostname #{hostname} port #{port} options #{options}" if $Z3950_DEBUG
118 conn = ZOOM::Connection.new(options).connect(hostname, port)
119 conn.database_name = prefs['database']
120 conn.preferred_record_syntax = prefs['record_syntax']
121 conn.element_set_name = 'F'
122 conn.count = conn_count
123 attr = case type
124 when SEARCH_BY_ISBN then [7]
125 when SEARCH_BY_TITLE then [4]
126 when SEARCH_BY_AUTHORS then [1, 1003]
127 when SEARCH_BY_KEYWORD then [1016]
128 end
129 pqf = ""
130 attr.each { |attr| pqf += "@attr 1=#{attr} "}
131 pqf += "\"" + criterion.upcase + "\""
132 puts "pqf is #{pqf}, syntax #{prefs['record_syntax']}" if $Z3950_DEBUG
133 conn.search(pqf)
134 end
135 end
136
137
138 class LOCProvider < Z3950Provider
139 # http://en.wikipedia.org/wiki/Library_of_Congress
140 unabstract
141
142 include GetText
143 GetText.bindtextdomain(Alexandria::TEXTDOMAIN, nil, nil, "UTF-8")
144
145 def initialize
146 super("LOC", _("Library of Congress (Usa)"))
147 prefs.variable_named("hostname").default_value = "z3950.loc.gov"
148 prefs.variable_named("port").default_value = 7090
149 prefs.variable_named("database").default_value = "Voyager"
150 prefs.variable_named("record_syntax").default_value = "USMARC"
151 prefs.variable_named("charset").default_value = "ISO_6937"
152 end
153
154 def url(book)
155 "http://catalog.loc.gov/cgi-bin/Pwebrecon.cgi?DB=local&CNT=25+records+per+page&CMD=isbn+" + Library.canonicalise_isbn(book.isbn)
156 end
157 end
158
159
160 class BLProvider < Z3950Provider
161 # http://en.wikipedia.org/wiki/Copac
162 # http://en.wikipedia.org/wiki/British_Library
163 # http://www.bl.uk/catalogues/z3950fullaccess.html
164 # http://www.bl.uk/catalogues/z3950copacaccess.html
165 # FIXME: switch from BL to Copac, which incudes the BL itself and many more libraries: http://copac.ac.uk/libraries/
166 # Details: http://copac.ac.uk/interfaces/z39.50/
167 # The SUTRS format used by Copac is different from the one used by BL
168 unabstract
169
170 include GetText
171 GetText.bindtextdomain(Alexandria::TEXTDOMAIN, nil, nil, "UTF-8")
172
173 def initialize
174 super("BL", _("British Library"))
175 prefs.variable_named("hostname").default_value = "z3950cat.bl.uk"
176 prefs.variable_named("port").default_value = 9909
177 prefs.variable_named("database").default_value = "BLAC"
178 prefs.variable_named("record_syntax").default_value = "SUTRS"
179 prefs.variable_named("charset").default_value = "ISO-8859-1"
180 end
181
182 def search(criterion, type)
183 return super unless prefs['record_syntax'] == 'SUTRS'
184
185 prefs.read
186 criterion = Library.canonicalise_isbn(criterion) if type == SEARCH_BY_ISBN
187 conn_count = type == SEARCH_BY_ISBN ? 1 : 10 # results to retrieve
188 resultset = search_records(criterion, type, conn_count)
189 puts "total #{resultset.length}" if $Z3950_DEBUG
190 raise NoResultsError if resultset.length == 0
191 results = books_from_sutrs(resultset)
192 type == SEARCH_BY_ISBN ? results.first : results
193 end
194
195 def url(book)
196 "http://copac.ac.uk/openurl?isbn=" + Library.canonicalise_isbn(book.isbn)
197 end
198
199 #######
200 private
201 #######
202
203 def books_from_sutrs(resultset)
204 results = []
205 resultset[0..9].each do |record|
206 text = record.render
207 puts text if $Z3950_DEBUG
208 text = text.convert("UTF-8", prefs['charset'])
209
210 title = isbn = publisher = publish_year = edition = nil
211 authors = []
212
213 text.split(/\n/).each do |line|
214 if md = /^Title:\s+(.*)$/.match(line)
215 title = md[1].sub(/\.$/, '').squeeze(' ')
216 elsif md = /^Added Person Name:\s+(.*),[^,]+$/.match(line)
217 authors << md[1]
218 elsif md = /^ME-Personal Name:\s+(.*),[^,]+$/.match(line)
219 authors << md[1]
220 elsif md = /^ISBN:\s+([\dXx]+)/.match(line)
221 isbn = Library.canonicalise_ean( md[1] )
222 elsif md = /^Imprint:.+\:\s*(.+)\,/.match(line)
223 publisher = md[1]
224 end
225 end
226
227 if $Z3950_DEBUG
228 puts "Parsing SUTRS"
229 puts "title: #{title}"
230 puts "authors: #{authors.join(' and ')}"
231 puts "isbn: #{isbn}"
232 puts "publisher: #{publisher}"
233 puts "edition: #{edition}"
234 end
235
236 if title # and !authors.empty?
237 book = Book.new(title, authors, isbn, (publisher or nil), (publish_year or nil), (edition or nil))
238 results << [book]
239 end
240
241 end
242 return results
243
244 end
245 end
246
247
248 class SBNProvider < Z3950Provider
249 # http://sbnonline.sbn.it/
250 # http://it.wikipedia.org/wiki/ICCU
251 unabstract
252
253 include GetText
254 GetText.bindtextdomain(Alexandria::TEXTDOMAIN, nil, nil, "UTF-8")
255
256 def initialize
257 super("SBN", "Servizio Bibliotecario Nazionale (Italy)")
258 prefs.variable_named("hostname").default_value = "opac.sbn.it"
259 prefs.variable_named("port").default_value = 3950
260 prefs.variable_named("database").default_value = "nopac"
261 # supported 'USMARC', 'UNIMARC' , 'SUTRS'
262 prefs.variable_named("record_syntax").default_value = "USMARC"
263 prefs.variable_named("charset").default_value = "ISO-8859-1"
264 end
265
266 def search(criterion, type)
267 prefs.read
268
269 isbn = type == SEARCH_BY_ISBN ? criterion : nil
270 criterion = canonicalise_isbn_with_dashes(criterion)
271 resultset = search_records(criterion, type, 0)
272 puts "total #{resultset.length}" if $Z3950_DEBUG
273 raise NoResultsError if resultset.length == 0
274 results = books_from_marc(resultset, isbn)
275 type == SEARCH_BY_ISBN ? results.first : results
276 end
277
278 def url(book)
279 "http://sbnonline.sbn.it/cgi-bin/zgw/BRIEF.pl?displayquery=%253CB%253E%253Cfont%2520color%253D%2523000064%253E" +
280 "Codice%2520ISBN%253C%2FB%253E%253C%2Ffont%253E%2520contiene%2520%2522%2520%253CFONT%2520COLOR%253Dred%253E" +
281 canonicalise_isbn_with_dashes(book.isbn) +
282 "%253C%2FFONT%253E%2522&session=&zurl=opac&zquery=%281%3D7+4%3D2+2%3D3+5%3D100+6%3D1+3%3D3+%22" +
283 canonicalise_isbn_with_dashes(book.isbn) +
284 "%22%29&language=it&maxentries=10&target=0&position=1"
285 end
286
287 #######
288 private
289 #######
290
291 def canonicalise_isbn_with_dashes(isbn)
292 # The reference for the position of the dashes is
293 # http://www.isbn-international.org/converter/ranges.htm
294
295 isbn = Alexandria::Library.canonicalise_isbn(isbn)
296
297 if isbn[0..1] == "88"
298 # Italian speaking area
299 if isbn > "8895000" and isbn <="8899999996"
300 return isbn[0..1] + "-" + isbn[2..6] + "-" + isbn[7..8] + "-" + isbn[9..9]
301 elsif isbn > "88900000"
302 return isbn[0..1] + "-" + isbn[2..7] + "-" + isbn[8..8] + "-" + isbn[9..9]
303 elsif isbn > "8885000"
304 return isbn[0..1] + "-" + isbn[2..6] + "-" + isbn[7..8] + "-" + isbn[9..9]
305 elsif isbn > "886000"
306 return isbn[0..1] + "-" + isbn[2..5] + "-" + isbn[6..8] + "-" + isbn[9..9]
307 elsif isbn > "88200"
308 return isbn[0..1] + "-" + isbn[2..4] + "-" + isbn[5..8] + "-" + isbn[9..9]
309 elsif isbn > "8800"
310 return isbn[0..1] + "-" + isbn[2..3] + "-" + isbn[4..8] + "-" + isbn[9..9]
311 else
312 raise "Invalid ISBN"
313 end
314
315 else
316 return isbn
317 end
318 end
319 =begin
320
321 Remarks about SBN
322
323 This provider requires that value of conn.count is 0. It's a Yaz option "Number of records to be retrieved".
324 This provider requires to specify the value of conn.element_set_name = 'F'. It's a Yaz option "Element-Set name of records".
325 See http://www.indexdata.dk/yaz/doc/zoom.resultsets.tkl
326
327 Dashes:
328 this database requires that Italian books are searched with dashes :(
329 However, they have also books with dashes in wrong positions, for instance 88-061-4934-2
330
331 References:
332 http://opac.internetculturale.it/cgi-bin/main.cgi?type=field
333 http://www.internetculturale.it/
334 http://sbnonline.sbn.it/zgw/homeit.html
335 http://www.iccu.sbn.it/genera.jsp?id=124
336 with link at http://www.iccu.sbn.it/upload/documenti/cartecsbn.pdf
337 http://www.loc.gov/cgi-bin/zgstart?ACTION=INIT&FORM_HOST_PORT=/prod/www/data/z3950/iccu.html,opac.sbn.it,2100
338 http://gwz.cilea.it/cgi-bin/reportOpac.cgi
339
340 =end
341 end
342
343 end
344 end
Generated using the rcov code coverage analysis tool for Ruby version 0.8.0.