alexandria-book-collection-manager 0.7.2 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) 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 +5 -1
  5. data/.hound.yml +2 -0
  6. data/.rubocop.yml +87 -37
  7. data/.rubocop_todo.yml +62 -191
  8. data/.simplecov +5 -2
  9. data/CHANGELOG.md +63 -0
  10. data/Gemfile +4 -3
  11. data/INSTALL.md +26 -14
  12. data/README.md +52 -42
  13. data/Rakefile +93 -109
  14. data/TODO.md +9 -1
  15. data/alexandria-book-collection-manager.gemspec +50 -43
  16. data/bin/alexandria +30 -53
  17. data/doc/FAQ +2 -6
  18. data/doc/dependency_decisions.yml +27 -8
  19. data/lib/alexandria.rb +27 -37
  20. data/lib/alexandria/about.rb +50 -50
  21. data/lib/alexandria/book_providers.rb +90 -97
  22. data/lib/alexandria/book_providers/adlibris.rb +41 -76
  23. data/lib/alexandria/book_providers/amazon_aws.rb +96 -100
  24. data/lib/alexandria/book_providers/amazon_ecs_util.rb +295 -322
  25. data/lib/alexandria/book_providers/barnes_and_noble.rb +48 -45
  26. data/lib/alexandria/book_providers/douban.rb +26 -42
  27. data/lib/alexandria/book_providers/proxis.rb +44 -55
  28. data/lib/alexandria/book_providers/pseudomarc.rb +77 -85
  29. data/lib/alexandria/book_providers/siciliano.rb +64 -65
  30. data/lib/alexandria/book_providers/thalia.rb +42 -41
  31. data/lib/alexandria/book_providers/web.rb +15 -33
  32. data/lib/alexandria/book_providers/worldcat.rb +70 -97
  33. data/lib/alexandria/book_providers/z3950.rb +160 -173
  34. data/lib/alexandria/config.rb +1 -1
  35. data/lib/alexandria/console.rb +8 -21
  36. data/lib/alexandria/default_preferences.rb +37 -0
  37. data/lib/alexandria/execution_queue.rb +15 -13
  38. data/lib/alexandria/export_format.rb +47 -0
  39. data/lib/alexandria/export_library.rb +193 -300
  40. data/lib/alexandria/import_library.rb +108 -141
  41. data/lib/alexandria/import_library_csv.rb +43 -46
  42. data/lib/alexandria/library_collection.rb +79 -0
  43. data/lib/alexandria/library_sort_order.rb +45 -0
  44. data/lib/alexandria/library_store.rb +233 -0
  45. data/lib/alexandria/logging.rb +11 -13
  46. data/lib/alexandria/models/book.rb +13 -20
  47. data/lib/alexandria/models/library.rb +81 -353
  48. data/lib/alexandria/net.rb +5 -6
  49. data/lib/alexandria/preferences.rb +73 -87
  50. data/lib/alexandria/scanners.rb +2 -2
  51. data/lib/alexandria/scanners/{cuecat.rb → cue_cat.rb} +20 -18
  52. data/lib/alexandria/scanners/keyboard.rb +8 -8
  53. data/lib/alexandria/smart_library.rb +133 -170
  54. data/lib/alexandria/ui.rb +15 -15
  55. data/lib/alexandria/ui/about_dialog.rb +49 -0
  56. data/lib/alexandria/ui/{dialogs/acquire_dialog.rb → acquire_dialog.rb} +119 -136
  57. data/lib/alexandria/ui/alert_dialog.rb +64 -0
  58. data/lib/alexandria/ui/bad_isbns_dialog.rb +41 -0
  59. data/lib/alexandria/ui/{dialogs/barcode_animation.rb → barcode_animation.rb} +16 -15
  60. data/lib/alexandria/ui/{dialogs/book_properties_dialog.rb → book_properties_dialog.rb} +39 -52
  61. data/lib/alexandria/ui/book_properties_dialog_base.rb +318 -0
  62. data/lib/alexandria/ui/builder_base.rb +7 -27
  63. data/lib/alexandria/ui/calendar_popup.rb +58 -0
  64. data/lib/alexandria/ui/callbacks.rb +189 -183
  65. data/lib/alexandria/ui/completion_models.rb +10 -23
  66. data/lib/alexandria/ui/confirm_erase_dialog.rb +33 -0
  67. data/lib/alexandria/ui/conflict_while_copying_dialog.rb +34 -0
  68. data/lib/alexandria/ui/dndable.rb +7 -7
  69. data/lib/alexandria/ui/error_dialog.rb +25 -0
  70. data/lib/alexandria/ui/export_dialog.rb +142 -0
  71. data/lib/alexandria/ui/icons.rb +47 -63
  72. data/lib/alexandria/ui/iconview.rb +12 -10
  73. data/lib/alexandria/ui/iconview_tooltips.rb +41 -54
  74. data/lib/alexandria/ui/import_dialog.rb +157 -0
  75. data/lib/alexandria/ui/init.rb +21 -33
  76. data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +36 -0
  77. data/lib/alexandria/ui/libraries_combo.rb +16 -14
  78. data/lib/alexandria/ui/listview.rb +73 -87
  79. data/lib/alexandria/ui/main_app.rb +24 -26
  80. data/lib/alexandria/ui/misc_dialogs.rb +10 -0
  81. data/lib/alexandria/ui/multi_drag_treeview.rb +28 -41
  82. data/lib/alexandria/ui/{dialogs/new_book_dialog.rb → new_book_dialog.rb} +156 -194
  83. data/lib/alexandria/ui/new_book_dialog_manual.rb +139 -0
  84. data/lib/alexandria/ui/new_provider_dialog.rb +100 -0
  85. data/lib/alexandria/ui/new_smart_library_dialog.rb +74 -0
  86. data/lib/alexandria/ui/preferences_dialog.rb +313 -0
  87. data/lib/alexandria/ui/provider_preferences_base_dialog.rb +95 -0
  88. data/lib/alexandria/ui/provider_preferences_dialog.rb +35 -0
  89. data/lib/alexandria/ui/really_delete_dialog.rb +53 -0
  90. data/lib/alexandria/ui/{sidepane.rb → sidepane_manager.rb} +56 -68
  91. data/lib/alexandria/ui/skip_entry_dialog.rb +33 -0
  92. data/lib/alexandria/ui/smart_library_properties_dialog.rb +60 -0
  93. data/lib/alexandria/ui/smart_library_properties_dialog_base.rb +242 -0
  94. data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
  95. data/lib/alexandria/ui/sound.rb +11 -13
  96. data/lib/alexandria/ui/ui_manager.rb +236 -251
  97. data/lib/alexandria/undo_manager.rb +1 -0
  98. data/lib/alexandria/version.rb +4 -19
  99. data/lib/alexandria/web_themes.rb +22 -21
  100. data/po/Makefile +2 -2
  101. data/po/cs.po +993 -880
  102. data/po/cy.po +957 -874
  103. data/po/de.po +990 -869
  104. data/po/el.po +989 -869
  105. data/po/es.po +985 -865
  106. data/po/fr.po +986 -870
  107. data/po/ga.po +907 -823
  108. data/po/gl.po +981 -865
  109. data/po/it.po +986 -868
  110. data/po/ja.po +969 -853
  111. data/po/mk.po +983 -863
  112. data/po/nb.po +979 -863
  113. data/po/nl.po +983 -864
  114. data/po/pl.po +1017 -974
  115. data/po/pt.po +988 -861
  116. data/po/pt_BR.po +984 -868
  117. data/po/ru.po +992 -873
  118. data/po/sk.po +987 -869
  119. data/po/sv.po +977 -861
  120. data/po/uk.po +975 -865
  121. data/po/zh_TW.po +976 -860
  122. data/schemas/alexandria.schemas +25 -3
  123. data/share/alexandria/glade/acquire_dialog__builder.glade +15 -12
  124. data/share/alexandria/glade/book_properties_dialog__builder.glade +171 -299
  125. data/share/alexandria/glade/main_app__builder.glade +24 -33
  126. data/share/alexandria/glade/new_book_dialog__builder.glade +27 -59
  127. data/share/alexandria/glade/preferences_dialog__builder.glade +250 -290
  128. data/share/gnome/help/alexandria/C/introduction.xml +0 -8
  129. data/share/gnome/help/alexandria/C/searching.xml +1 -1
  130. data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
  131. data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
  132. data/share/gnome/help/alexandria/fr/alexandria.xml +1 -1
  133. data/share/gnome/help/alexandria/ja/introduction.xml +0 -8
  134. data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
  135. data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
  136. data/spec/alexandria/book_providers_spec.rb +75 -171
  137. data/spec/alexandria/book_spec.rb +12 -10
  138. data/spec/alexandria/console_spec.rb +27 -0
  139. data/spec/alexandria/export_library_spec.rb +130 -0
  140. data/spec/alexandria/library_spec.rb +128 -172
  141. data/spec/alexandria/library_store_spec.rb +37 -0
  142. data/spec/alexandria/preferences_spec.rb +44 -17
  143. data/spec/alexandria/scanners/cue_cat_spec.rb +52 -0
  144. data/spec/alexandria/smart_library_spec.rb +30 -25
  145. data/spec/alexandria/ui/about_dialog_spec.rb +14 -0
  146. data/spec/alexandria/ui/acquire_dialog_spec.rb +14 -0
  147. data/spec/alexandria/ui/alert_dialog_spec.rb +16 -0
  148. data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +14 -0
  149. data/spec/alexandria/ui/book_properties_dialog_spec.rb +17 -0
  150. data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +14 -0
  151. data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +16 -0
  152. data/spec/alexandria/ui/error_dialog_spec.rb +14 -0
  153. data/spec/alexandria/ui/export_dialog_spec.rb +36 -0
  154. data/spec/alexandria/ui/icons_spec.rb +26 -0
  155. data/spec/alexandria/ui/iconview_spec.rb +7 -21
  156. data/spec/alexandria/ui/import_dialog_spec.rb +46 -0
  157. data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +17 -0
  158. data/spec/alexandria/ui/main_app_spec.rb +7 -34
  159. data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +15 -0
  160. data/spec/alexandria/ui/new_book_dialog_spec.rb +22 -0
  161. data/spec/alexandria/ui/new_provider_dialog_spec.rb +30 -0
  162. data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +39 -0
  163. data/spec/alexandria/ui/preferences_dialog_spec.rb +14 -0
  164. data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +34 -0
  165. data/spec/alexandria/ui/really_delete_dialog_spec.rb +16 -0
  166. data/spec/alexandria/ui/sidepane_manager_spec.rb +15 -0
  167. data/spec/alexandria/ui/skip_entry_dialog_spec.rb +14 -0
  168. data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +49 -0
  169. data/spec/alexandria/ui/sound_spec.rb +2 -2
  170. data/spec/alexandria/ui/ui_manager_spec.rb +43 -20
  171. data/spec/end_to_end/basic_run_spec.rb +52 -0
  172. data/spec/spec_helper.rb +65 -33
  173. data/tasks/setup.rb +2 -2
  174. data/tasks/spec.rake +16 -3
  175. data/util/rake/fileinstall.rb +39 -35
  176. data/util/rake/gettextgenerate.rb +7 -7
  177. data/util/rake/omfgenerate.rb +7 -7
  178. metadata +178 -45
  179. data/dogtail/basic_run_test.py +0 -9
  180. data/lib/alexandria/book_providers/deastore.rb +0 -265
  181. data/lib/alexandria/book_providers/mcu.rb +0 -182
  182. data/lib/alexandria/book_providers/renaud.rb +0 -149
  183. data/lib/alexandria/ui/dialogs/about_dialog.rb +0 -61
  184. data/lib/alexandria/ui/dialogs/alert_dialog.rb +0 -72
  185. data/lib/alexandria/ui/dialogs/bad_isbns_dialog.rb +0 -51
  186. data/lib/alexandria/ui/dialogs/book_properties_dialog_base.rb +0 -426
  187. data/lib/alexandria/ui/dialogs/export_dialog.rb +0 -171
  188. data/lib/alexandria/ui/dialogs/import_dialog.rb +0 -196
  189. data/lib/alexandria/ui/dialogs/misc_dialogs.rb +0 -87
  190. data/lib/alexandria/ui/dialogs/new_book_dialog_manual.rb +0 -154
  191. data/lib/alexandria/ui/dialogs/new_smart_library_dialog.rb +0 -74
  192. data/lib/alexandria/ui/dialogs/preferences_dialog.rb +0 -568
  193. data/lib/alexandria/ui/dialogs/smart_library_properties_dialog.rb +0 -59
  194. data/lib/alexandria/ui/dialogs/smart_library_properties_dialog_base.rb +0 -420
  195. data/spec/alexandria/scanners/cuecat_spec.rb +0 -67
  196. data/spec/alexandria/ui/dialogs_spec.rb +0 -96
  197. data/spec/alexandria/ui/sidepane_spec.rb +0 -29
  198. data/spec/alexandria/ui/ui_utilities_spec.rb +0 -62
  199. data/spec/alexandria/utilities_spec.rb +0 -52
  200. data/tasks/dogtail.rake +0 -6
