alexandria-book-collection-manager 0.7.3 → 0.7.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +77 -0
  4. data/.gitignore +4 -1
  5. data/.rubocop.yml +86 -36
  6. data/.rubocop_todo.yml +58 -161
  7. data/.simplecov +5 -2
  8. data/CHANGELOG.md +56 -2
  9. data/Gemfile +4 -3
  10. data/INSTALL.md +23 -11
  11. data/README.md +52 -41
  12. data/Rakefile +78 -75
  13. data/alexandria-book-collection-manager.gemspec +50 -44
  14. data/bin/alexandria +12 -22
  15. data/doc/FAQ +1 -2
  16. data/doc/dependency_decisions.yml +27 -8
  17. data/lib/alexandria.rb +25 -23
  18. data/lib/alexandria/about.rb +50 -50
  19. data/lib/alexandria/book_providers.rb +86 -91
  20. data/lib/alexandria/book_providers/adlibris.rb +37 -74
  21. data/lib/alexandria/book_providers/amazon_aws.rb +94 -100
  22. data/lib/alexandria/book_providers/amazon_ecs_util.rb +289 -324
  23. data/lib/alexandria/book_providers/barnes_and_noble.rb +42 -42
  24. data/lib/alexandria/book_providers/douban.rb +25 -41
  25. data/lib/alexandria/book_providers/proxis.rb +34 -29
  26. data/lib/alexandria/book_providers/pseudomarc.rb +77 -85
  27. data/lib/alexandria/book_providers/siciliano.rb +60 -64
  28. data/lib/alexandria/book_providers/thalia_provider.rb +161 -0
  29. data/lib/alexandria/book_providers/web.rb +5 -5
  30. data/lib/alexandria/book_providers/worldcat.rb +66 -95
  31. data/lib/alexandria/book_providers/z3950.rb +153 -169
  32. data/lib/alexandria/config.rb +1 -1
  33. data/lib/alexandria/console.rb +3 -3
  34. data/lib/alexandria/default_preferences.rb +37 -0
  35. data/lib/alexandria/execution_queue.rb +13 -12
  36. data/lib/alexandria/export_format.rb +8 -8
  37. data/lib/alexandria/export_library.rb +128 -127
  38. data/lib/alexandria/import_library.rb +102 -126
  39. data/lib/alexandria/import_library_csv.rb +41 -41
  40. data/lib/alexandria/library_collection.rb +6 -5
  41. data/lib/alexandria/library_sort_order.rb +4 -2
  42. data/lib/alexandria/library_store.rb +39 -28
  43. data/lib/alexandria/logging.rb +10 -14
  44. data/lib/alexandria/models/book.rb +5 -4
  45. data/lib/alexandria/models/library.rb +63 -53
  46. data/lib/alexandria/net.rb +5 -6
  47. data/lib/alexandria/preferences.rb +66 -63
  48. data/lib/alexandria/scanners.rb +2 -2
  49. data/lib/alexandria/scanners/{cuecat.rb → cue_cat.rb} +17 -17
  50. data/lib/alexandria/scanners/keyboard.rb +8 -8
  51. data/lib/alexandria/smart_library.rb +110 -112
  52. data/lib/alexandria/ui.rb +15 -15
  53. data/lib/alexandria/ui/{dialogs/about_dialog.rb → about_dialog.rb} +2 -2
  54. data/lib/alexandria/ui/{dialogs/acquire_dialog.rb → acquire_dialog.rb} +108 -109
  55. data/lib/alexandria/ui/alert_dialog.rb +66 -0
  56. data/lib/alexandria/ui/{dialogs/bad_isbns_dialog.rb → bad_isbns_dialog.rb} +13 -9
  57. data/lib/alexandria/ui/{dialogs/barcode_animation.rb → barcode_animation.rb} +16 -15
  58. data/lib/alexandria/ui/{dialogs/book_properties_dialog.rb → book_properties_dialog.rb} +25 -38
  59. data/lib/alexandria/ui/{dialogs/book_properties_dialog_base.rb → book_properties_dialog_base.rb} +64 -157
  60. data/lib/alexandria/ui/builder_base.rb +1 -1
  61. data/lib/alexandria/ui/calendar_popup.rb +58 -0
  62. data/lib/alexandria/ui/callbacks.rb +187 -155
  63. data/lib/alexandria/ui/completion_models.rb +8 -22
  64. data/lib/alexandria/ui/confirm_erase_dialog.rb +33 -0
  65. data/lib/alexandria/ui/conflict_while_copying_dialog.rb +34 -0
  66. data/lib/alexandria/ui/dndable.rb +7 -7
  67. data/lib/alexandria/ui/error_dialog.rb +25 -0
  68. data/lib/alexandria/ui/{dialogs/export_dialog.rb → export_dialog.rb} +37 -58
  69. data/lib/alexandria/ui/icons.rb +38 -43
  70. data/lib/alexandria/ui/iconview.rb +12 -10
  71. data/lib/alexandria/ui/iconview_tooltips.rb +41 -54
  72. data/lib/alexandria/ui/import_dialog.rb +157 -0
  73. data/lib/alexandria/ui/init.rb +30 -41
  74. data/lib/alexandria/ui/{dialogs/keep_bad_isbn_dialog.rb → keep_bad_isbn_dialog.rb} +9 -6
  75. data/lib/alexandria/ui/libraries_combo.rb +15 -14
  76. data/lib/alexandria/ui/listview.rb +69 -67
  77. data/lib/alexandria/ui/main_app.rb +24 -26
  78. data/lib/alexandria/ui/misc_dialogs.rb +10 -0
  79. data/lib/alexandria/ui/multi_drag_treeview.rb +8 -9
  80. data/lib/alexandria/ui/{dialogs/new_book_dialog.rb → new_book_dialog.rb} +113 -114
  81. data/lib/alexandria/ui/{dialogs/new_book_dialog_manual.rb → new_book_dialog_manual.rb} +22 -19
  82. data/lib/alexandria/ui/new_provider_dialog.rb +100 -0
  83. data/lib/alexandria/ui/new_smart_library_dialog.rb +74 -0
  84. data/lib/alexandria/ui/preferences_dialog.rb +313 -0
  85. data/lib/alexandria/ui/provider_preferences_base_dialog.rb +95 -0
  86. data/lib/alexandria/ui/provider_preferences_dialog.rb +35 -0
  87. data/lib/alexandria/ui/{dialogs/misc_dialogs.rb → really_delete_dialog.rb} +7 -28
  88. data/lib/alexandria/ui/{sidepane.rb → sidepane_manager.rb} +53 -48
  89. data/lib/alexandria/ui/skip_entry_dialog.rb +33 -0
  90. data/lib/alexandria/ui/smart_library_properties_dialog.rb +60 -0
  91. data/lib/alexandria/ui/smart_library_properties_dialog_base.rb +242 -0
  92. data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
  93. data/lib/alexandria/ui/sound.rb +11 -13
  94. data/lib/alexandria/ui/ui_manager.rb +216 -200
  95. data/lib/alexandria/version.rb +4 -19
  96. data/lib/alexandria/web_themes.rb +21 -21
  97. data/po/Makefile +2 -2
  98. data/po/cs.po +992 -875
  99. data/po/cy.po +961 -874
  100. data/po/de.po +990 -865
  101. data/po/el.po +989 -865
  102. data/po/es.po +985 -861
  103. data/po/fr.po +987 -867
  104. data/po/ga.po +908 -820
  105. data/po/gl.po +980 -860
  106. data/po/it.po +986 -864
  107. data/po/ja.po +969 -849
  108. data/po/mk.po +984 -860
  109. data/po/nb.po +979 -859
  110. data/po/nl.po +983 -860
  111. data/po/pl.po +1018 -971
  112. data/po/pt.po +988 -857
  113. data/po/pt_BR.po +983 -863
  114. data/po/ru.po +994 -871
  115. data/po/sk.po +989 -867
  116. data/po/sv.po +976 -856
  117. data/po/uk.po +972 -858
  118. data/po/zh_TW.po +974 -854
  119. data/schemas/alexandria.schemas +24 -2
  120. data/share/alexandria/glade/acquire_dialog__builder.glade +1 -1
  121. data/share/alexandria/glade/book_properties_dialog__builder.glade +1 -1
  122. data/share/alexandria/glade/main_app__builder.glade +6 -21
  123. data/share/alexandria/glade/new_book_dialog__builder.glade +1 -1
  124. data/share/alexandria/glade/preferences_dialog__builder.glade +1 -1
  125. data/share/gnome/help/alexandria/C/introduction.xml +0 -4
  126. data/share/gnome/help/alexandria/C/searching.xml +1 -1
  127. data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
  128. data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
  129. data/share/gnome/help/alexandria/fr/alexandria.xml +1 -1
  130. data/share/gnome/help/alexandria/ja/introduction.xml +0 -4
  131. data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
  132. data/spec/alexandria/book_providers/thalia_provider_spec.rb +119 -0
  133. data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
  134. data/spec/alexandria/book_providers_spec.rb +62 -156
  135. data/spec/alexandria/book_spec.rb +12 -10
  136. data/spec/alexandria/console_spec.rb +6 -11
  137. data/spec/alexandria/export_library_spec.rb +47 -58
  138. data/spec/alexandria/library_spec.rb +121 -109
  139. data/spec/alexandria/library_store_spec.rb +8 -8
  140. data/spec/alexandria/preferences_spec.rb +44 -17
  141. data/spec/alexandria/scanners/cue_cat_spec.rb +52 -0
  142. data/spec/alexandria/smart_library_spec.rb +15 -15
  143. data/spec/alexandria/ui/about_dialog_spec.rb +14 -0
  144. data/spec/alexandria/ui/acquire_dialog_spec.rb +14 -0
  145. data/spec/alexandria/ui/alert_dialog_spec.rb +16 -0
  146. data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +14 -0
  147. data/spec/alexandria/ui/book_properties_dialog_spec.rb +59 -0
  148. data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +14 -0
  149. data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +16 -0
  150. data/spec/alexandria/ui/error_dialog_spec.rb +14 -0
  151. data/spec/alexandria/ui/export_dialog_spec.rb +36 -0
  152. data/spec/alexandria/ui/icons_spec.rb +26 -0
  153. data/spec/alexandria/ui/iconview_spec.rb +7 -21
  154. data/spec/alexandria/ui/import_dialog_spec.rb +46 -0
  155. data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +17 -0
  156. data/spec/alexandria/ui/main_app_spec.rb +7 -34
  157. data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +51 -0
  158. data/spec/alexandria/ui/{dialogs/new_book_dialog_spec.rb → new_book_dialog_spec.rb} +4 -4
  159. data/spec/alexandria/ui/new_provider_dialog_spec.rb +30 -0
  160. data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +39 -0
  161. data/spec/alexandria/ui/preferences_dialog_spec.rb +14 -0
  162. data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +34 -0
  163. data/spec/alexandria/ui/really_delete_dialog_spec.rb +16 -0
  164. data/spec/alexandria/ui/sidepane_manager_spec.rb +15 -0
  165. data/spec/alexandria/ui/skip_entry_dialog_spec.rb +14 -0
  166. data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +49 -0
  167. data/spec/alexandria/ui/sound_spec.rb +2 -2
  168. data/spec/alexandria/ui/ui_manager_spec.rb +44 -20
  169. data/spec/end_to_end/basic_run_spec.rb +21 -38
  170. data/spec/fixtures/cover.jpg +0 -0
  171. data/spec/spec_helper.rb +54 -10
  172. data/tasks/setup.rb +2 -2
  173. data/tasks/spec.rake +11 -11
  174. data/util/rake/fileinstall.rb +38 -35
  175. data/util/rake/gettextgenerate.rb +7 -7
  176. data/util/rake/omfgenerate.rb +7 -7
  177. metadata +158 -45
  178. data/dogtail/basic_run_test.py +0 -9
  179. data/lib/alexandria/book_providers/renaud.rb +0 -155
  180. data/lib/alexandria/book_providers/thalia.rb +0 -198
  181. data/lib/alexandria/ui/dialogs/alert_dialog.rb +0 -63
  182. data/lib/alexandria/ui/dialogs/import_dialog.rb +0 -176
  183. data/lib/alexandria/ui/dialogs/new_smart_library_dialog.rb +0 -62
  184. data/lib/alexandria/ui/dialogs/preferences_dialog.rb +0 -563
  185. data/lib/alexandria/ui/dialogs/smart_library_properties_dialog.rb +0 -61
  186. data/lib/alexandria/ui/dialogs/smart_library_properties_dialog_base.rb +0 -423
  187. data/spec/alexandria/scanners/cuecat_spec.rb +0 -67
  188. data/spec/alexandria/ui/dialogs_spec.rb +0 -162
  189. data/spec/alexandria/ui/sidepane_spec.rb +0 -29
  190. data/spec/alexandria/ui/ui_utilities_spec.rb +0 -62
  191. data/spec/alexandria/utilities_spec.rb +0 -52
  192. data/tasks/dogtail.rake +0 -6
