alexandria-book-collection-manager 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +28 -25
  3. data/.rubocop_todo.yml +87 -67
  4. data/CHANGELOG.md +12 -1
  5. data/Gemfile +4 -3
  6. data/README.md +16 -6
  7. data/Rakefile +71 -72
  8. data/alexandria-book-collection-manager.gemspec +44 -44
  9. data/bin/alexandria +12 -12
  10. data/lib/alexandria.rb +22 -22
  11. data/lib/alexandria/about.rb +50 -50
  12. data/lib/alexandria/book_providers.rb +50 -50
  13. data/lib/alexandria/book_providers/adlibris.rb +28 -44
  14. data/lib/alexandria/book_providers/amazon_aws.rb +64 -64
  15. data/lib/alexandria/book_providers/amazon_ecs_util.rb +52 -78
  16. data/lib/alexandria/book_providers/barnes_and_noble.rb +34 -34
  17. data/lib/alexandria/book_providers/douban.rb +21 -37
  18. data/lib/alexandria/book_providers/proxis.rb +24 -24
  19. data/lib/alexandria/book_providers/pseudomarc.rb +19 -19
  20. data/lib/alexandria/book_providers/renaud.rb +44 -57
  21. data/lib/alexandria/book_providers/siciliano.rb +39 -39
  22. data/lib/alexandria/book_providers/thalia.rb +33 -33
  23. data/lib/alexandria/book_providers/web.rb +5 -5
  24. data/lib/alexandria/book_providers/worldcat.rb +44 -69
  25. data/lib/alexandria/book_providers/z3950.rb +94 -109
  26. data/lib/alexandria/config.rb +1 -1
  27. data/lib/alexandria/console.rb +3 -3
  28. data/lib/alexandria/export_format.rb +8 -8
  29. data/lib/alexandria/export_library.rb +112 -113
  30. data/lib/alexandria/import_library.rb +45 -45
  31. data/lib/alexandria/import_library_csv.rb +30 -30
  32. data/lib/alexandria/library_collection.rb +4 -4
  33. data/lib/alexandria/library_sort_order.rb +1 -1
  34. data/lib/alexandria/library_store.rb +14 -14
  35. data/lib/alexandria/logging.rb +5 -5
  36. data/lib/alexandria/models/book.rb +1 -1
  37. data/lib/alexandria/models/library.rb +36 -36
  38. data/lib/alexandria/net.rb +5 -5
  39. data/lib/alexandria/preferences.rb +32 -32
  40. data/lib/alexandria/scanners/{cuecat.rb → cue_cat.rb} +13 -13
  41. data/lib/alexandria/scanners/keyboard.rb +5 -5
  42. data/lib/alexandria/smart_library.rb +53 -53
  43. data/lib/alexandria/ui.rb +15 -15
  44. data/lib/alexandria/ui/{dialogs/about_dialog.rb → about_dialog.rb} +1 -1
  45. data/lib/alexandria/ui/{dialogs/acquire_dialog.rb → acquire_dialog.rb} +66 -65
  46. data/lib/alexandria/ui/{dialogs/alert_dialog.rb → alert_dialog.rb} +1 -16
  47. data/lib/alexandria/ui/{dialogs/bad_isbns_dialog.rb → bad_isbns_dialog.rb} +0 -0
  48. data/lib/alexandria/ui/{dialogs/barcode_animation.rb → barcode_animation.rb} +7 -7
  49. data/lib/alexandria/ui/{dialogs/book_properties_dialog.rb → book_properties_dialog.rb} +25 -37
  50. data/lib/alexandria/ui/{dialogs/book_properties_dialog_base.rb → book_properties_dialog_base.rb} +38 -37
  51. data/lib/alexandria/ui/builder_base.rb +1 -1
  52. data/lib/alexandria/ui/callbacks.rb +95 -91
  53. data/lib/alexandria/ui/completion_models.rb +7 -21
  54. data/lib/alexandria/ui/confirm_erase_dialog.rb +33 -0
  55. data/lib/alexandria/ui/conflict_while_copying_dialog.rb +34 -0
  56. data/lib/alexandria/ui/dndable.rb +7 -7
  57. data/lib/alexandria/ui/error_dialog.rb +25 -0
  58. data/lib/alexandria/ui/{dialogs/export_dialog.rb → export_dialog.rb} +22 -42
  59. data/lib/alexandria/ui/icons.rb +6 -6
  60. data/lib/alexandria/ui/iconview.rb +7 -7
  61. data/lib/alexandria/ui/iconview_tooltips.rb +6 -6
  62. data/lib/alexandria/ui/{dialogs/import_dialog.rb → import_dialog.rb} +14 -32
  63. data/lib/alexandria/ui/init.rb +16 -29
  64. data/lib/alexandria/ui/{dialogs/keep_bad_isbn_dialog.rb → keep_bad_isbn_dialog.rb} +6 -4
  65. data/lib/alexandria/ui/libraries_combo.rb +7 -7
  66. data/lib/alexandria/ui/listview.rb +40 -40
  67. data/lib/alexandria/ui/main_app.rb +22 -24
  68. data/lib/alexandria/ui/misc_dialogs.rb +10 -0
  69. data/lib/alexandria/ui/multi_drag_treeview.rb +4 -4
  70. data/lib/alexandria/ui/{dialogs/new_book_dialog.rb → new_book_dialog.rb} +46 -45
  71. data/lib/alexandria/ui/{dialogs/new_book_dialog_manual.rb → new_book_dialog_manual.rb} +20 -19
  72. data/lib/alexandria/ui/new_provider_dialog.rb +99 -0
  73. data/lib/alexandria/ui/{dialogs/new_smart_library_dialog.rb → new_smart_library_dialog.rb} +4 -4
  74. data/lib/alexandria/ui/{dialogs/preferences_dialog.rb → preferences_dialog.rb} +44 -235
  75. data/lib/alexandria/ui/provider_preferences_base_dialog.rb +90 -0
  76. data/lib/alexandria/ui/provider_preferences_dialog.rb +35 -0
  77. data/lib/alexandria/ui/{dialogs/misc_dialogs.rb → really_delete_dialog.rb} +6 -27
  78. data/lib/alexandria/ui/{sidepane.rb → sidepane_manager.rb} +27 -25
  79. data/lib/alexandria/ui/skip_entry_dialog.rb +32 -0
  80. data/lib/alexandria/ui/{dialogs/smart_library_properties_dialog.rb → smart_library_properties_dialog.rb} +2 -2
  81. data/lib/alexandria/ui/{dialogs/smart_library_properties_dialog_base.rb → smart_library_properties_dialog_base.rb} +30 -30
  82. data/lib/alexandria/ui/sound.rb +8 -8
  83. data/lib/alexandria/ui/ui_manager.rb +136 -135
  84. data/lib/alexandria/version.rb +4 -19
  85. data/lib/alexandria/web_themes.rb +8 -8
  86. data/po/cs.po +97 -97
  87. data/po/cy.po +97 -97
  88. data/po/de.po +97 -97
  89. data/po/el.po +97 -97
  90. data/po/es.po +97 -97
  91. data/po/fr.po +97 -97
  92. data/po/ga.po +97 -97
  93. data/po/gl.po +97 -97
  94. data/po/it.po +97 -97
  95. data/po/ja.po +97 -97
  96. data/po/mk.po +97 -97
  97. data/po/nb.po +97 -97
  98. data/po/nl.po +97 -97
  99. data/po/pl.po +97 -97
  100. data/po/pt.po +97 -97
  101. data/po/pt_BR.po +97 -97
  102. data/po/ru.po +97 -97
  103. data/po/sk.po +97 -97
  104. data/po/sv.po +97 -97
  105. data/po/uk.po +97 -97
  106. data/po/zh_TW.po +97 -97
  107. data/schemas/alexandria.schemas +24 -2
  108. data/spec/alexandria/book_providers_spec.rb +65 -82
  109. data/spec/alexandria/book_spec.rb +12 -10
  110. data/spec/alexandria/console_spec.rb +9 -9
  111. data/spec/alexandria/export_library_spec.rb +31 -31
  112. data/spec/alexandria/library_spec.rb +86 -86
  113. data/spec/alexandria/library_store_spec.rb +8 -8
  114. data/spec/alexandria/preferences_spec.rb +18 -17
  115. data/spec/alexandria/scanners/cue_cat_spec.rb +52 -0
  116. data/spec/alexandria/smart_library_spec.rb +15 -15
  117. data/spec/alexandria/ui/about_dialog_spec.rb +14 -0
  118. data/spec/alexandria/ui/acquire_dialog_spec.rb +14 -0
  119. data/spec/alexandria/ui/alert_dialog_spec.rb +16 -0
  120. data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +14 -0
  121. data/spec/alexandria/ui/book_properties_dialog_spec.rb +17 -0
  122. data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +14 -0
  123. data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +16 -0
  124. data/spec/alexandria/ui/error_dialog_spec.rb +14 -0
  125. data/spec/alexandria/ui/export_dialog_spec.rb +15 -0
  126. data/spec/alexandria/ui/iconview_spec.rb +7 -21
  127. data/spec/alexandria/ui/import_dialog_spec.rb +14 -0
  128. data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +17 -0
  129. data/spec/alexandria/ui/main_app_spec.rb +6 -6
  130. data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +15 -0
  131. data/spec/alexandria/ui/{dialogs/new_book_dialog_spec.rb → new_book_dialog_spec.rb} +4 -4
  132. data/spec/alexandria/ui/new_provider_dialog_spec.rb +14 -0
  133. data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +14 -0
  134. data/spec/alexandria/ui/preferences_dialog_spec.rb +14 -0
  135. data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +19 -0
  136. data/spec/alexandria/ui/really_delete_dialog_spec.rb +15 -0
  137. data/spec/alexandria/ui/sidepane_manager_spec.rb +15 -0
  138. data/spec/alexandria/ui/skip_entry_dialog_spec.rb +14 -0
  139. data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +18 -0
  140. data/spec/alexandria/ui/sound_spec.rb +2 -2
  141. data/spec/alexandria/ui/ui_manager_spec.rb +6 -20
  142. data/spec/alexandria/ui/ui_utilities_spec.rb +9 -9
  143. data/spec/alexandria/utilities_spec.rb +6 -6
  144. data/spec/end_to_end/basic_run_spec.rb +24 -36
  145. data/spec/spec_helper.rb +9 -9
  146. data/tasks/dogtail.rake +1 -1
  147. data/tasks/setup.rb +2 -2
  148. data/tasks/spec.rake +11 -11
  149. data/util/rake/fileinstall.rb +25 -25
  150. data/util/rake/gettextgenerate.rb +7 -7
  151. data/util/rake/omfgenerate.rb +7 -7
  152. metadata +59 -33
  153. data/spec/alexandria/scanners/cuecat_spec.rb +0 -67
  154. data/spec/alexandria/ui/dialogs_spec.rb +0 -162
  155. data/spec/alexandria/ui/sidepane_spec.rb +0 -29