@@ -1,48 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (C) 2004-2006 Laurent Sansonetti
4
- # Copyright (C) 2011, 2014 Matijs van Zuijlen
3
+ # This file is part of Alexandria.
5
4
  #
6
- # Alexandria is free software; you can redistribute it and/or
7
- # modify it under the terms of the GNU General Public License as
8
- # published by the Free Software Foundation; either version 2 of the
9
- # License, or (at your option) any later version.
10
- #
11
- # Alexandria is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
- # General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU General Public
17
- # License along with Alexandria; see the file COPYING. If not,
18
- # write to the Free Software Foundation, Inc., 51 Franklin Street,
19
- # Fifth Floor, Boston, MA 02110-1301 USA.
5
+ # See the file README.md for authorship and licensing information.
20
6
 
21
7
  # require 'date'
22
- require 'time'
8
+ require "time"
23
9
 
24
10
  module Alexandria
25
11
  class SmartLibrary < Array
26
12
  include Logging
27
13
  include GetText
28
14
  extend GetText
29
- bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
15
+ bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
30
16
 
31
17
  ALL_RULES = 1
32
18
  ANY_RULE = 2
33
- attr_reader :name
19
+ attr_reader :name, :n_rated
34
20
  attr_accessor :rules, :predicate_operator_rule, :deleted_books