@@ -4,8 +4,8 @@
4
4
  #
5
5
  # See the file README.md for authorship and licensing information.
6
6
 
7
- require 'observer'
8
- require 'singleton'
7
+ require "observer"
8
+ require "singleton"
9
9
 
10
10
  module Alexandria
11
11
  class LibraryCollection
@@ -22,11 +22,12 @@ module Alexandria
22
22
 
23
23
  ruined = []
24
24
  deleted = []
25
- all_regular_libraries.each { |library|
25
+ all_regular_libraries.each do |library|
26
26
  ruined += library.ruined_books
27
- # make deleted books from each library accessible so we don't crash on smart libraries
27
+ # make deleted books from each library accessible so we don't crash on
28
+ # smart libraries
28
29
  deleted += library.deleted_books
29
- }
30
+ end
30
31
  @ruined_books = ruined
31
32
  @deleted_books = deleted
32
33
  end
@@ -29,14 +29,16 @@ 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
36
38
  end
37
39
 
38
40
  def to_s
39
- 'default order'
41
+ "default order"
40
42
  end
41
43
  end
42
44
  end
@@ -9,10 +9,10 @@ module Alexandria
9
9
  include Logging
10
10
 
11
11
  FIX_BIGNUM_REGEX =
12
- /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
- bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
15
+ bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
16
16
 
