alexandria-book-collection-manager 0.7.5 → 0.7.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +72 -0
  4. data/.gitignore +4 -1
  5. data/.rubocop.yml +65 -30
  6. data/.rubocop_todo.yml +49 -165
  7. data/.simplecov +5 -2
  8. data/CHANGELOG.md +64 -0
  9. data/ChangeLog.0 +19 -19
  10. data/INSTALL.md +26 -16
  11. data/README.md +31 -35
  12. data/Rakefile +18 -16
  13. data/alexandria-book-collection-manager.gemspec +35 -29
  14. data/doc/FAQ +2 -2
  15. data/doc/dependency_decisions.yml +22 -3
  16. data/lib/alexandria/about.rb +1 -1
  17. data/lib/alexandria/book_providers/bl_provider.rb +88 -0
  18. data/lib/alexandria/book_providers/douban.rb +2 -2
  19. data/lib/alexandria/book_providers/loc_provider.rb +38 -0
  20. data/lib/alexandria/book_providers/pseudomarc.rb +61 -71
  21. data/lib/alexandria/book_providers/sbn_provider.rb +108 -0
  22. data/lib/alexandria/book_providers/{thalia.rb → thalia_provider.rb} +37 -74
  23. data/lib/alexandria/book_providers/web.rb +2 -2
  24. data/lib/alexandria/book_providers/worldcat.rb +34 -38
  25. data/lib/alexandria/book_providers/z3950_provider.rb +199 -0
  26. data/lib/alexandria/book_providers.rb +48 -65
  27. data/lib/alexandria/default_preferences.rb +2 -1
  28. data/lib/alexandria/execution_queue.rb +13 -12
  29. data/lib/alexandria/export_library.rb +21 -22
  30. data/lib/alexandria/image_fetcher.rb +25 -0
  31. data/lib/alexandria/import_library.rb +46 -70
  32. data/lib/alexandria/import_library_csv.rb +16 -16
  33. data/lib/alexandria/library_sort_order.rb +3 -1
  34. data/lib/alexandria/library_store.rb +19 -20
  35. data/lib/alexandria/logging.rb +5 -9
  36. data/lib/alexandria/models/book.rb +15 -2
  37. data/lib/alexandria/models/library.rb +31 -35
  38. data/lib/alexandria/net.rb +1 -2
  39. data/lib/alexandria/preferences.rb +27 -33
  40. data/lib/alexandria/scanners/cue_cat.rb +6 -6
  41. data/lib/alexandria/scanners/keyboard.rb +1 -1
  42. data/lib/alexandria/scanners.rb +2 -2
  43. data/lib/alexandria/smart_library.rb +22 -26
  44. data/lib/alexandria/ui/about_dialog.rb +1 -1
  45. data/lib/alexandria/ui/acquire_dialog.rb +15 -19
  46. data/lib/alexandria/ui/alert_dialog.rb +36 -19
  47. data/lib/alexandria/ui/bad_isbns_dialog.rb +13 -9
  48. data/lib/alexandria/ui/barcode_animation.rb +6 -6
  49. data/lib/alexandria/ui/book_properties_dialog.rb +2 -3
  50. data/lib/alexandria/ui/book_properties_dialog_base.rb +35 -137
  51. data/lib/alexandria/ui/calendar_popup.rb +58 -0
  52. data/lib/alexandria/ui/callbacks.rb +144 -123
  53. data/lib/alexandria/ui/completion_models.rb +2 -6
  54. data/lib/alexandria/ui/confirm_erase_dialog.rb +1 -1
  55. data/lib/alexandria/ui/conflict_while_copying_dialog.rb +2 -2
  56. data/lib/alexandria/ui/error_dialog.rb +1 -1
  57. data/lib/alexandria/ui/export_dialog.rb +19 -18
  58. data/lib/alexandria/ui/icons.rb +34 -40
  59. data/lib/alexandria/ui/iconview_tooltips.rb +40 -53
  60. data/lib/alexandria/ui/import_dialog.rb +49 -48
  61. data/lib/alexandria/ui/init.rb +14 -12
  62. data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +2 -2
  63. data/lib/alexandria/ui/libraries_combo.rb +10 -9
  64. data/lib/alexandria/ui/listview.rb +6 -7
  65. data/lib/alexandria/ui/main_app.rb +2 -2
  66. data/lib/alexandria/ui/multi_drag_treeview.rb +5 -7
  67. data/lib/alexandria/ui/new_book_dialog.rb +63 -65
  68. data/lib/alexandria/ui/new_book_dialog_manual.rb +1 -1
  69. data/lib/alexandria/ui/new_provider_dialog.rb +12 -11
  70. data/lib/alexandria/ui/new_smart_library_dialog.rb +39 -27
  71. data/lib/alexandria/ui/preferences_dialog.rb +25 -84
  72. data/lib/alexandria/ui/provider_preferences_base_dialog.rb +10 -6
  73. data/lib/alexandria/ui/provider_preferences_dialog.rb +5 -5
  74. data/lib/alexandria/ui/really_delete_dialog.rb +2 -2
  75. data/lib/alexandria/ui/sidepane_manager.rb +38 -38
  76. data/lib/alexandria/ui/skip_entry_dialog.rb +3 -2
  77. data/lib/alexandria/ui/smart_library_properties_dialog.rb +35 -36
  78. data/lib/alexandria/ui/smart_library_properties_dialog_base.rb +61 -244
  79. data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
  80. data/lib/alexandria/ui/sound.rb +4 -6
  81. data/lib/alexandria/ui/ui_manager.rb +80 -83
  82. data/lib/alexandria/ui.rb +7 -7
  83. data/lib/alexandria/version.rb +2 -2
  84. data/lib/alexandria/web_themes.rb +15 -15
  85. data/lib/alexandria.rb +2 -2
  86. data/po/cs.po +947 -865
  87. data/po/cy.po +913 -864
  88. data/po/de.po +961 -865
  89. data/po/el.po +956 -861
  90. data/po/es.po +952 -857
  91. data/po/fr.po +950 -865
  92. data/po/ga.po +866 -819
  93. data/po/gl.po +946 -861
  94. data/po/it.po +945 -858
  95. data/po/ja.po +921 -836
  96. data/po/mk.po +953 -858
  97. data/po/nb.po +932 -847
  98. data/po/nl.po +955 -849
  99. data/po/pl.po +999 -963
  100. data/po/pt.po +946 -850
  101. data/po/pt_BR.po +944 -859
  102. data/po/ru.po +959 -868
  103. data/po/sk.po +950 -863
  104. data/po/sv.po +944 -859
  105. data/po/uk.po +925 -846
  106. data/po/zh_TW.po +926 -841
  107. data/schemas/alexandria.schemas +1 -1
  108. data/share/alexandria/glade/main_app__builder.glade +6 -21
  109. data/share/gnome/help/alexandria/C/adding-books.xml +3 -4
  110. data/share/gnome/help/alexandria/C/introduction.xml +0 -16
  111. data/share/gnome/help/alexandria/C/searching.xml +1 -4
  112. data/share/gnome/help/alexandria/C/settings.xml +0 -30
  113. data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
  114. data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
  115. data/share/gnome/help/alexandria/fr/alexandria.xml +5 -160
  116. data/share/gnome/help/alexandria/ja/adding-books.xml +1 -1
  117. data/share/gnome/help/alexandria/ja/introduction.xml +0 -15
  118. data/share/gnome/help/alexandria/ja/searching.xml +3 -7
  119. data/share/gnome/help/alexandria/ja/settings.xml +0 -27
  120. data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
  121. data/spec/alexandria/book_providers/bl_provider_spec.rb +13 -0
  122. data/spec/alexandria/book_providers/loc_provider_spec.rb +17 -0
  123. data/spec/alexandria/book_providers/sbn_provider_spec.rb +13 -0
  124. data/spec/alexandria/book_providers/thalia_provider_spec.rb +119 -0
  125. data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
  126. data/spec/alexandria/book_providers_spec.rb +0 -154
  127. data/spec/alexandria/console_spec.rb +0 -5
  128. data/spec/alexandria/export_library_spec.rb +27 -38
  129. data/spec/alexandria/library_spec.rb +76 -46
  130. data/spec/alexandria/preferences_spec.rb +29 -3
  131. data/spec/alexandria/scanners/cue_cat_spec.rb +1 -1
  132. data/spec/alexandria/ui/about_dialog_spec.rb +1 -1
  133. data/spec/alexandria/ui/acquire_dialog_spec.rb +1 -1
  134. data/spec/alexandria/ui/alert_dialog_spec.rb +1 -1
  135. data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +1 -1
  136. data/spec/alexandria/ui/book_properties_dialog_spec.rb +47 -5
  137. data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +1 -1
  138. data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +1 -1
  139. data/spec/alexandria/ui/error_dialog_spec.rb +1 -1
  140. data/spec/alexandria/ui/export_dialog_spec.rb +25 -4
  141. data/spec/alexandria/ui/icons_spec.rb +26 -0
  142. data/spec/alexandria/ui/iconview_spec.rb +1 -1
  143. data/spec/alexandria/ui/import_dialog_spec.rb +35 -3
  144. data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +1 -1
  145. data/spec/alexandria/ui/main_app_spec.rb +1 -1
  146. data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +39 -3
  147. data/spec/alexandria/ui/new_provider_dialog_spec.rb +19 -3
  148. data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +28 -3
  149. data/spec/alexandria/ui/preferences_dialog_spec.rb +2 -2
  150. data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +23 -8
  151. data/spec/alexandria/ui/really_delete_dialog_spec.rb +1 -1
  152. data/spec/alexandria/ui/sidepane_manager_spec.rb +2 -2
  153. data/spec/alexandria/ui/skip_entry_dialog_spec.rb +1 -1
  154. data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +37 -6
  155. data/spec/alexandria/ui/ui_manager_spec.rb +116 -2
  156. data/spec/data/libraries/0.6.2/My Library/9780571147168.yaml +2 -0
  157. data/spec/end_to_end/basic_run_spec.rb +3 -8
  158. data/spec/fixtures/cover.jpg +0 -0
  159. data/spec/spec_helper.rb +47 -3
  160. data/tasks/spec.rake +3 -5
  161. data/util/rake/fileinstall.rb +16 -15
  162. data/util/rake/omfgenerate.rb +1 -1
  163. metadata +141 -52
  164. data/.travis.yml +0 -39
  165. data/lib/alexandria/book_providers/adlibris.rb +0 -196
  166. data/lib/alexandria/book_providers/amazon_aws.rb +0 -252
  167. data/lib/alexandria/book_providers/amazon_ecs_util.rb +0 -388
  168. data/lib/alexandria/book_providers/barnes_and_noble.rb +0 -209
  169. data/lib/alexandria/book_providers/proxis.rb +0 -175
  170. data/lib/alexandria/book_providers/siciliano.rb +0 -257
  171. data/lib/alexandria/book_providers/z3950.rb +0 -415
  172. data/spec/alexandria/ui/ui_utilities_spec.rb +0 -62
  173. data/spec/alexandria/utilities_spec.rb +0 -52