35
21
 
36
- DIR = File.join(ENV['HOME'], '.alexandria', '.smart_libraries')
37
- EXT = '.yaml'
22
+ EXT = ".yaml"
38
23
 
39
- def initialize(name, rules, predicate_operator_rule)
24
+ def initialize(name, rules, predicate_operator_rule, store = nil)
40
25
  super()
41
26
  raise if name.nil? || rules.nil? || predicate_operator_rule.nil?
42
- @name = name.dup.force_encoding('UTF-8')
27
+
28
+ @name = name.dup.force_encoding("UTF-8")
43
29
  @rules = rules
44
30
  @predicate_operator_rule = predicate_operator_rule
45
- libraries = Libraries.instance
31
+ @store = store
32
+ libraries = LibraryCollection.instance
46
33
  libraries.add_observer(self)
47
34
  self.libraries = libraries.all_regular_libraries
48
35
  # carry deleted books over from libraries that are part of the smart library
@@ -50,39 +37,7 @@ module Alexandria
50
37
  @cache = {}
51
38
  end
52
39
 
53
- def self.loadall
54
- a = []
55
- begin
56
- # Deserialize smart libraries.
57
- Dir.chdir(DIR) do
58
- Dir['*' + EXT].each do |filename|
59
- # Skip non-regular files.
60
- next unless File.stat(filename).file?
61
-
62
- text = IO.read(filename)
63
- hash = YAML.safe_load(text, whitelist_classes = [Symbol])
64
- begin
65
- smart_library = from_hash(hash)
66
- a << smart_library
67
- rescue => e
68
- puts "Cannot load serialized smart library: #{e}"
69
- puts e.backtrace
70
- end
71
- end
72
- end
73
- rescue Errno::ENOENT
74
- # First run and no smart libraries yet? Provide some default
75
- # ones.
76
- sample_smart_libraries.each do |smart_library|
77
- smart_library.save
78
- a << smart_library
79
- end
80
- end
81
- a.each(&:refilter)
82
- a
83
- end
84
-
85
- def self.sample_smart_libraries
40
+ def self.sample_smart_libraries(store)
86
41
  a = []