@@ -21,45 +21,45 @@
21
21
 
22
22
  # http://en.wikipedia.org/wiki/Amazon
23
23
 
24
- require 'hpricot'
25
- require 'alexandria/book_providers/amazon_ecs_util'
24
+ require "hpricot"
25
+ require "alexandria/book_providers/amazon_ecs_util"
26
26
 
27
27
  module Alexandria
28
28
  class BookProviders
29
29
  class AmazonProvider < GenericProvider
30
30
  include Logging
31
31
  include GetText
32
- GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
32
+ GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
33
33
 
34
34
  # CACHE_DIR = File.join(Alexandria::Library::DIR, '.amazon_cache')
35
35
 
36
- LOCALES = ['ca', 'de', 'fr', 'jp', 'uk', 'us'].freeze
36
+ LOCALES = ["ca", "de", "fr", "jp", "uk", "us"].freeze
37
37
 
38
38
  def initialize
39
- super('Amazon', 'Amazon')
39
+ super("Amazon", "Amazon")
40
40
  # prefs.add("enabled", _("Enabled"), true, [true,false])
41
- prefs.add('locale', _('Locale'), 'us', AmazonProvider::LOCALES)
42
- prefs.add('dev_token', _('Access key ID'), '')
43
- prefs.add('secret_key', _('Secret access key'), '')
44
- prefs.add('associate_tag', _('Associate Tag'), '')
41
+ prefs.add("locale", _("Locale"), "us", AmazonProvider::LOCALES)
42
+ prefs.add("dev_token", _("Access key ID"), "")
43
+ prefs.add("secret_key", _("Secret access key"), "")
44
+ prefs.add("associate_tag", _("Associate Tag"), "")
45
45
 