@@ -11,6 +11,7 @@ module Alexandria
11
11
  class ImportFilter
12
12
  attr_reader :name, :patterns, :message
13
13
 
14
+ include Logging
14
15
  include GetText
15
16
  extend GetText
16
17
  bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
@@ -34,7 +35,7 @@ module Alexandria
34
35
  end
35
36
 
36
37
  def invoke(library_name, filename)
37
- puts "Selected: #{@message} -- #{library_name} -- #{filename}"
38
+ log.debug { "Selected: #{@message} -- #{library_name} -- #{filename}" }
38
39
  Library.send(@message, library_name, filename,
39
40
  @on_iterate_cb, @on_error_cb)
40
41
  end
@@ -50,30 +51,24 @@ module Alexandria
50
51
 
51
52
  class Library
52
53
  def self.import_autodetect(*args)
53
- puts args.inspect
54
+ log.debug { args.inspect }
54
55
  filename = args[1]
55
- puts "Filename is #{filename} and ext is #{filename[-4..-1]}"
56
- puts "Beginning import: #{args[0]}, #{args[1]}"
57
- if filename[-4..-1] == ".txt"
56
+ log.debug { "Filename is #{filename} and ext is #{filename[-4..]}" }
57
+ log.debug { "Beginning import: #{args[0]}, #{args[1]}" }
58
+ if filename[-4..] == ".txt"
58
59
  import_as_isbn_list(*args)