17
17
  def initialize(dir)
18
18
  @dir = dir
@@ -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 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
 
@@ -34,7 +34,7 @@ module Alexandria
34
34
  end
35
35
  # Create the default library if there is no library yet.
36
36
 
37
- a << load_library(_('My Library')) if a.empty?
37
+ a << load_library(_("My Library")) if a.empty?
38
38
 
39
39
  a
40
40
  end
@@ -45,7 +45,7 @@ module Alexandria
45
45
  library = Library.new(name, self)
46
46
  FileUtils.mkdir_p(library.path) unless File.exist?(library.path)
47
47
  Dir.chdir(library.path) do
48
- Dir['*' + Library::EXT[:book]].each do |filename|
48
+ Dir["*" + Library::EXT[:book]].sort.each do |filename|
49
49
  test[1] = filename if (test[0]).zero?
50
50
 
51
51
  unless File.size? test[1]
@@ -64,32 +64,41 @@ 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
71
71
 
72
- book.publishing_year = book.publishing_year.to_i unless book.publishing_year.nil?
72
+ unless book.publishing_year.nil?
73
+ book.publishing_year = book.publishing_year.to_i
74
+ end
73
75
 
74
76
  # Or if isbn has changed
75
- 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
76
80
 
77
81
  # Re-save book if Alexandria::DATA_VERSION changes