46
46
  prefs.read
47
- token = prefs.variable_named('dev_token')
47
+ token = prefs.variable_named("dev_token")
48
48
  # kill old (shorter) tokens, or previously distributed Access Key Id (see #26250)
49
49
 
50
50
  if token
51
51
  token.new_value = token.value.strip if token.value != token.value.strip
52
52
  end
53
- token.new_value = '' if token && ((token.value.size != 20) || (token.value == '0J356Z09CN88KB743582'))
53
+ token.new_value = "" if token && ((token.value.size != 20) || (token.value == "0J356Z09CN88KB743582"))
54
54
 
55
- secret = prefs.variable_named('secret_key')
55
+ secret = prefs.variable_named("secret_key")
56
56
  if secret
57
57
  secret.new_value = secret.value.strip if secret.value != secret.value.strip
58
58
  end
59
59
 
60
- associate = prefs.variable_named('associate_tag')
60
+ associate = prefs.variable_named("associate_tag")
61
61
  if associate
62
- associate.new_value = 'rubyalexa-20' if associate.value.strip.empty?
62
+ associate.new_value = "rubyalexa-20" if associate.value.strip.empty?
63
63
  associate.new_value = associate.value.strip if associate.value != associate.value.strip
64
64
  end
65
65
  end
@@ -67,29 +67,29 @@ module Alexandria
67
67
  def search(criterion, type)