59
- elsif [".tc", ".bc"].include? filename[-3..-1]
60
- begin
61
- import_as_tellico_xml_archive(*args)
62
- rescue StandardError => ex
63
- puts ex.message
64
- puts ex.backtrace.join("\n>> ")
65
- end
66
- elsif [".csv"].include? filename[-4..-1]
60
+ elsif [".tc", ".bc"].include? filename[-3..]
61
+ import_as_tellico_xml_archive(*args)
62
+ elsif [".csv"].include? filename[-4..]
67
63
  import_as_csv_file(*args)
68
64
  else
69
- puts "Bailing on this import!"
70
- raise "Not supported type"
65
+ raise _("Unsupported type")
71
66
  end
72
67
  end
73
68
 
74
69
  def self.import_as_tellico_xml_archive(name, filename,
75
70
  on_iterate_cb, _on_error_cb)
76
- puts "Starting import_as_tellico_xml_archive... "
71
+ log.debug { "Starting import_as_tellico_xml_archive... " }
77
72
  return nil unless system("unzip -qqt \"#{filename}\"")
78
73
 
79
74
  tmpdir = File.join(Dir.tmpdir, "tellico_export")
@@ -102,34 +97,21 @@ module Alexandria
102
97
  keys = ["isbn", "publisher", "pub_year", "binding"]