87
42
 
88
43
  operands = Rule::Operands::LEFT
@@ -91,25 +46,25 @@ module Alexandria
91
46
  rule = Rule.new(operands.find { |x| x.book_selector == :rating },
92
47
  Rule::Operators::IS,
93
48
  Book::MAX_RATING_STARS.to_s)
94
- a << new(_('Favorite'), [rule], ALL_RULES)
49
+ a << new(_("Favorite"), [rule], ALL_RULES, store)
95
50
 
96
51
  # Loaned books.
97
52
  rule = Rule.new(operands.find { |x| x.book_selector == :loaned },
98
53
  Rule::Operators::IS_TRUE,
99
54
  nil)
100
- a << new(_('Loaned'), [rule], ALL_RULES)
55
+ a << new(_("Loaned"), [rule], ALL_RULES, store)
101
56
 
102
57
  # Redd books.
103
58
  rule = Rule.new(operands.find { |x| x.book_selector == :redd },
104
59
  Rule::Operators::IS_TRUE,
105
60
  nil)
106
- a << new(_('Read'), [rule], ALL_RULES)
61
+ a << new(_("Read"), [rule], ALL_RULES, store)
107
62
 
108
63
  # Own books.
109
64
  rule = Rule.new(operands.find { |x| x.book_selector == :own },
110
65
  Rule::Operators::IS_TRUE,
111
66
  nil)