68
68
  prefs.read
69
69
 
70
- if prefs['secret_key'].empty?
70
+ if prefs["secret_key"].empty?
71
71
  raise(Amazon::RequestError,
72
- 'Secret Access Key required for Authentication:' \
73
- ' you must sign up for your own Amazon AWS account')
72
+ "Secret Access Key required for Authentication:" \
73
+ " you must sign up for your own Amazon AWS account")
74
74
  end
75
75
 
76
76
  if (config = Alexandria::Preferences.instance.http_proxy_config)
77
77
  host, port, user, pass = config
78
- url = 'http://'
79
- url += user + ':' + pass + '@' if user && pass
80
- url += host + ':' + port.to_s
81
- ENV['http_proxy'] = url
78
+ url = "http://"
79
+ url += user + ":" + pass + "@" if user && pass
80
+ url += host + ":" + port.to_s
81
+ ENV["http_proxy"] = url
82
82
  end
83
83
 
84
- access_key_id = prefs['dev_token']
84
+ access_key_id = prefs["dev_token"]
85
85
 
86
86
  Amazon::Ecs.options = { aWS_access_key_id: access_key_id,
87
- associateTag: prefs['associate_tag'] }
88
- Amazon::Ecs.secret_access_key = prefs['secret_key']
87
+ associateTag: prefs["associate_tag"] }
88
+ Amazon::Ecs.secret_access_key = prefs["secret_key"]
89
89
  # #req.cache = Amazon::Search::Cache.new(CACHE_DIR)
90
90
  locales = AmazonProvider::LOCALES.dup
91
- locales.delete prefs['locale']
92
- locales.unshift prefs['locale']
91
+ locales.delete prefs["locale"]
92
+ locales.unshift prefs["locale"]
93
93
  locales.reverse!
94
94
 
95
95
  begin
@@ -99,7 +99,7 @@ module Alexandria
99
99
  when SEARCH_BY_ISBN
100
100
  criterion = Library.canonicalise_isbn(criterion)
101
101
  # This isn't ideal : I'd like to do an ISBN/EAN-specific search
102
- res = Amazon::Ecs.item_search(criterion, response_group: 'ItemAttributes,Images',
102
+ res = Amazon::Ecs.item_search(criterion, response_group: "ItemAttributes,Images",
103
103
  country: request_locale)
104
104
  res.items.each do |item|
105
105
  products << item
@@ -120,27 +120,27 @@ module Alexandria
120
120
  # result with different ISBNs
121
121
 
122
122
  if products.length > 1
123
- log.warn {
123
+ log.warn do
124
124
  "ISBN search at Amazon[#{request_locale}] got #{products.length} results;" \
125
- ' returning the first result only'
126
- }
125
+ " returning the first result only"
126
+ end
127
127
  end
128
128
 
129
129
  when SEARCH_BY_TITLE
130
130
  res = Amazon::Ecs.item_search(criterion,
131
- response_group: 'ItemAttributes,Images',
131
+ response_group: "ItemAttributes,Images",
132
132
  country: request_locale)
133
133
 
134
134
  res.items.each do |item|
135
- products << item if item.get('itemattributes/title') =~ /#{criterion}/i
135
+ products << item if /#{criterion}/i.match?(item.get("itemattributes/title"))
136
136
  end
137
137
  # #req.keyword_search(criterion) do |product|
138
138
 
139
139
  when SEARCH_BY_AUTHORS
140
140
  criterion = "author:#{criterion}"
141
141
  res = Amazon::Ecs.item_search(criterion,
142
- response_group: 'ItemAttributes,Images',
143
- country: request_locale, type: 'Power')
142
+ response_group: "ItemAttributes,Images",
143
+ country: request_locale, type: "Power")
144
144
  res.items.each do |item|
145
145
  products << item
146
146
  end
@@ -148,7 +148,7 @@ module Alexandria
148
148
 
149
149
  when SEARCH_BY_KEYWORD
150
150
  res = Amazon::Ecs.item_search(criterion,
151
- response_group: 'ItemAttributes,Images',
151
+ response_group: "ItemAttributes,Images",
152
152
  country: request_locale)
153
153
 
154
154
  res.items.each do |item|
