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.
Name Total lines Lines of code Total coverage Code coverage
lib/alexandria/export_library.rb 412 350
34.7% 
28.0% 
  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.

Valid XHTML 1.0! Valid CSS!