112
- a << new(_('Owned'), [rule], ALL_RULES)
67
+ a << new(_("Owned"), [rule], ALL_RULES, store)
113
68
 
114
69
  # Want books.
115
70
  rule = Rule.new(operands.find { |x| x.book_selector == :want },
@@ -118,15 +73,16 @@ module Alexandria
118
73
  rule2 = Rule.new(operands.find { |x| x.book_selector == :own },
119
74
  Rule::Operators::IS_NOT_TRUE,
120
75
  nil)
121
- a << new(_('Wishlist'), [rule, rule2], ALL_RULES)
76
+ a << new(_("Wishlist"), [rule, rule2], ALL_RULES, store)
122
77
 
123
78
  a
124
79
  end
125
80
 
126
- def self.from_hash(hash)
81
+ def self.from_hash(hash, store)
127
82
  SmartLibrary.new(hash[:name],
128
83
  hash[:rules].map { |x| Rule.from_hash(x) },
129
- hash[:predicate_operator_rule] == :all ? ALL_RULES : ANY_RULE)
84
+ hash[:predicate_operator_rule] == :all ? ALL_RULES : ANY_RULE,
85
+ store)
130
86
  end
131
87
 
132
88
  def to_hash
@@ -138,22 +94,23 @@ module Alexandria
138
94
  end
139
95
 
140
96
  def name=(new_name)
141
- if @name != new_name
142
- old_yaml = yaml
143
- @name = new_name
144
- FileUtils.mv(old_yaml, yaml)
145
- save
146
- end
97
+ return unless @name != new_name
98
+
99
+ old_yaml = yaml
100
+ @name = new_name
101
+ FileUtils.mv(old_yaml, yaml)
102
+ save
147
103
  end
148
104
 
149
105
  def update(*params)
150
- if params.first.is_a?(Libraries)
106
+ case params.first
107
+ when LibraryCollection
151
108
  libraries, _, library = params
152
109
  unless library.is_a?(self.class)
153
110
  self.libraries = libraries.all_libraries
154
111
  refilter
155
112
  end
156
- elsif params.first.is_a?(Library)
113
+ when Library
157
114
  refilter
158
115
  end
159
116
  end
@@ -183,7 +140,7 @@ module Alexandria
183
140
  if book
184
141
  @cache[book].yaml(book)
185
142
  else
186
- File.join(DIR, @name + EXT)
143
+ File.join(base_dir, @name + EXT)
187
144
  end
188
145
  end
189
146
 
@@ -191,8 +148,8 @@ module Alexandria
191
148
  if book
192
149
  @cache[book].save(book)
193
150
  else
194
- FileUtils.mkdir_p(DIR) unless File.exist? DIR
195
- File.open(yaml, 'w') { |io| io.puts to_hash.to_yaml }
151
+ FileUtils.mkdir_p(base_dir) unless File.exist? base_dir
152
+ File.open(yaml, "w") { |io| io.puts to_hash.to_yaml }
196
153
  end
197
154
  end
198
155
 
@@ -210,19 +167,18 @@ module Alexandria
210
167
  each do |book|
211
168
  library = @cache[book]
212
169
  next unless File.exist?(library.cover(book))
170
+
213
171
  FileUtils.cp(File.join(library.path, book.ident + Library::EXT[:cover]),
214
172
  File.join(somewhere, library.final_cover(book)))