@@ -158,37 +158,37 @@ module Alexandria
158
158
  else
159
159
  raise InvalidSearchTypeError
160
160
  end
161
- raise Amazon::RequestError, 'No products' if products.empty?
161
+ raise Amazon::RequestError, "No products" if products.empty?
162
162
  # raise NoResultsError if products.empty?
163
- rescue Amazon::RequestError => re
164
- log.debug { "Got Amazon::RequestError at #{request_locale}: #{re}" }
163
+ rescue Amazon::RequestError => ex
164
+ log.debug { "Got Amazon::RequestError at #{request_locale}: #{ex}" }
165
165
  retry unless locales.empty?
166
166
  raise NoResultsError
167
167
  end
168
168
 
169
169
  results = []
170
170
  products.each do |item|
171
- next unless item.get('itemattributes/productgroup') == 'Book'
171
+ next unless item.get("itemattributes/productgroup") == "Book"
172
172
 
173
- atts = item.search_and_convert('itemattributes')
174
- title = normalize(atts.get('title'))
173
+ atts = item.search_and_convert("itemattributes")
174
+ title = normalize(atts.get("title"))
175
175
 
176
- media = normalize(atts.get('binding'))
177
- media = nil if media == 'Unknown Binding'
176
+ media = normalize(atts.get("binding"))
177
+ media = nil if media == "Unknown Binding"
178
178
 
179
- isbn = normalize(atts.get('isbn'))
179
+ isbn = normalize(atts.get("isbn"))
180
180
  isbn = (Library.canonicalise_ean(isbn) if isbn && Library.valid_isbn?(isbn))
181
181
  # hack, extract year by regexp (not Y10K compatible :-)
182
- /([1-9][0-9]{3})/ =~ atts.get('publicationdate')
182
+ /([1-9][0-9]{3})/ =~ atts.get("publicationdate")
183
183
  publishing_year = Regexp.last_match[1] ? Regexp.last_match[1].to_i : nil
184
184
  book = Book.new(title,
185
- atts.get_array('author').map { |x| normalize(x) },
185
+ atts.get_array("author").map { |x| normalize(x) },
186
186
  isbn,
187
- normalize(atts.get('manufacturer')),
187
+ normalize(atts.get("manufacturer")),
188
188
  publishing_year,
189
189
  media)
190
190
 
191
- image_url = item.get('mediumimage/url')
191
+ image_url = item.get("mediumimage/url")
192
192
  log.info { "Found at Amazon[#{request_locale}]: #{book.title}" }
193
193
  results << [book, image_url]
194
194
  end
@@ -196,7 +196,7 @@ module Alexandria
196
196
  if results.size == 1
197
197
  return results.first
198
198
  else
199
- log.info { 'Found multiple results for lookup: checking each' }
199
+ log.info { "Found multiple results for lookup: checking each" }
200
200
  query_isbn_canon = Library.canonicalise_ean(criterion)
201
201
  results.each do |rslt|
202
202
  book = rslt[0]
@@ -206,7 +206,7 @@ module Alexandria
206
206
  log.debug { "rejected possible result #{book}" }
207
207
  end
208
208
  # gone through all and no ISBN match, so just return first result
209
- log.info { 'no more results to check. Returning first result, just an approximation' }
209
+ log.info { "no more results to check. Returning first result, just an approximation" }
210
210
  return results.first
211
211
  end
212
212
  else
@@ -216,19 +216,19 @@ module Alexandria
216
216
 
217
217
  def url(book)
218
218
  isbn = Library.canonicalise_isbn(book.isbn)
219
- url = case prefs['locale']
220
- when 'fr'
221
- 'http://www.amazon.fr/exec/obidos/ASIN/%s'
222
- when 'uk'
223
- 'http://www.amazon.co.uk/exec/obidos/ASIN/%s'
224
- when 'de'
225
- 'http://www.amazon.de/exec/obidos/ASIN/%s'
226
- when 'ca'
227
- 'http://www.amazon.ca/exec/obidos/ASIN/%s'
228
- when 'jp'
229
- 'http://www.amazon.jp/exec/obidos/ASIN/%s'
230
- when 'us'
231
- 'http://www.amazon.com/exec/obidos/ASIN/%s'
219
+ url = case prefs["locale"]
220
+ when "fr"
221
+ "http://www.amazon.fr/exec/obidos/ASIN/%s"
222
+ when "uk"
223
+ "http://www.amazon.co.uk/exec/obidos/ASIN/%s"
224
+ when "de"
225
+ "http://www.amazon.de/exec/obidos/ASIN/%s"
226
+ when "ca"
227
+ "http://www.amazon.ca/exec/obidos/ASIN/%s"
228
+ when "jp"
229
+ "http://www.amazon.jp/exec/obidos/ASIN/%s"
230
+ when "us"
231
+ "http://www.amazon.com/exec/obidos/ASIN/%s"
232
232
  end