78
- raise "#{test[1]} version is not okay" unless book.version == Alexandria::DATA_VERSION
82
+ unless book.version == Alexandria::DATA_VERSION
83
+ raise format(_("%<file>s version is not okay"), file: test[1])
84
+ end
79
85
 
80
86
  # Or if publishing year has changed
81
- raise "#{test[1]} pub year is not okay" unless book.publishing_year == old_pub_year
87
+ unless book.publishing_year == old_pub_year
88
+ raise format(_("%<file>s pub year is not okay"), file: test[1])
89
+ end
82
90
 
83
91
  # ruined_books << [book, book.isbn, library]
84
92
  book.library = library.name
85
93
 
86
94
  ## TODO copy cover image file, if necessary
87
- # due to #26909 cover files for books without ISBN are re-saved as "g#{ident}.cover"
88
- if book.isbn.nil? || book.isbn.empty?
89
- if File.exist? library.old_cover(book)
90
- log.debug { "#{library.name}; book #{book.title} has no ISBN, fixing cover image" }
91
- FileUtils::Verbose.mv(library.old_cover(book), library.cover(book))
95
+ # due to #26909 cover files for books without ISBN are re-saved as
96
+ # "g#{ident}.cover"
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"
92
100
  end
101
+ FileUtils::Verbose.mv(library.old_cover(book), library.cover(book))
93
102
  end
94
103
 
95
104
  library << book
@@ -111,21 +120,23 @@ module Alexandria
111
120
  # '_medium.jpg' have been deprecated for a single medium
112
121
  # cover file named '.cover'.
113
122
 
114
- Dir['*' + '_medium.jpg'].each do |medium_cover|
123
+ Dir["*" + "_medium.jpg"].each do |medium_cover|
115
124
  FileUtils.mv(medium_cover,
116
125
  medium_cover.sub(/_medium\.jpg$/,
117
126
  Library::EXT[:cover]))
118
127
  end
119
128
 
120
- Dir['*' + Library::EXT[:cover]].each do |cover|
121
- next if cover[0] == 'g'
129
+ Dir["*" + Library::EXT[:cover]].each do |cover|
130
+ next if cover[0] == "g"
122
131
 
123
132
  md = /(.+)\.cover/.match(cover)
124
133
  ean = Library.canonicalise_ean(md[1]) || md[1]