215
173
  end
216
174
  end
217
175
 
218
- attr_reader :n_rated
219
-
220
176
  def n_unrated
221
177
  length - n_rated
222
178
  end
223
179
 
224
- def ==(object)
225
- object.is_a?(self.class) && object.name == name
180
+ def ==(other)
181
+ other.is_a?(self.class) && other.name == name
226
182
  end
227
183
 
228
184
  @@deleted_libraries = []
@@ -233,15 +189,16 @@ module Alexandria
233
189
 
234
190
  def self.really_delete_deleted_libraries
235
191
  @@deleted_libraries.each do |library|
236
- puts "Deleting smart library file (#{yaml})" if $DEBUG
192
+ log.debug { "Deleting smart library file (#{yaml})" }
237
193
  FileUtils.rm_rf(library.yaml)
238
194
  end
239
195
  end
240
196
 
241
197
  def delete
242
198
  if @@deleted_libraries.include?(self)
243
- puts 'Already deleted a SmartLibrary with this name'
244
- puts '(this might mess up undeletes...)'
199
+ log.info do
200
+ "Already deleted a SmartLibrary with this name (this might mess up undeletes)"
201
+ end
245
202
  FileUtils.rm_rf(yaml)
246
203
  # so we just delete the old smart library, and
247
204
  # 'pending' delete the new one of the same name...
@@ -256,6 +213,7 @@ module Alexandria
256
213
 
257
214
  def undelete
258
215
  raise unless @@deleted_libraries.include?(self)
216
+
259
217
  @@deleted_libraries.delete(self)
260
218
  end
261
219
 
@@ -268,15 +226,20 @@ module Alexandria
268
226
  @libraries.each { |x| x.add_observer(self) }
269
227
  end
270
228
 
229
+ def base_dir
230
+ @store.smart_library_dir
231
+ end
232
+
271
233
  class Rule
272
234
  include GetText
273
235
  extend GetText
274
- bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
236
+ bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
275
237
 
276
238
  attr_accessor :operand, :operation, :value
277
239
 
278
240
  def initialize(operand, operation, value)
279
241
  raise if operand.nil? || operation.nil? # value can be nil
242
+
280
243
  @operand = operand
281
244
  @operation = operation
282
245
  @value = value
@@ -300,9 +263,10 @@ module Alexandria
300
263
  }
301
264
  end
302
265
 
303
- class Operand < Struct.new(:name, :klass)
304
- def <=>(x)
305
- name <=> x.name
266
+ Operand = Struct.new(:name, :klass)
267
+ class Operand
268
+ def <=>(other)
269
+ name <=> other.name
306
270
  end
307
271
  end
308
272
 
@@ -315,124 +279,127 @@ module Alexandria
315
279
  end
316
280
  end
317
281
 
318
- class Operator < Struct.new(:sym, :name, :proc)
319
- def <=>(x)
320
- name <=> x.name
282
+ Operator = Struct.new(:sym, :name, :proc)
283
+ class Operator
284
+ def <=>(other)
285
+ name <=> other.name
321
286
  end
322
287
  end
323
288
 
324
289
  module Operands
325
290
  include GetText
326
291
  extend GetText
327
- bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
292
+ bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
328
293
 