233
233
  url % isbn
234
234
  rescue StandardError => ex
@@ -237,7 +237,7 @@ module Alexandria
237
237
  end
238
238
 
239
239
  def normalize(str)
240
- str = str.squeeze(' ').strip unless str.nil?
240
+ str = str.squeeze(" ").strip unless str.nil?
241
241
  str
242
242
  end
243
243
  end
@@ -1,40 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- #--
4
- # Copyright (c) 2006 Herryanto Siatono, Pluit Solutions
3
+ # This file is part of Alexandria.
5
4
  #
6
- # Permission is hereby granted, free of charge, to any person obtaining
7
- # a copy of this software and associated documentation files (the
8
- # "Software"), to deal in the Software without restriction, including
9
- # without limitation the rights to use, copy, modify, merge, publish,
10
- # distribute, sublicense, and/or sell copies of the Software, and to
11
- # permit persons to whom the Software is furnished to do so, subject to
12
- # the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be
15
- # included in all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
- # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
- # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
- # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
- # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
- #++
25
-
26
- # Modified by Cathal Mc Ginley 2008-02-18
27
- # added Amazon::Ecs.transport - to enable Alexandria's proxy support
28
- # Modified by Cathal Mc Ginley 2008-08-26
29
- # Amazon::Element.get now uses inner_text, not inner_html, fixing #21659
30
- # Modified by Cathal Mc Ginley 2009-08-13
31
- # Added sign_request and hmac_sha256 methods for Authentication support
32
-
33
- require 'net/http'
34
- require 'hpricot'
35
- require 'cgi'
36
-
37
- require 'digest/sha2'
5
+ # See the file README.md for authorship and licensing information.
6
+
7
+ require "net/http"
8
+ require "hpricot"
9
+ require "cgi"
10
+
11
+ require "digest/sha2"
38
12
 
39
13
  module Amazon
40
14
  class RequestError < StandardError; end
@@ -42,17 +16,17 @@ module Amazon
42
16
  class Ecs
43
17
  include Alexandria::Logging
44
18
 
45
- SERVICE_URLS = { us: 'http://webservices.amazon.com/onca/xml?Service=AWSECommerceService',
46
- uk: 'http://webservices.amazon.co.uk/onca/xml?Service=AWSECommerceService',
47
- ca: 'http://webservices.amazon.ca/onca/xml?Service=AWSECommerceService',
48
- de: 'http://webservices.amazon.de/onca/xml?Service=AWSECommerceService',
49
- jp: 'http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService',
50
- fr: 'http://webservices.amazon.fr/onca/xml?Service=AWSECommerceService' }.freeze
19
+ SERVICE_URLS = { us: "http://webservices.amazon.com/onca/xml?Service=AWSECommerceService",
20
+ uk: "http://webservices.amazon.co.uk/onca/xml?Service=AWSECommerceService",
21
+ ca: "http://webservices.amazon.ca/onca/xml?Service=AWSECommerceService",
22
+ de: "http://webservices.amazon.de/onca/xml?Service=AWSECommerceService",
23
+ jp: "http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService",
24
+ fr: "http://webservices.amazon.fr/onca/xml?Service=AWSECommerceService" }.freeze
51
25
 
52
26
  @@options = {}
53
27
  @@debug = false
54
28
 
55
- @@secret_access_key = ''
29
+ @@secret_access_key = ""
56
30
 
57
31
  # Default search options
58
32
  def self.options
@@ -79,7 +53,7 @@ module Amazon
79
53
  end
80
54
 
81
55
  def self.configure(&_proc)
82
- raise ArgumentError, 'Block is required.' unless block_given?
56
+ raise ArgumentError, "Block is required." unless block_given?
83
57
 
84
58
  yield @@options
85
59
  end
@@ -87,8 +61,8 @@ module Amazon
87
61
  # Search amazon items with search terms. Default search index option is 'Books'.
88
62
  # For other search type other than keywords, please specify :type => [search type param name].
89
63
  def self.item_search(terms, opts = {})
90
- opts[:operation] = 'ItemSearch'
91
- opts[:search_index] = opts[:search_index] || 'Books'
64
+ opts[:operation] = "ItemSearch"
65
+ opts[:search_index] = opts[:search_index] || "Books"
92
66
 
93
67
  type = opts.delete(:type)
94
68
  if type