125
- FileUtils.mv(cover, ean + Library::EXT[:cover]) unless cover == ean + Library::EXT[:cover]
134
+ unless cover == ean + Library::EXT[:cover]
135
+ FileUtils.mv(cover, ean + Library::EXT[:cover])
136
+ end
126
137
  end
127
138
 
128
- FileUtils.rm_f(Dir['*_small.jpg'])
139
+ FileUtils.rm_f(Dir["*_small.jpg"])
129
140
  end
130
141
  library.ruined_books = ruined_books
131
142
 
@@ -137,7 +148,7 @@ module Alexandria
137
148
  begin
138
149
  # Deserialize smart libraries.
139
150
  Dir.chdir(smart_library_dir) do
140
- Dir['*' + SmartLibrary::EXT].each do |filename|
151
+ Dir["*" + SmartLibrary::EXT].each do |filename|
141
152
  # Skip non-regular files.
142
153
  next unless File.stat(filename).file?
143
154
 
@@ -164,7 +175,7 @@ module Alexandria
164
175
  end
165
176
 
166
177
  def smart_library_dir
167
- File.join(@dir, '.smart_libraries')
178
+ File.join(@dir, ".smart_libraries")
168
179
  end
169
180
 
170
181
  private
@@ -177,9 +188,9 @@ module Alexandria
177
188
 
178
189
  # The string is removed on load, but can't make it stick, maybe has to do with cache
179
190
 
180
- if text =~ /!str:Amazon::Search::Response/
191
+ if /!str:Amazon::Search::Response/.match?(text)
181
192
  log.debug { "Removing Ruby/Amazon strings from #{name}" }
182
- text.gsub!('!str:Amazon::Search::Response', '')
193
+ text.gsub!("!str:Amazon::Search::Response", "")
183
194
  end
184
195
 
185
196
  # Backward compatibility with versions <= 0.6.0, where the
@@ -187,14 +198,14 @@ module Alexandria
187
198
  if (md = FIX_BIGNUM_REGEX.match(text))
188
199
  new_yaml = Time.at(md[2].to_i).to_yaml
189
200
  # Remove the "---" prefix.
190
- new_yaml.sub!(/^\s*\-+\s*/, '')
201
+ new_yaml.sub!(/^\s*-+\s*/, "")
191
202
  text.sub!(md[0], "loaned_since: #{new_yaml}\n")
192
203
  end
193
204
 
194
205
  # TODO: Ensure book loading passes through Book#initialize
195
206
  book = YAML.safe_load(text, permitted_classes: [Book, Time])
196
207
 
197
- unless book.isbn.class == String
208
+ unless book.isbn.instance_of? String
198
209
  # HACK
199
210
  md = /isbn: (.+)/.match(text)
200
211
  if md
@@ -204,7 +215,7 @@ module Alexandria
204
215
  end
205
216
 
206
217
  # another HACK of the same type as above
207
- unless book.saved_ident.class == String
218
+ unless book.saved_ident.instance_of? String
208
219
 
209
220
  md2 = /saved_ident: (.+)/.match(text)
210
221
  if md2
@@ -213,7 +224,7 @@ module Alexandria
213
224
  book.saved_ident = string_saved_ident
214
225
  end
215
226
  end
216
- if (book.isbn.class == String) && book.isbn.empty?
227
+ if (book.isbn.instance_of? String) && book.isbn.empty?
217
228
  book.isbn = nil # save trouble later
218
229
  end
219
230
  book
@@ -18,20 +18,20 @@
18
18
  # write to the Free Software Foundation, Inc., 51 Franklin Street,
19
19
  # Fifth Floor, Boston, MA 02110-1301 USA.
20
20
 
21
- require 'logger'
22
- require 'forwardable'
21
+ require "logger"
22
+ require "forwardable"
23
23
 
24
24
  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)
@@ -82,9 +82,9 @@ module Alexandria
82
82
 
83
83
  def <<(msg)
84
84
  if msg.respond_to? :backtrace
85
- msg.backtrace.each { |line|
85
+ msg.backtrace.each do |line|
86
86
  @logger << " #{line} \n"
87
- }
87
+ end
88
88
  else
89
89
  @logger << msg + "\n"
90
90
  end
@@ -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,17 +127,15 @@ 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
- level = ENV['LOGLEVEL'] ? ENV['LOGLEVEL'].intern : nil
138
+ level = ENV["LOGLEVEL"] ? ENV["LOGLEVEL"].intern : nil
141
139
  if [:FATAL, :ERROR, :WARN, :INFO, :DEBUG].include? level