103
98
 
104
99
  book_elements = [neaten(elements["title"].text)]
105
- book_elements += if !elements["authors"].nil?
100
+ book_elements += if elements["authors"].nil?
101
+ [[]]
102
+ else
106
103
  [elements["authors"].elements.to_a.map \
107
104
  { |x| neaten(x.text) }]
108
- else
109
- [[]]
110
105
  end
111
106
  book_elements += keys.map do |key|
112
107
  neaten(elements[key].text) if elements[key]
113
108
  end
114
- # isbn
115
- if book_elements[2].nil? || book_elements[2].strip.empty?
116
- book_elements[2] = nil
117
- else
118
- begin
119
- book_elements[2] = book_elements[2].strip
120
- book_elements[2] = Library.canonicalise_ean(book_elements[2])
121
- rescue StandardError => ex
122
- puts book_elements[2]
123
- puts ex.message
124
- puts ex.backtrace.join("\n> ")
125
- raise ex
126
- end
127
- end
109
+ book_elements[2] = Library.canonicalise_ean(book_elements[2])
128
110
  # publishing_year
129
111
  book_elements[4] = book_elements[4].to_i unless book_elements[4].nil?
130
- puts book_elements.inspect
112
+ log.debug { book_elements.inspect }
131
113
  cover = (neaten(elements["cover"].text) if elements["cover"])
132
- puts cover
114
+ log.debug { cover }
133
115
  book = Book.new(*book_elements)
134
116
  if elements["rating"]
135
117
  rating = elements["rating"].text.to_i
@@ -140,19 +122,16 @@ module Alexandria
140
122
  on_iterate_cb&.call(n + 1, total)
141
123
  end
142
124
 
143
- library = Library.load(name)
125
+ # TODO: Pass in library store as an argument
126
+ library = LibraryCollection.instance.library_store.load_library name
144
127
  content.each do |book, cover|
145
- unless cover.nil?
146
- library.save_cover(book,
147
- File.join(Dir.pwd, "images",
148
- cover))
149
- end
128
+ library.save_cover(book, File.join(Dir.pwd, "images", cover)) unless cover.nil?
150
129
  library << book
151
130
  library.save(book)
152
131
  end
153
132
  return [library, []]
154
133
  rescue StandardError => ex
155
- puts ex.message
134
+ log.info { ex.message }
156
135
  return nil
157
136
  end
158
137
  end
@@ -160,7 +139,7 @@ module Alexandria
160
139
  def self.import_as_csv_file(name, filename, on_iterate_cb, _on_error_cb)
161
140
  require "alexandria/import_library_csv"
162
141
  books_and_covers = []
163
- line_count = IO.readlines(filename).reduce(0) { |count, _line| count + 1 }
142
+ line_count = File.readlines(filename).reduce(0) { |count, _line| count + 1 }
164
143
 
165
144
  import_count = 0
166
145
  max_import = line_count - 1
@@ -177,7 +156,7 @@ module Alexandria
177
156
  if book.isbn
178
157
  # if we can search by ISBN, try to grab the cover
179
158
  begin
180
- dl_book, dl_cover = Alexandria::BookProviders.isbn_search(book.isbn)
159
+ dl_book, dl_cover = BookProviders.isbn_search(book.isbn)
181
160
  if dl_book.authors.size > book.authors.size
182
161
  # LibraryThing only supports a single author, so
183
162
  # attempt to include more author information if it's