329
294
  LEFT = [
330
- LeftOperand.new(:title, _('Title'), String),
331
- LeftOperand.new(:isbn, _('ISBN'), String),
332
- LeftOperand.new(:authors, _('Authors'), String),
333
- LeftOperand.new(:publisher, _('Publisher'), String),
334
- LeftOperand.new(:publishing_year, _('Publish Year'), Integer),
335
- LeftOperand.new(:edition, _('Binding'), String),
336
- LeftOperand.new(:rating, _('Rating'), Integer),
337
- LeftOperand.new(:notes, _('Notes'), String),
338
- LeftOperand.new(:tags, _('Tags'), Array),
339
- LeftOperand.new(:loaned, _('Loaning State'), TrueClass),
340
- LeftOperand.new(:loaned_since, _('Loaning Date'), Time),
341
- LeftOperand.new(:loaned_to, _('Loaning Person'), String),
342
- LeftOperand.new(:redd, _('Read'), TrueClass),
343
- LeftOperand.new(:redd_when, _('Date Read'), Time),
344
- LeftOperand.new(:own, _('Own'), TrueClass),
345
- LeftOperand.new(:want, _('Want'), TrueClass),
295
+ LeftOperand.new(:title, _("Title"), String),
296
+ LeftOperand.new(:isbn, _("ISBN"), String),
297
+ LeftOperand.new(:authors, _("Authors"), String),
298
+ LeftOperand.new(:publisher, _("Publisher"), String),
299
+ LeftOperand.new(:publishing_year, _("Publish Year"), Integer),
300
+ LeftOperand.new(:edition, _("Binding"), String),
301
+ LeftOperand.new(:rating, _("Rating"), Integer),
302
+ LeftOperand.new(:notes, _("Notes"), String),
303
+ LeftOperand.new(:tags, _("Tags"), Array),
304
+ LeftOperand.new(:loaned, _("Loaning State"), TrueClass),
305
+ LeftOperand.new(:loaned_since, _("Loaning Date"), Time),
306
+ LeftOperand.new(:loaned_to, _("Loaning Person"), String),
307
+ LeftOperand.new(:redd, _("Read"), TrueClass),
308
+ LeftOperand.new(:redd_when, _("Date Read"), Time),
309
+ LeftOperand.new(:own, _("Own"), TrueClass),
310
+ LeftOperand.new(:want, _("Want"), TrueClass),
346
311
  ].sort
347
312
 
348
313
  STRING = Operand.new(nil, String)
349
314
  STRING_ARRAY = Operand.new(nil, String)
350
315
  INTEGER = Operand.new(nil, Integer)
351
316
  TIME = Operand.new(nil, Time)
352
- DAYS = Operand.new(_('days'), Integer)
317
+ DAYS = Operand.new(_("days"), Integer)
353
318
  end
354
319
 
355
320
  module Operators
356
321
  include Logging
357
322
  include GetText
358
323
  extend GetText
359
- bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
324
+ bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
360
325
 
361
326
  IS_TRUE = Operator.new(:is_true,
362
- _('is set'),
327
+ _("is set"),
363
328
  proc { |x| x })
364
329
  IS_NOT_TRUE = Operator.new(:is_not_true,
365
- _('is not set'),
330
+ _("is not set"),
366
331
  proc { |x| !x })
367
332
  IS = Operator.new(:is,
368
- _('is'),
333
+ _("is"),
369
334
  proc { |x, y| x == y })
370
335
  IS_NOT = Operator.new(:is_not,
371
- _('is not'),
336
+ _("is not"),
372
337
  proc { |x, y| x != y })
373
338
  CONTAINS = Operator.new(:contains,
374
- _('contains'),
339
+ _("contains"),
375
340
  proc { |x, y| x.include?(y) })
376
341
  DOES_NOT_CONTAIN = Operator.new(:does_not_contain,
377
- _('does not contain'),
342
+ _("does not contain"),
378
343
  proc { |x, y| !x.include?(y) })