142
140
  logger.level = Logger.const_get(level)
143
141
  else
@@ -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
@@ -8,7 +8,8 @@ module Alexandria
8
8
  class Book
9
9
  attr_accessor :title, :authors, :isbn, :publisher, :publishing_year,
10
10
  :edition, :notes, :loaned, :loaned_since,
11
- :loaned_to, :saved_ident, :redd, :redd_when, :own, :want, :tags, :version, :library
11
+ :loaned_to, :saved_ident, :redd, :redd_when, :own, :want,
12
+ :tags, :version, :library
12
13
 
13
14
  attr_reader :rating
14
15
 
@@ -24,7 +25,7 @@ module Alexandria
24
25
  @isbn = isbn
25
26
  @publisher = publisher
26
27
  @edition = edition # actually used for binding! (i.e. paperback or hardback)
27
- @notes = ''
28
+ @notes = ""
28
29
  @saved_ident = ident
29
30
  @publishing_year = publishing_year
30
31
  @redd = false
@@ -63,8 +64,8 @@ module Alexandria
63
64
  own || false
64
65
  end
65
66
 
66
- def ==(obj)
67
- obj.is_a?(self.class) && (ident == obj.ident)
67
+ def ==(other)
68
+ other.is_a?(self.class) && (ident == other.ident)
68
69
  end
69
70
 
70
71
  def inspect
@@ -4,12 +4,12 @@
4
4
  #
5
5
  # See the file README.md for authorship and licensing information.
6
6
 
7
- require 'yaml'
8
- require 'fileutils'
9
- require 'rexml/document'
10
- require 'tempfile'
11
- require 'etc'
12
- require 'alexandria/library_store'
7
+ require "yaml"
8
+ require "fileutils"
9
+ require "rexml/document"
10
+ require "tempfile"
11
+ require "etc"
12
+ require "alexandria/library_store"
13
13
 
14
14
  module Alexandria
15
15
  class Library < Array
@@ -17,12 +17,13 @@ module Alexandria
17
17
 
18
18
  attr_reader :name
19
19
  attr_accessor :ruined_books, :updating, :deleted_books
20
- DEFAULT_DIR = File.join(ENV['HOME'], '.alexandria')
21
- EXT = { book: '.yaml', cover: '.cover' }.freeze
20
+
21
+ DEFAULT_DIR = File.join(ENV["HOME"], ".alexandria")
22
+ EXT = { book: ".yaml", cover: ".cover" }.freeze
22
23
 
23
24
  include GetText
24
25
  extend GetText
25
- bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
26
+ bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
26
27
 
27
28
  BOOK_ADDED, BOOK_UPDATED, BOOK_REMOVED = (0..3).to_a
28
29
  include Observable
@@ -36,7 +37,7 @@ module Alexandria
36
37
  end
37
38
 
38
39
  def self.generate_new_name(existing_libraries,
39
- from_base = _('Untitled'))
40
+ from_base = _("Untitled"))
40
41
  i = 1
41
42
  name = nil
42
43
  all_libraries = existing_libraries + @@deleted_libraries
@@ -53,7 +54,9 @@ module Alexandria
53
54
  dest = dest_library.path
54
55
  books.each do |book|
55
56
  FileUtils.mv(source_library.yaml(book), dest)
56
- FileUtils.mv(source_library.cover(book), dest) if File.exist?(source_library.cover(book))
57
+ if File.exist?(source_library.cover(book))
58
+ FileUtils.mv(source_library.cover(book), dest)
59
+ end
57
60
 
58
61
  source_library.changed
59
62
  source_library.old_delete(book)
@@ -71,11 +74,11 @@ module Alexandria
71
74
  def self.extract_numbers(entry)
72
75
  return [] if entry.nil? || entry.empty?
73
76
 
74
- normalized = entry.delete('- ').upcase
75
- return [] unless normalized =~ /\A[\dX]*\Z/
77
+ normalized = entry.delete("- ").upcase
78
+ return [] unless /\A[\dX]*\Z/.match?(normalized)
76
79
 
77
- normalized.split('').map do |char|
78
- char == 'X' ? 10 : char.to_i
80
+ normalized.split("").map do |char|
81
+ char == "X" ? 10 : char.to_i
79
82
  end
80
83
  end
81
84
 
@@ -84,7 +87,7 @@ module Alexandria
84
87
  accumulator + numbers[i] * (i + 1)
85
88
  end % 11
86
89
 
87
- sum == 10 ? 'X' : sum
90
+ sum == 10 ? "X" : sum
88
91
  end
89
92
 