@@ -187,8 +166,7 @@ module Alexandria
187
166
  book.edition = dl_book.edition unless book.edition
188
167
  cover = dl_cover
189
168
  rescue StandardError
190
- puts "failed to get cover for #{book.title} #{book.isbn}" if $DEBUG
191
- # note failure
169
+ log.debug { "Failed to get cover for #{book.title} #{book.isbn}" }
192
170
  end
193
171
  end
194
172
 
@@ -203,7 +181,7 @@ module Alexandria
203
181
  # probably Goodreads' wonky ISBN fields ,,="043432432X",
204
182
  # this is a hack to fix up such files
205
183
  data = File.read(filename)
206
- data.gsub!(/\,\=\"/, ',"')
184
+ data.gsub!(/,="/, ',"')
207
185
  csv_fixed = Tempfile.new("alexandria_import_csv_fixed_")
208
186
  csv_fixed.write(data)
209
187
  csv_fixed.close
@@ -216,12 +194,13 @@ module Alexandria
216
194
  end
217
195
  end
218
196
 
219
- library = Library.load(name)
197
+ # TODO: Pass in library store as an argument
198
+ library = LibraryCollection.instance.library_store.load_library name
220
199
 
221
200
  books_and_covers.each do |book, cover_uri|
222
- puts "Saving #{book.isbn} cover..." if $DEBUG
201
+ log.debug { "Saving #{book.isbn} cover" }
223
202
  library.save_cover(book, cover_uri) unless cover_uri.nil?
224
- puts "Saving #{book.isbn}..." if $DEBUG
203
+ log.debug { "Saving #{book.isbn}" }
225
204
  library << book
226
205
  library.save(book)
227
206
  end
@@ -230,18 +209,12 @@ module Alexandria
230
209
 
231
210
  def self.import_as_isbn_list(name, filename, on_iterate_cb,
232
211
  on_error_cb)
233
- puts "Starting import_as_isbn_list... "
234
- isbn_list = IO.readlines(filename).map do |line|
235
- puts "Trying line #{line}" if $DEBUG
236
- # Let's preserve the failing isbns so we can report them later.
237
- begin
238
- [line.chomp, canonicalise_isbn(line.chomp)] unless line == "\n"
239
- rescue StandardError => ex
240
- puts ex.message
241
- [line.chomp, nil]
242
- end
212
+ log.debug { "Starting import_as_isbn_list... " }
213
+ isbn_list = File.readlines(filename).map do |line|
214
+ log.debug { "Trying line #{line}" }
215
+ [line.chomp, canonicalise_isbn(line.chomp)] unless line == "\n"
243
216
  end
244
- puts "Isbn list: #{isbn_list.inspect}"
217
+ log.debug { "Isbn list: #{isbn_list.inspect}" }
245
218
  isbn_list.compact!
246
219
  return nil if isbn_list.empty?
247
220
 
@@ -253,27 +226,30 @@ module Alexandria
253
226
  isbn_list.each do |isbn|
254
227
  begin
255
228
  if isbn[1]
256
- books << Alexandria::BookProviders.isbn_search(isbn[1])
229
+ books << BookProviders.isbn_search(isbn[1])
257
230
  else
258
231
  bad_isbns << isbn[0]
259
232
  end
260
- rescue StandardError => ex
261
- puts ex.message
233
+ rescue BookProviders::SearchEmptyError => ex
234
+ log.debug { ex.message }
262
235
  failed_lookup_isbns << isbn[1]
263
- puts "NOTE : ignoring on_error_cb #{on_error_cb}"
236
+ log.debug { "NOTE : ignoring on_error_cb #{on_error_cb}" }
264
237
  # return nil unless
265
238
  # (on_error_cb and on_error_cb.call(e.message))
266
239
  end
267
240
 
268
241
  on_iterate_cb&.call(current_iteration += 1, max_iterations)
269
242
  end
270
- puts "Bad Isbn list: #{bad_isbns.inspect}" if bad_isbns
271
- library = load(name)
272
- puts "Going with these #{books.length} books: #{books.inspect}" if $DEBUG
243
+ log.debug { "Bad Isbn list: #{bad_isbns.inspect}" } if bad_isbns
244
+
245
+ # TODO: Pass in library store as an argument
246
+ library = LibraryCollection.instance.library_store.load_library name
247
+
248
+ log.debug { "Going with these #{books.length} books: #{books.inspect}" }
273
249
  books.each do |book, cover_uri|
274
- puts "Saving #{book.isbn} cover..." if $DEBUG
250
+ log.debug { "Saving #{book.isbn} cover..." }
275
251
  library.save_cover(book, cover_uri) unless cover_uri.nil?
276
- puts "Saving #{book.isbn}..." if $DEBUG
252
+ log.debug { "Saving #{book.isbn}..." }
277
253
  library << book
278
254
  library.save(book)
279
255
  on_iterate_cb&.call(current_iteration += 1, max_iterations)
@@ -72,8 +72,7 @@ module Alexandria
72
72
  additional.split(",").each do |add|
73
73
  authors << normalize(add)
74
74
  end
75
- isbn = row[@isbn] # TODO: canonicalize_ean...
76
- isbn = Library.canonicalise_ean(isbn) if isbn
75
+ isbn = Library.canonicalise_ean(row[@isbn])
77
76
  publisher = normalize(row[@publisher])
78
77
  year = row[@publishing_year].to_i
79
78
  edition = normalize(row[@edition])
@@ -95,12 +94,13 @@ module Alexandria
95
94
  book.redd = true
96
95
  end
97
96
  if row[@mainshelf]
98
- if row[@mainshelf] == "read"
97
+ case row[@mainshelf]
98
+ when "read"
99
99
  book.redd = true
100
- elsif row[@mainshelf] == "to-read"
100
+ when "to-read"
101
101
  book.redd = false
102
102
  book.tags = ["to read"]
103
- elsif row[@mainshelf] == "currently-reading"
103
+ when "currently-reading"
104
104
  book.redd = false
105
105
  book.tags = ["currently reading"]
106
106
  end
@@ -112,7 +112,7 @@ module Alexandria
112
112
  book.tags << tag unless book.tags.include? tag
113
113
  end
114
114
  end
115
- puts "Goodreads loading #{book.title}" if $DEBUG
115
+ log.debug { "Goodreads loading #{book.title}" }
116
116
  book
117
117
  end
118
118
  end
@@ -146,7 +146,7 @@ module Alexandria
146
146
  # sometimes "Publisher (YEAR), Edition: NUM, Binding, NUM pages"
147
147
  publisher_info = normalize(row[@publisher_info])
148
148
  publisher = publisher_info
149
- publisher = Regexp.last_match[1] if publisher_info =~ /([^\(]+)\(/
149
+ publisher = Regexp.last_match[1] if publisher_info =~ /([^(]+)\(/
150
150
  edition = publisher_info # binding
151
151
  edition_info = publisher_info.split(",")
152
152
  edition = publisher_info.split(",")[-2] if edition_info.size >= 3
@@ -169,7 +169,7 @@ module Alexandria
169
169
  end
170
170
  end
171
171
 
172
- puts "LibraryThing loading #{book.title}" if $DEBUG
172
+ log.debug { "LibraryThing loading #{book.title}" }
173
173
  book
174
174
  end
175
175
  end
@@ -183,20 +183,20 @@ module Alexandria
183
183
  is_librarything = false
184
184
  is_goodreads = false
185
185
  header.each do |head|
186
- if head == "'PUBLICATION INFO'"
186
+ case head
187
+ when "'PUBLICATION INFO'"
187
188
  is_librarything = true
188
189
  break
189
- elsif head == "Year Published"
190
+ when "Year Published"
190
191
  is_goodreads = true
191
192
  break
192
193
  end
193
194
  end
194
- if is_librarything
195
- return LibraryThingCSVImport.new(header)
196
- elsif is_goodreads
197
- return GoodreadsCSVImport.new(header)
198
- end
199
- raise "Not Recognized" unless is_librarything || is_goodreads
195
+
196
+ return LibraryThingCSVImport.new(header) if is_librarything
197
+ return GoodreadsCSVImport.new(header) if is_goodreads
198
+
199
+ raise _("Not Recognized") unless is_librarything || is_goodreads
200
200
  end
201
201
  end
202
202
  end
@@ -29,7 +29,9 @@ module Alexandria
29
29
  end
30
30
 
31
31
  class Unsorted < LibrarySortOrder
32
- def initialize; end
32
+ def initialize
33
+ super(nil, nil)
34
+ end
33
35
 
34
36
  def sort(library)
35
37
  library
@@ -9,7 +9,7 @@ module Alexandria
9
9
  include Logging
10
10
 
11
11
  FIX_BIGNUM_REGEX =
12
- %r{loaned_since:\s*(\!ruby/object\:Bignum\s*)?(\d+)\n}.freeze
12
+ %r{loaned_since:\s*(!ruby/object:Bignum\s*)?(\d+)\n}.freeze
13
13
 
14
14
  include GetText
15
15
  bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
@@ -23,7 +23,7 @@ module Alexandria
23
23
  begin
24
24
  Dir.entries(library_dir).each do |file|
25
25
  # Skip hidden files.
26
- next if /^\./.match?(file)
26
+ next if file.start_with?(".")
27
27
  # Skip non-directory files.
28
28
  next unless File.stat(File.join(library_dir, file)).directory?
29
29
 
@@ -64,7 +64,7 @@ module Alexandria
64
64
  old_isbn = book.isbn
65
65
  old_pub_year = book.publishing_year
66
66
  begin
67
- raise "Not a book: #{book.inspect}" unless book.is_a?(Book)
67
+ raise format(_("Not a book: %<book>s"), book.inspect) unless book.is_a?(Book)
68
68
 
69
69
  ean = Library.canonicalise_ean(book.isbn)
70
70
  book.isbn = ean if ean
@@ -74,16 +74,18 @@ module Alexandria
74
74
  end
75
75
 
76
76
  # Or if isbn has changed
77
- raise "#{test[1]} isbn is not okay" unless book.isbn == old_isbn
77
+ unless book.isbn == old_isbn
78
+ raise format(_("%<file>s isbn is not okay"), file: test[1])
79
+ end
78
80
 
79
81
  # Re-save book if Alexandria::DATA_VERSION changes
80
82
  unless book.version == Alexandria::DATA_VERSION
81
- raise "#{test[1]} version is not okay"
83
+ raise format(_("%<file>s version is not okay"), file: test[1])
82
84
  end
83
85
 
84
86
  # Or if publishing year has changed
85
87
  unless book.publishing_year == old_pub_year
86
- raise "#{test[1]} pub year is not okay"
88
+ raise format(_("%<file>s pub year is not okay"), file: test[1])
87
89
  end
88
90
 
89
91
  # ruined_books << [book, book.isbn, library]
@@ -92,13 +94,11 @@ module Alexandria
92
94
  ## TODO copy cover image file, if necessary
93
95
  # due to #26909 cover files for books without ISBN are re-saved as
94
96
  # "g#{ident}.cover"
95
- if book.isbn.nil? || book.isbn.empty?
96
- if File.exist? library.old_cover(book)
97
- log.debug do
98
- "#{library.name}; book #{book.title} has no ISBN, fixing cover image"
99
- end
100
- FileUtils::Verbose.mv(library.old_cover(book), library.cover(book))
97
+ if (book.isbn.nil? || book.isbn.empty?) && File.exist?(library.old_cover(book))
98
+ log.debug do
99
+ "#{library.name}; book #{book.title} has no ISBN, fixing cover image"
101
100
  end
101
+ FileUtils::Verbose.mv(library.old_cover(book), library.cover(book))
102
102
  end
103
103
 
104
104
  library << book
@@ -152,7 +152,7 @@ module Alexandria
152
152
  # Skip non-regular files.
153
153
  next unless File.stat(filename).file?
154
154
 
155
- text = IO.read(filename)
155
+ text = File.read(filename)
156
156
  hash = YAML.safe_load(text, permitted_classes: [Symbol])
157
157
  smart_library = SmartLibrary.from_hash(hash, self)
158
158
  a << smart_library
@@ -181,7 +181,7 @@ module Alexandria
181
181
  private
182
182
 
183
183
  def regularize_book_from_yaml(name)
184
- text = IO.read(name)
184
+ text = File.read(name)
185
185
 
186
186
  # Code to remove the mystery string in books imported from Amazon
187
187
  # (In the past, still?) To allow ruby-amazon to be removed.
@@ -198,14 +198,13 @@ module Alexandria
198
198
  if (md = FIX_BIGNUM_REGEX.match(text))
199
199
  new_yaml = Time.at(md[2].to_i).to_yaml
200
200
  # Remove the "---" prefix.
201
- new_yaml.sub!(/^\s*\-+\s*/, "")
201
+ new_yaml.sub!(/^\s*-+\s*/, "")
202
202
  text.sub!(md[0], "loaned_since: #{new_yaml}\n")
203
203
  end
204
204
 
205
- # TODO: Ensure book loading passes through Book#initialize
206
- book = YAML.safe_load(text, permitted_classes: [Book, Time])
205
+ book = Book.from_yaml(text)
207
206
 
208
- unless book.isbn.class == String
207
+ unless book.isbn.instance_of? String
209
208
  # HACK
210
209
  md = /isbn: (.+)/.match(text)
211
210
  if md
@@ -215,7 +214,7 @@ module Alexandria
215
214
  end
216
215
 
217
216
  # another HACK of the same type as above
218
- unless book.saved_ident.class == String
217
+ unless book.saved_ident.instance_of? String
219
218
 
220
219
  md2 = /saved_ident: (.+)/.match(text)
221
220
  if md2
@@ -224,7 +223,7 @@ module Alexandria
224
223
  book.saved_ident = string_saved_ident
225
224
  end
226
225
  end
227
- if (book.isbn.class == String) && book.isbn.empty?
226
+ if (book.isbn.instance_of? String) && book.isbn.empty?
228
227
  book.isbn = nil # save trouble later
229
228
  end
230
229
  book
@@ -25,13 +25,13 @@ module Alexandria
25
25
  # A Logger subclass which accepts a source for log messages
26
26
  # in order to improve legibility of the logs.
27
27
  # The source should usually be +self+, whether that be a Class, Module
28
- # or Object. A LoggerWrapper can be used to simplify this procedure.
28
+ # or Object. A LogWrapper can be used to simplify this procedure.
29
29
  class Logger < ::Logger
30
30
  def add(severity, message = nil, source = nil, progname = nil, &block)
31
31
  return super(severity, message, progname, &block) if source.nil?
32
32
 
33
33
  category = self.class.category(source)
34
- return super(severity, progname, category) unless block_given?
34
+ return super(severity, progname, category) unless block
35
35
 
36
36
  category = "#{category} #{progname}" if progname
37
37
  super(severity, message, category, &block)
@@ -118,7 +118,7 @@ module Alexandria
118
118
  module Logging
119
119
  module ClassMethods
120
120
  def log
121
- @log_wrapper ||= LogWrapper.new(Alexandria.log, self)
121
+ @log ||= LogWrapper.new(Alexandria.log, self)
122
122
  end
123
123
  end
124
124
 
@@ -127,15 +127,13 @@ module Alexandria
127
127
  end
128
128
 
129
129
  def log
130
- @log_wrapper ||= LogWrapper.new(Alexandria.log, self)
130
+ @log ||= LogWrapper.new(Alexandria.log, self)
131
131
  end
132
132
  end
133
133
 
134
- private
135
-
136
134
  # Creates the Logger for Alexandria
137
135
  def self.create_logger
138
- logger = Alexandria::Logger.new(STDERR)
136
+ logger = Alexandria::Logger.new($stderr)
139
137
 
140
138
  level = ENV["LOGLEVEL"] ? ENV["LOGLEVEL"].intern : nil
141
139
  if [:FATAL, :ERROR, :WARN, :INFO, :DEBUG].include? level
@@ -150,8 +148,6 @@ module Alexandria
150
148
 
151
149
  @@logger = create_logger
152
150
 
153
- public
154
-
155
151
  # Returns the Logger for Alexandria
156
152
  def self.log
157
153
  @@logger
@@ -64,12 +64,25 @@ module Alexandria
64
64
  own || false
65
65
  end
66
66
 
67
- def ==(obj)
68
- obj.is_a?(self.class) && (ident == obj.ident)
67
+ def ==(other)
68
+ other.is_a?(self.class) && (ident == other.ident)
69
69
  end
70
70
 
71
71
  def inspect
72
72
  "#<Alexandria::Book title: #{@title}>"
73
73
  end
74
+
75
+ def self.from_yaml(text)
76
+ node = YAML.parse_stream text
77
+ doc = node.children.first
78
+ mapping = doc.children.first
79
+ mapping.children.each_slice(2) do |_k, v|
80
+ v.tag = nil if v.tag == "!ruby/array:Alexandria:Library"
81
+ end
82
+ yaml = node.to_yaml
83
+
84
+ # TODO: Ensure book loading passes through Book#initialize
85
+ YAML.safe_load(yaml, permitted_classes: [Book, Time])
86
+ end
74
87
  end
75
88
  end