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) 2004-2006 Laurent Sansonetti
2 #
3 # Alexandria is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License as
5 # published by the Free Software Foundation; either version 2 of the
6 # License, or (at your option) any later version.
7 #
8 # Alexandria is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public
14 # License along with Alexandria; see the file COPYING. If not,
15 # write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 # Boston, MA 02111-1307, USA.
17
18 require 'cgi'
19
20 begin # image_size is optional
21 $IMAGE_SIZE_LOADED = true
22 require 'image_size'
23 rescue LoadError
24 $IMAGE_SIZE_LOADED = false
25 puts "Can't load image_size, hence exported libraries are not optimized"
26 end
27
28 module Alexandria
29 class ExportFormat
30 attr_reader :name, :ext, :message
31
32 include GetText
33 extend GetText
34 bindtextdomain(Alexandria::TEXTDOMAIN, nil, nil, "UTF-8")
35
36 def self.all
37 [
38 self.new(_("Archived ONIX XML"), "onix.tbz2",
39 :export_as_onix_xml_archive),
40 self.new(_("Archived Tellico XML"), "tc",
41 :export_as_tellico_xml_archive),
42 self.new(_("BibTeX"), "bib", :export_as_bibtex),
43 self.new(_("CSV list"), "csv", :export_as_csv_list),
44 self.new(_("ISBN List"), "txt", :export_as_isbn_list),
45 self.new(_("HTML Web Page"), nil, :export_as_html, true)
46 ]
47 end
48
49 def invoke(library, filename, *args)
50 library.send(@message, filename, *args)
51 end
52
53 def needs_preview?
54 @needs_preview
55 end
56
57 #######
58 private
59 #######
60
61 def initialize(name, ext, message, needs_preview=false)
62 @name = name
63 @ext = ext
64 @message = message
65 @needs_preview = needs_preview
66 end
67 end
68
69 module Exportable
70 def export_as_onix_xml_archive(filename)
71 File.open(File.join(Dir.tmpdir, "onix.xml"), "w") do |io|
72 to_onix_document.write(io, 0)
73 end
74 copy_covers(File.join(Dir.tmpdir, "images"))
75 Dir.chdir(Dir.tmpdir) do
76 output = `tar -cjf \"#{filename}\" onix.xml images 2>&1`
77 raise output unless $?.success?
78 end
79 FileUtils.rm_rf(File.join(Dir.tmpdir, "images"))
80 FileUtils.rm(File.join(Dir.tmpdir, "onix.xml"))
81 end
82
83 def export_as_tellico_xml_archive(filename)
84 File.open(File.join(Dir.tmpdir, "tellico.xml"), "w") do |io|
85 to_tellico_document.write(io, 0)
86 end
87 copy_covers(File.join(Dir.tmpdir, "images"))
88 Dir.chdir(Dir.tmpdir) do
89 output = `zip -q -r \"#{filename}\" tellico.xml images 2>&1`
90 raise output unless $?.success?
91 end
92 FileUtils.rm_rf(File.join(Dir.tmpdir, "images"))
93 FileUtils.rm(File.join(Dir.tmpdir, "tellico.xml"))
94 end
95
96 def export_as_isbn_list(filename)
97 File.open(filename, 'w') do |io|
98 each do |book|
99 io.puts book.isbn
100 end
101 end
102 end
103
104 def export_as_html(filename, theme)
105 FileUtils.mkdir(filename) unless File.exists?(filename)
106 Dir.chdir(filename) do
107 copy_covers("pixmaps")
108 FileUtils.cp_r(theme.pixmaps_directory,
109 "pixmaps") if theme.has_pixmaps?
110 FileUtils.cp(theme.css_file, ".")
111 File.open("index.html", "w") do |io|
112 io << to_xhtml(File.basename(theme.css_file))
113 end
114 end
115 end
116
117 def export_as_bibtex(filename)
118 File.open(filename, "w") do |io|
119 io << to_bibtex
120 end
121 end
122
123 def export_as_csv_list(filename)
124 File.open(filename, 'w') do |io|
125 each do |book|
126 io.puts book.title + ';' + book.authors.join(', ') + ';' + (book.publisher or "") + ';' + (book.edition or "") + ';' + (book.isbn or "") + ';' + (book.publishing_year.to_s or "")
127 end
128 end
129 end
130
131 #######
132 private
133 #######
134
135 ONIX_DTD_URL = "http://www.editeur.org/onix/2.1/reference/onix-international.dtd"
136 def to_onix_document
137 doc = REXML::Document.new
138 doc << REXML::XMLDecl.new
139 doc << REXML::DocType.new('ONIXMessage',
140 "SYSTEM \"#{ONIX_DTD_URL}\"")
141 msg = doc.add_element('ONIXMessage')
142 header = msg.add_element('Header')
143 header.add_element('FromCompany').text = "Alexandria"
144 header.add_element('FromPerson').text = Etc.getlogin
145 now = Time.now
146 header.add_element('SentDate').text = "%.4d%.2d%.2d%.2d%.2d" % [
147 now.year, now.month, now.day, now.hour, now.min
148 ]
149 header.add_element('MessageNote').text = name
150 each_with_index do |book, idx|
151 # fields that are missing: edition and rating.
152 prod = msg.add_element('Product')
153 prod.add_element('RecordReference').text = idx
154 prod.add_element('NotificationType').text = "03" # confirmed
155 prod.add_element('RecordSourceName').text =
156 "Alexandria " + VERSION
157 prod.add_element('ISBN').text = book.isbn
158 prod.add_element('ProductForm').text = 'BA' # book
159 prod.add_element('DistinctiveTitle').text = book.title
160 unless book.authors.empty?
161 book.authors.each do |author|
162 elem = prod.add_element('Contributor')
163 # author
164 elem.add_element('ContributorRole').text = 'A01'
165 elem.add_element('PersonName').text = author
166 end
167 end
168 if book.notes and not book.notes.empty?
169 elem = prod.add_element('OtherText')
170 # reader description
171 elem.add_element('TextTypeCode').text = '12'
172 elem.add_element('TextFormat').text = '00' # ASCII
173 elem.add_element('Text').text = book.notes
174 end
175 if File.exists?(cover(book))
176 elem = prod.add_element('MediaFile')
177 # front cover image
178 elem.add_element('MediaFileTypeCode').text = '04'
179 elem.add_element('MediaFileFormatCode').text =
180 (Library.jpeg?(cover(book)) ? '03' : '02' )
181 # filename
182 elem.add_element('MediaFileLinkTypeCode').text = '06'
183 elem.add_element('MediaFileLink').text =
184 File.join('images', final_cover(book))
185 end
186 if book.isbn
187 BookProviders.each do |provider|
188 elem = prod.add_element('ProductWebsite')
189 elem.add_element('ProductWebsiteDescription').text =
190 provider.fullname
191 elem.add_element('ProductWebsiteLink').text =
192 provider.url(book)
193 end
194 end
195 elem = prod.add_element('Publisher')
196 elem.add_element('PublishingRole').text = '01'
197 elem.add_element('PublisherName').text = book.publisher
198 prod.add_element('PublicationDate').text = book.publishing_year
199 end
200 return doc
201 end
202
203 def to_tellico_document
204 # For the Tellico format, see
205 # http://periapsis.org/tellico/doc/hacking.html
206 doc = REXML::Document.new
207 doc << REXML::XMLDecl.new
208 doc << REXML::DocType.new('tellico', "PUBLIC \"-//Robby Stephenson/DTD Tellico V7.0//EN\" \"http://periapsis.org/tellico/dtd/v7/tellico.dtd\"")
209 tellico = doc.add_element('tellico')
210 tellico.add_attribute('syntaxVersion', "7")
211 tellico.add_namespace('http://periapsis.org/tellico/')
212 collection = tellico.add_element('collection')
213 collection.add_attribute('title', self.name)
214 collection.add_attribute('type', "2")
215 fields = collection.add_element('fields')
216 field1 = fields.add_element('field')
217 # a field named _default implies adding all default book
218 # collection fields
219 field1.add_attribute('name', "_default")
220 images = collection.add_element('images')
221 each_with_index do |book, idx|
222 entry = collection.add_element('entry')
223 entry.add_attribute('id', idx+1)
224 # translate the binding
225 entry.add_element('title').text = book.title
226 entry.add_element('isbn').text = book.isbn
227 entry.add_element('pub_year').text = book.publishing_year
228 entry.add_element('binding').text = book.edition
229 entry.add_element('publisher').text = book.publisher
230 unless book.authors.empty?
231 authors = entry.add_element('authors')
232 book.authors.each do |author|
233 authors.add_element('author').text = author
234 end
235 end
236 entry.add_element('read').text = book.redd.to_s if book.redd
237 entry.add_element('loaned').text = book.loaned.to_s if book.loaned
238 if not book.rating == Book::DEFAULT_RATING
239 entry.add_element('rating').text = book.rating
240 end
241 if book.notes and not book.notes.empty?
242 entry.add_element('comments').text = book.notes
243 end
244 if File.exists?(cover(book))
245 entry.add_element('cover').text = final_cover(book)
246 image = images.add_element('image')
247 image.add_attribute('id', final_cover(book))
248 if $IMAGE_SIZE_LOADED
249 image_s = ImageSize.new(IO.read(cover(book)))
250 image.add_attribute('height', image_s.get_height)
251 image.add_attribute('width', image_s.get_width)
252 image.add_attribute('format', image_s.get_type)
253 else
254 image.add_attribute('format',
255 Library.jpeg?(cover(book)) \
256 ? "JPEG" : "GIF")
257 end
258 end
259 end
260 return doc
261 end
262
263 def to_xhtml(css)
264 generator = "Alexandria " + Alexandria::VERSION
265 xhtml = ""
266 xhtml << <<EOS
267 <?xml version="1.0" encoding="UTF-8"?>
268 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
269 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
270 <html>
271 <head>
272 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
273 <meta name="Author" content="#{Etc.getlogin}"/>
274 <meta name="Description" content="List of books"/>
275 <meta name="Keywords" content="books"/>
276 <meta name="Generator" content="#{generator}"/>
277 <title>#{name}</title>
278 <link rel="stylesheet" href="#{css}" type="text/css"/>
279 </head>
280 <body>
281 <h1 class="library_name">#{name}</h1>
282 EOS
283
284 each do |book|
285 xhtml << <<EOS
286 <div class="book">
287 <p class="book_isbn">#{book.isbn}</p>
288 EOS
289
290 if File.exists?(cover(book))
291 xhtml << <<EOS
292 <img class="book_cover"
293 src="#{File.join("pixmaps", final_cover(book))}"
294 alt="Cover file for '#{book.title}'"
295 EOS
296 if $IMAGE_SIZE_LOADED
297 image_s = ImageSize.new(IO.read(cover(book)))
298 xhtml << <<EOS
299 height="#{image_s.get_height}" width="#{image_s.get_width}"
300 EOS
301 end
302 xhtml << <<EOS
303 />
304 EOS
305 else
306 xhtml << <<EOS
307 <div class="no_book_cover"></div>
308 EOS
309 end
310
311 unless book.title == nil
312 xhtml << <<EOS
313 <p class="book_title">#{book.title}</p>
314 EOS
315 end
316
317 unless book.authors.empty?
318 xhtml << "<ul class=\"book_authors\">"
319 book.authors.each do |author|
320 xhtml << <<EOS
321 <li class="book_author">#{author}</li>
322 EOS
323 end
324 xhtml << "</ul>"
325 end
326
327 unless book.edition == nil
328 xhtml << <<EOS
329 <p class="book_binding">#{CGI.escapeHTML(book.edition)}</p>
330 EOS
331 end
332
333 unless book.publisher == nil
334 xhtml << <<EOS
335 <p class="book_publisher">#{CGI.escapeHTML(book.publisher)}</p>
336 EOS
337 end
338
339 xhtml << <<EOS
340 </div>
341 EOS
342 end
343 xhtml << <<EOS
344 <p class="copyright">
345 Generated on #{Date.today()} by <a href="#{Alexandria::WEBSITE_URL}">#{generator}</a>.
346 </p>
347 </body>
348 </html>
349 EOS
350 end
351
352 def to_bibtex
353 generator = "Alexandria " + Alexandria::VERSION
354 bibtex = ""
355 bibtex << "\%Generated on #{Date.today()} by: #{generator}\n"
356 bibtex << "\%\n"
357 bibtex << "\n"
358
359 auths = Hash.new(0)
360 each do |book|
361 k = (book.authors[0] or "Anonymous").split[0]
362 if auths.has_key?(k)
363 auths[k] += 1
364 else
365 auths[k] = 1
366 end
367 cite_key = k + auths[k].to_s
368 bibtex << "@BOOK{#{cite_key},\n"
369 bibtex << "author = \""
370 if book.authors != []
371 bibtex << book.authors[0]
372 book.authors[1..-1].each do |author|
373 bibtex << " and #{latex_escape(author)}"
374 end
375 end
376 bibtex << "\",\n"
377 bibtex << "title = \"#{latex_escape(book.title)}\",\n"
378 bibtex << "publisher = \"#{latex_escape(book.publisher)}\",\n"
379 if book.notes and not book.notes.empty?
380 bibtex << "OPTnote = \"#{latex_escape(book.notes)}\",\n"
381 end
382 #year is a required field in bibtex @BOOK
383 bibtex << "year = " + (book.publishing_year or "\"n/a\"").to_s + "\n"
384 bibtex << "}\n\n"
385 end
386 return bibtex
387 end
388
389 def latex_escape(str)
390 return "" if str == nil
391 my_str = str.dup
392 my_str.gsub!(/%/,"\\%")
393 my_str.gsub!(/~/,"\\textasciitilde")
394 my_str.gsub!(/\&/,"\\\\&")
395 my_str.gsub!(/\#/,"\\\\#")
396 my_str.gsub!(/\{/,"\\{")
397 my_str.gsub!(/\}/,"\\}")
398 my_str.gsub!(/_/,"\\_")
399 my_str.gsub!(/\$/,"\\\$")
400 my_str.gsub!(/\"(.+)\"/, %q/``\1''/)
401 return my_str
402 end
403 end
404
405 class Library
406 include Exportable
407 end
408
409 class SmartLibrary
410 include Exportable
411 end
412 end
Generated using the rcov code coverage analysis tool for Ruby version 0.8.0.