90
93
  def self.valid_isbn?(isbn)
@@ -93,8 +96,8 @@ module Alexandria
93
96
  end
94
97
 
95
98
  def self.ean_checksum(numbers)
96
- -(numbers.values_at(1, 3, 5, 7, 9, 11).reduce(:+) * 3 +
97
- numbers.values_at(0, 2, 4, 6, 8, 10).reduce(:+)) % 10
99
+ -(numbers.values_at(1, 3, 5, 7, 9, 11).sum * 3 +
100
+ numbers.values_at(0, 2, 4, 6, 8, 10).sum) % 10
98
101
  end
99
102
 
100
103
  def self.valid_ean?(ean)
@@ -106,8 +109,8 @@ module Alexandria
106
109
  end
107
110
 
108
111
  def self.upc_checksum(numbers)
109
- -(numbers.values_at(0, 2, 4, 6, 8, 10).reduce(:+) * 3 +
110
- numbers.values_at(1, 3, 5, 7, 9).reduce(:+)) % 10
112
+ -(numbers.values_at(0, 2, 4, 6, 8, 10).sum * 3 +
113
+ numbers.values_at(1, 3, 5, 7, 9).sum) % 10
111
114
  end
112
115
 
113
116
  def self.valid_upc?(upc)
@@ -117,18 +120,18 @@ module Alexandria
117
120
  end
118
121
 
119
122
  AMERICAN_UPC_LOOKUP = {
120
- '014794' => '08041', '018926' => '0445', '02778' => '0449',
121
- '037145' => '0812', '042799' => '0785', '043144' => '0688',
122
- '044903' => '0312', '045863' => '0517', '046594' => '0064',
123
- '047132' => '0152', '051487' => '08167', '051488' => '0140',
124
- '060771' => '0002', '065373' => '0373', '070992' => '0523',
125
- '070993' => '0446', '070999' => '0345', '071001' => '0380',
126
- '071009' => '0440', '071125' => '088677', '071136' => '0451',
127
- '071149' => '0451', '071152' => '0515', '071162' => '0451',
128
- '071268' => '08217', '071831' => '0425', '071842' => '08439',
129
- '072742' => '0441', '076714' => '0671', '076783' => '0553',
130
- '076814' => '0449', '078021' => '0872', '079808' => '0394',
131
- '090129' => '0679', '099455' => '0061', '099769' => '0451'
123
+ "014794" => "08041", "018926" => "0445", "02778" => "0449",
124
+ "037145" => "0812", "042799" => "0785", "043144" => "0688",
125
+ "044903" => "0312", "045863" => "0517", "046594" => "0064",
126
+ "047132" => "0152", "051487" => "08167", "051488" => "0140",
127
+ "060771" => "0002", "065373" => "0373", "070992" => "0523",
128
+ "070993" => "0446", "070999" => "0345", "071001" => "0380",
129
+ "071009" => "0440", "071125" => "088677", "071136" => "0451",
130
+ "071149" => "0451", "071152" => "0515", "071162" => "0451",
131
+ "071268" => "08217", "071831" => "0425", "071842" => "08439",
132
+ "072742" => "0441", "076714" => "0671", "076783" => "0553",
133
+ "076814" => "0449", "078021" => "0872", "079808" => "0394",
134
+ "090129" => "0679", "099455" => "0061", "099769" => "0451"
132
135
  }.freeze
133
136
 
134
137
  def self.upc_convert(upc)
@@ -137,15 +140,15 @@ module Alexandria
137
140
  end
138
141
 
139
142
  def self.canonicalise_ean(code)
140
- code = code.to_s.delete('- ')
143
+ code = code.to_s.delete("- ")
141
144
  if valid_ean?(code)
142
145
  code
143
146
  elsif valid_isbn?(code)
144
- code = '978' + code[0..8]
147
+ code = "978" + code[0..8]
145
148
  code + String(ean_checksum(extract_numbers(code)))
146
149
  elsif valid_upc?(code)
147
150
  isbn10 = canonicalise_isbn
148
- code = '978' + isbn10[0..8]
151
+ code = "978" + isbn10[0..8]
149
152
  code + String(ean_checksum(extract_numbers(code)))
150
153
  end
151
154
  end
@@ -181,12 +184,14 @@ module Alexandria
181
184
  book.saved_ident = book.ident if book.saved_ident.nil? || book.saved_ident.empty?
182
185
  if book.ident != book.saved_ident
183
186
  FileUtils.rm(yaml(book.saved_ident))