@@ -102,7 +76,7 @@ module Amazon
102
76
 
103
77
  # Search an item by ASIN no.
104
78
  def self.item_lookup(item_id, opts = {})
105
- opts[:operation] = 'ItemLookup'
79
+ opts[:operation] = "ItemLookup"
106
80
  opts[:item_id] = item_id
107
81
 
108
82
  send_request(opts)
@@ -140,7 +114,7 @@ module Amazon
140
114
 
141
115
  # Return true if request is valid.
142
116
  def is_valid_request?
143
- (@doc / 'isvalid').inner_html == 'True'
117
+ (@doc / "isvalid").inner_html == "True"
144
118
  end
145
119
 
146
120
  # Return true if response has an error.
@@ -150,12 +124,12 @@ module Amazon
150
124
 
151
125
  # Return error message.
152
126
  def error
153
- Element.get(@doc, 'error/message')
127
+ Element.get(@doc, "error/message")
154
128
  end
155
129
 
156
130
  # Return an array of Amazon::Element item objects.
157
131
  def items
158
- @items ||= (@doc / 'item').map { |item| Element.new(item) }
132
+ @items ||= (@doc / "item").map { |item| Element.new(item) }
159
133
  @items
160
134
  end
161
135
 
@@ -166,19 +140,19 @@ module Amazon
166
140
 
167
141
  # Return current page no if :item_page option is when initiating the request.
168
142
  def item_page
169
- @item_page ||= (@doc / 'itemsearchrequest/itempage').inner_html.to_i
143
+ @item_page ||= (@doc / "itemsearchrequest/itempage").inner_html.to_i
170
144
  @item_page
171
145
  end
172
146
 
173
147
  # Return total results.
174
148
  def total_results
175
- @total_results ||= (@doc / 'totalresults').inner_html.to_i
149
+ @total_results ||= (@doc / "totalresults").inner_html.to_i
176
150
  @total_results
177
151
  end
178
152
 
179
153
  # Return total pages.
180
154
  def total_pages
181
- @total_pages ||= (@doc / 'totalpages').inner_html.to_i
155
+ @total_pages ||= (@doc / "totalpages").inner_html.to_i
182
156
  @total_pages
183
157
  end
184
158
  end
@@ -197,17 +171,17 @@ module Amazon
197
171
 
198
172
  def self.prepare_url(opts)
199
173
  country = opts.delete(:country)
200
- country = country.nil? ? 'us' : country
174
+ country = country.nil? ? "us" : country
201
175
  request_url = SERVICE_URLS[country.to_sym]
202
176
  raise Amazon::RequestError, "Invalid country '#{country}'" unless request_url
203
177
 
204
- qs = ''
205
- opts.each { |k, v|
178
+ qs = ""
179
+ opts.each do |k, v|
206
180
  next unless v
207
181
 
208
- v = v.join(',') if v.is_a? Array
182
+ v = v.join(",") if v.is_a? Array
209
183
  qs << "&#{camelize(k.to_s)}=#{URI.encode(v.to_s)}"
210
- }
184
+ end
211
185
  url = "#{request_url}#{qs}"
212
186
  # puts ">>> base url >> #{url}"
213
187
  signed_url = sign_request(url)
@@ -216,9 +190,9 @@ module Amazon
216
190
  end
217
191
 
218
192
  def self.camelize(s)
219
- s.to_s.
220
- gsub(/\/(.?)/) { '::' + Regexp.last_match[1].upcase }.
221
- gsub(/(^|_)(.)/) { Regexp.last_match[2].upcase }
193
+ s.to_s
194
+ .gsub(%r{/(.?)}) { "::" + Regexp.last_match[1].upcase }
195
+ .gsub(/(^|_)(.)/) { Regexp.last_match[2].upcase }
222
196
  end
223
197
 
224
198
  def self.hmac_sha256(message, key)
@@ -233,9 +207,9 @@ module Amazon
233
207
  ipad_bytes = ipad.bytes.map { |b| b }
234
208
  opad_bytes = opad.bytes.map { |b| b }
235
209
  key_bytes = key.bytes.map { |b| b }
236
- ipad_xor = ''
237
- opad_xor = ''
238
- for i in 0..key.size - 1
210
+ ipad_xor = ""
211
+ opad_xor = ""
212
+ (0..key.size - 1).each do |i|
239
213
  ipad_xor << (ipad_bytes[i] ^ key_bytes[i])
240
214
  opad_xor << (opad_bytes[i] ^ key_bytes[i])
241
215
  end
@@ -260,7 +234,7 @@ module Amazon
260
234
  raise AmazonNotConfiguredError unless @@secret_access_key