379
344
  STARTS_WITH = Operator.new(:starts_with,
380
- _('starts with'),
345
+ _("starts with"),
381
346
  proc { |x, y| /^#{y}/.match(x) })
382
347
  ENDS_WITH = Operator.new(:ends_with,
383
- _('ends with'),
348
+ _("ends with"),
384
349
  proc { |x, y| /#{y}$/.match(x) })
385
350
  IS_GREATER_THAN = Operator.new(:is_greater_than,
386
- _('is greater than'),
351
+ _("is greater than"),
387
352
  proc { |x, y| x > y })
388
353
  IS_LESS_THAN = Operator.new(:is_less_than,
389
- _('is less than'),
354
+ _("is less than"),
390
355
  proc { |x, y| x < y })
391
356
  IS_AFTER = Operator.new(:is_after,
392
- _('is after'),
357
+ _("is after"),
393
358
  proc { |x, y| x.to_i > y.to_i && !x.nil? })
394
359
  IS_BEFORE = Operator.new(:is_before,
395
- _('is before'),
360
+ _("is before"),
396
361
  proc { |x, y| x.to_i < y.to_i && !x.nil? })
397
- IS_IN_LAST = Operator.new(:is_in_last_days,
398
- _('is in last'),
399
- proc { |x, y|
400
- begin
401
- if x.nil? || x.empty?
402
- false
403
- else
404
- log.debug { "Given Date: #{x.inspect} #{x.class}" }
405
- given_date = Time.parse(x)
406
- days = y.to_i * (24 * 60 * 60)
407
-
408
- Time.now - given_date <= days
409
- end
410
- rescue => ex
411
- trace = ex.backtrace.join("\n >")
412
- log.warn { "Date matching failed #{ex} #{trace}" }
413
- false
414
- end
415
- })
416
- IS_NOT_IN_LAST = Operator.new(:is_not_in_last_days,
417
- _('is not in last'),
418
- proc { |x, y|
419
- begin
420
- if x.nil? || x.empty?
421
- false
422
- else
423
- log.debug { "Given Date: #{x.inspect} #{x.class}" }
424
- given_date = Time.parse(x)
425
- days = y.to_i * (24 * 60 * 60)
426
-
427
- Time.now - given_date > days
428
- end
429
- rescue => ex
430
- trace = ex.backtrace.join("\n >")
431
- log.warn { "Date matching failed #{ex} #{trace}" }
432
- false
433
- end
434
- # Time.now - x > 3600*24*y
435
- })
362
+ IS_IN_LAST =
363
+ Operator.new(:is_in_last_days,
364
+ _("is in last"),
365
+ proc { |x, y|
366
+ begin
367
+ if x.nil? || x.empty?
368
+ false
369
+ else
370
+ log.debug { "Given Date: #{x.inspect} #{x.class}" }
371
+ given_date = Time.parse(x)
372
+ days = y.to_i * (24 * 60 * 60)
373
+
374
+ Time.now - given_date <= days
375
+ end
376
+ rescue StandardError => ex
377
+ trace = ex.backtrace.join("\n >")
378
+ log.warn { "Date matching failed #{ex} #{trace}" }
379
+ false
380
+ end
381
+ })
382
+ IS_NOT_IN_LAST =
383
+ Operator.new(:is_not_in_last_days,
384
+ _("is not in last"),
385
+ proc { |x, y|
386
+ begin
387
+ if x.nil? || x.empty?
388
+ false
389
+ else
390
+ log.debug { "Given Date: #{x.inspect} #{x.class}" }
391
+ given_date = Time.parse(x)
392
+ days = y.to_i * (24 * 60 * 60)
393
+
394
+ Time.now - given_date > days
395
+ end
396
+ rescue StandardError => ex
397
+ trace = ex.backtrace.join("\n >")
398
+ log.warn { "Date matching failed #{ex} #{trace}" }
399
+ false
400
+ end
401
+ # Time.now - x > 3600*24*y
402
+ })
436
403
 
437
404
  ALL = constants.map \
438
405
  { |x| module_eval(x.to_s) }.select \
@@ -476,15 +443,15 @@ module Alexandria
476
443
 
477
444
  def self.operations_for_operand(operand)
478
445
  case operand.klass.name
479
- when 'String'
446
+ when "String"
480
447
  STRING_OPERATORS.map { |x| [x, Operands::STRING] }
481
- when 'Array'
448
+ when "Array"
482
449
  STRING_ARRAY_OPERATORS.map { |x| [x, Operands::STRING] }
483
- when 'Integer'
450
+ when "Integer"
484
451
  INTEGER_OPERATORS.map { |x| [x, Operands::INTEGER] }
485
- when 'TrueClass'
452
+ when "TrueClass"
486
453
  BOOLEAN_OPERATORS.map { |x| [x, nil] }
487
- when 'Time'
454
+ when "Time"
488
455
  TIME_OPERATORS.map do |x|
489
456
  if (x == Operators::IS_IN_LAST) ||
490
457
  (x == Operators::IS_NOT_IN_LAST)
@@ -495,17 +462,13 @@ module Alexandria
495
462
  end
496
463
  end
497
464
  else
498
- raise "invalid operand klass #{operand.klass}"
465
+ raise format(_("invalid operand klass %<klass>s"), klass: operand.klass)
499
466
  end
500
467
  end
501
468
 
502
469
  def filter_proc
503
470
  proc do |book|
504
- begin
505
- left_value = book.send(@operand.book_selector)
506
- rescue => e
507
- puts e.message
508
- end
471
+ left_value = book.send(@operand.book_selector)
509
472
  right_value = @value
510
473
  if right_value.is_a?(String)
511
474
  left_value = left_value.to_s.downcase