184
- FileUtils.mv(cover(book.saved_ident), cover(book.ident)) if File.exist?(cover(book.saved_ident))
187
+ if File.exist?(cover(book.saved_ident))
188
+ FileUtils.mv(cover(book.saved_ident), cover(book.ident))
189
+ end
185
190
  end
186
191
  book.saved_ident = book.ident
187
192
 
188
- filename = book.saved_ident.to_s + '.yaml'
189
- File.open(filename, 'w') { |io| io.puts book.to_yaml }
193
+ filename = book.saved_ident.to_s + ".yaml"
194
+ File.open(filename, "w") { |io| io.puts book.to_yaml }
190
195
  filename
191
196
  end
192
197
 
@@ -199,7 +204,9 @@ module Alexandria
199
204
 
200
205
  if book.ident != book.saved_ident
201
206
  FileUtils.rm(yaml(book.saved_ident))
202
- FileUtils.mv(cover(book.saved_ident), cover(book.ident)) if File.exist?(cover(book.saved_ident))
207
+ if File.exist?(cover(book.saved_ident))
208
+ FileUtils.mv(cover(book.saved_ident), cover(book.ident))
209
+ end
203
210
 
204
211
  # Notify before updating the saved identifier, so the views
205
212
  # can still use the old one to update their models.
@@ -212,14 +219,14 @@ module Alexandria
212
219
 
213
220
  temp_book = book.dup
214
221
  temp_book.library = nil
215
- File.open(yaml(temp_book), 'w') { |io| io.puts temp_book.to_yaml }
222
+ File.open(yaml(temp_book), "w") { |io| io.puts temp_book.to_yaml }
216
223
 
217
224
  # Do not notify twice.
218
- if changed?
219
- notify_observers(self,
220
- already_there ? BOOK_UPDATED : BOOK_ADDED,
221
- book)
222
- end
225
+ return unless changed?
226
+
227
+ notify_observers(self,
228
+ already_there ? BOOK_UPDATED : BOOK_ADDED,
229
+ book)
223
230
  end
224
231
 
225
232
  def transport
@@ -231,7 +238,7 @@ module Alexandria
231
238
  Dir.chdir(path) do
232
239
  # Fetch the cover picture.
233
240
  cover_file = cover(book)
234
- File.open(cover_file, 'w') do |io|
241
+ File.open(cover_file, "w") do |io|
235
242
  uri = URI.parse(cover_uri)
236
243
  if uri.scheme.nil?
237
244
  # Regular filename.
@@ -277,7 +284,10 @@ module Alexandria
277
284
  else
278
285
  if @deleted_books.include?(book)
279
286
  doubles = @deleted_books.select { |b| b.equal?(book) }
280
- raise ArgumentError, "Book #{book.isbn} was already deleted" unless doubles.empty?
287
+ unless doubles.empty?
288
+ raise ArgumentError, format(_("Book %<isbn>s was already deleted"),
289
+ isbn: book.isbn)
290
+ end
281
291
  end
282
292
  @deleted_books << book
283
293
  i = index(book)
@@ -340,7 +350,7 @@ module Alexandria
340
350
  when Integer
341
351
  something
342
352
  else
343
- raise "#{something} is a #{something.class}"
353
+ raise NotImplementedError
344
354
  end
345
355
  File.join(path, ident.to_s + EXT[:cover])
346
356
  end
@@ -354,7 +364,7 @@ module Alexandria
354
364
  when Integer
355
365
  something
356
366
  else
357
- raise "#{something} is #{something.class}"
367
+ raise NotImplementedError
358
368
  end
359
369
  File.join(basedir, ident.to_s + EXT[:book])
360
370
  end
@@ -372,8 +382,8 @@ module Alexandria
372
382
  length - n_rated
373
383
  end
374
384
 
375
- def ==(object)
376
- object.is_a?(self.class) && object.name == name
385
+ def ==(other)
386
+ other.is_a?(self.class) && other.name == name
377
387
  end
378
388
 
379
389
  def copy_covers(somewhere)
@@ -388,12 +398,12 @@ module Alexandria
388
398
  end
389
399
 
390
400
  def self.jpeg?(file)
391
- IO.read(file, 10)[6..9] == 'JFIF'
401
+ IO.read(file, 10)[6..9] == "JFIF"
392
402
  end
393
403
 
394
404
  def final_cover(book)
395
405
  # TODO: what about PNG?
396
- book.ident + (Library.jpeg?(cover(book)) ? '.jpg' : '.gif')
406
+ book.ident + (Library.jpeg?(cover(book)) ? ".jpg" : ".gif")
397
407
  end
398
408
 
399
409
  protected