261
235
 
262
236
  # Step 0 : Split apart request string
263
- url_pattern = /http:\/\/([^\/]+)(\/[^\?]+)\?(.*$)/
237
+ url_pattern = %r{http://([^/]+)(/[^\?]+)\?(.*$)}
264
238
  url_pattern =~ request
265
239
  host = Regexp.last_match[1]
266
240
  path = Regexp.last_match[2]
@@ -268,21 +242,21 @@ module Amazon
268
242
 
269
243
  # Step 1: enter the timestamp
270
244
  t = Time.now.getutc # MUST be in UTC
271
- stamp = t.strftime('%Y-%m-%dT%H:%M:%SZ')
245
+ stamp = t.strftime("%Y-%m-%dT%H:%M:%SZ")
272
246
  param_string += "&Timestamp=#{stamp}"
273
247
 
274
248
  # Step 2 : URL-encode
275
- param_string = param_string.gsub(',', '%2C').gsub(':', '%3A')
249
+ param_string = param_string.gsub(",", "%2C").gsub(":", "%3A")
276
250
  # NOTE : take care not to double-encode
277
251
 
278
252
  # Step 3 : Split the parameter/value pairs
279
- params = param_string.split('&')
253
+ params = param_string.split("&")
280
254
 
281
255
  # Step 4 : Sort params
282
256
  params.sort!
283
257
 
284
258
  # Step 5 : Rejoin the param string
285
- canonical_param_string = params.join('&')
259
+ canonical_param_string = params.join("&")
286
260
 
287
261
  # Steps 6 & 7: Prepend HTTP request info
288
262
  string_to_sign = "GET\n#{host}\n#{path}\n#{canonical_param_string}"
@@ -291,7 +265,7 @@ module Amazon
291
265
 
292
266
  # Step 8 : Calculate RFC 2104-compliant HMAC with SHA256 hash algorithm
293
267
  sig = hmac_sha256(string_to_sign, @@secret_access_key)
294
- base64_sig = [sig].pack('m').strip
268
+ base64_sig = [sig].pack("m").strip
295
269
 
296
270
  # Step 9 : URL-encode + and = in sig
297
271
  base64_sig = CGI.escape(base64_sig)
@@ -334,27 +308,27 @@ module Amazon
334
308
  end
335
309
 
336
310
  # Get the text value of the given path, leave empty to retrieve current element value.
337
- def get(path = '')
311
+ def get(path = "")
338
312
  Element.get(@element, path)
339
313
  end
340
314
 
341
315
  # Get the unescaped HTML text of the given path.
342
- def get_unescaped(path = '')
316
+ def get_unescaped(path = "")
343
317
  Element.get_unescaped(@element, path)
344
318
  end
345
319
 
346
320
  # Get the array values of the given path.
347
- def get_array(path = '')
321
+ def get_array(path = "")
348
322
  Element.get_array(@element, path)
349
323
  end
350
324
 
351
325
  # Get the children element text values in hash format with the element names as the hash keys.
352
- def get_hash(path = '')
326
+ def get_hash(path = "")
353
327
  Element.get_hash(@element, path)
354
328
  end
355
329
 
356
330
  # Similar to #get, except an element object must be passed-in.
357
- def self.get(element, path = '')
331
+ def self.get(element, path = "")
358
332
  return unless element
359
333
 
360
334
  result = element.at(path)
@@ -365,21 +339,21 @@ module Amazon
365
339
  end
366
340
 
367
341
  # Similar to #get_unescaped, except an element object must be passed-in.
368
- def self.get_unescaped(element, path = '')
342
+ def self.get_unescaped(element, path = "")
369
343
  result = get(element, path)
370
344
  CGI.unescapeHTML(result) if result
371
345
  end
372
346
 
373
347
  # Similar to #get_array, except an element object must be passed-in.
374
- def self.get_array(element, path = '')
348
+ def self.get_array(element, path = "")
375
349
  return unless element
376
350
 
377
351
  result = element / path
378
352
  if (result.is_a? Hpricot::Elements) || (result.is_a? Array)
379
353
  parsed_result = []
380
- result.each { |item|
354
+ result.each do |item|
381
355
  parsed_result << Element.get(item)
382
- }
356
+ end
383
357
  parsed_result
384
358
  else
385
359
  [Element.get(result)]
@@ -387,7 +361,7 @@ module Amazon
387
361
  end
388
362
 
389
363
  # Similar to #get_hash, except an element object must be passed-in.
390
- def self.get_hash(element, path = '')
364
+ def self.get_hash(element, path = "")
391
365
  return unless element
392
366
 
393
367
  result = element.at(path)