alexandria-book-collection-manager 0.7.1 → 0.7.6

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