rapa 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,120 @@
1
+ require "cgi"
2
+ require "time"
3
+
4
+ module Rapa
5
+ module Queries
6
+ class BaseQuery
7
+ SERVICE = "AWSECommerceService"
8
+ VERSION = "2013-08-01"
9
+
10
+ class << self
11
+ attr_writer :property_names
12
+
13
+ # @note Override
14
+ def inherited(child_class)
15
+ child_class.property_names = property_names.clone
16
+ end
17
+
18
+ # @return [Array<Symbol>]
19
+ def property_names
20
+ @property_names ||= []
21
+ end
22
+
23
+ # @param property_name [Symbol]
24
+ def property(property_name)
25
+ property_names << property_name
26
+ end
27
+ end
28
+
29
+ property :AssociateTag
30
+ property :AWSAccessKeyId
31
+ property :Operation
32
+ property :RelatedItemPage
33
+ property :RelationshipType
34
+ property :ResponseGroup
35
+ property :Service
36
+ property :Timestamp
37
+ property :Version
38
+
39
+ # @param options [Hash]
40
+ def initialize(options = {})
41
+ @options = options
42
+ end
43
+
44
+ # @return [String]
45
+ def AssociateTag
46
+ options[:associate_tag]
47
+ end
48
+
49
+ # @return [String]
50
+ def AWSAccessKeyId
51
+ options[:access_key_id]
52
+ end
53
+
54
+ # @return [String]
55
+ def Operation
56
+ raise ::NotImplementedError
57
+ end
58
+
59
+ # @return [Integer, nil]
60
+ def RelatedItemPage
61
+ options[:related_item_page]
62
+ end
63
+
64
+ # @return [String, nil]
65
+ def RelationshipType
66
+ options[:relationship_type]
67
+ end
68
+
69
+ # @return [String, nil]
70
+ def ResponseGroup
71
+ if options[:response_groups]
72
+ options[:response_groups].join(",")
73
+ end
74
+ end
75
+
76
+ # @return [String]
77
+ def Service
78
+ SERVICE
79
+ end
80
+
81
+ # @return [String]
82
+ def Timestamp
83
+ ::Time.now.utc.iso8601
84
+ end
85
+
86
+ # @return [Hash]
87
+ def to_hash
88
+ self.class.property_names.each_with_object({}) do |property_name, result|
89
+ value = send(property_name)
90
+ unless value.nil?
91
+ result[property_name.to_s] = value
92
+ end
93
+ end.sort.to_h
94
+ end
95
+
96
+ # @return [String]
97
+ def to_s
98
+ to_hash.map do |key, value|
99
+ [
100
+ key,
101
+ ::CGI.escape(value),
102
+ ].join("=")
103
+ end.join("&")
104
+ end
105
+
106
+ # @return [String]
107
+ def Version
108
+ VERSION
109
+ end
110
+
111
+ private
112
+
113
+ # @private
114
+ # @return [Hash]
115
+ def options
116
+ @options
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,19 @@
1
+ module Rapa
2
+ module Queries
3
+ class ListItemsQuery < BaseQuery
4
+ OPERATION = "ItemLookup"
5
+
6
+ property :ItemId
7
+
8
+ # @return [String]
9
+ def ItemId
10
+ options[:asins].join(",")
11
+ end
12
+
13
+ # @note Override
14
+ def Operation
15
+ OPERATION
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ module Rapa
2
+ module Queries
3
+ class SearchItemsQuery < BaseQuery
4
+ SEARCH_INDEX_DEFAULT = "All"
5
+ OPERATION = "ItemSearch"
6
+
7
+ property :Keywords
8
+ property :SearchIndex
9
+
10
+ # @return [Array<String>]
11
+ def Keywords
12
+ options[:keywords].join(",")
13
+ end
14
+
15
+ # @note Override
16
+ def Operation
17
+ OPERATION
18
+ end
19
+
20
+ # @return [String]
21
+ def SearchIndex
22
+ options[:search_index] || SEARCH_INDEX_DEFAULT
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ module Rapa
2
+ module Resources
3
+ class BaseResource
4
+ # @param source [Hash]
5
+ def initialize(source)
6
+ @source = source
7
+ end
8
+
9
+ # @return [Hash]
10
+ def source
11
+ @source
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,357 @@
1
+ require "date"
2
+
3
+ module Rapa
4
+ module Resources
5
+ class ItemResource < BaseResource
6
+ # @return [Boolean, nil]
7
+ def adult_product?
8
+ if flag_source = source.dig("ItemAttributes", "IsAdultProduct")
9
+ flag_source != "0"
10
+ end
11
+ end
12
+
13
+ # @return [Array<Rapa::AlternateVersion>, nil]
14
+ def alternate_versions
15
+ if alternate_version_sources = source.dig("AlternateVersions", "AlternateVersion")
16
+ ::Array.wrap(alternate_version_sources).map do |alternate_version_source|
17
+ ::Rapa::AlternateVersion.new(alternate_version_source)
18
+ end
19
+ end
20
+ end
21
+
22
+ # @return [String]
23
+ def asin
24
+ source["ASIN"]
25
+ end
26
+
27
+ # @return [Array<String>, nil]
28
+ def authors
29
+ if author_sources = source.dig("ItemAttributes", "Author")
30
+ Array(author_sources)
31
+ end
32
+ end
33
+
34
+ # @return [String, nil]
35
+ def binding
36
+ source.dig("ItemAttributes", "Binding")
37
+ end
38
+
39
+ # @return [Array, nil]
40
+ def browse_nodes
41
+ source.dig("BrowseNodes", "BrowseNode")
42
+ end
43
+
44
+ # @return [String, nil]
45
+ def creator_name
46
+ source.dig("ItemAttributes", "Creator", "__content__")
47
+ end
48
+
49
+ # @return [String, nil]
50
+ def creator_role
51
+ source.dig("ItemAttributes", "Creator", "Role")
52
+ end
53
+
54
+ # @return [String, nil]
55
+ def ean
56
+ source.dig("ItemAttributes", "EAN")
57
+ end
58
+
59
+ # @return [Integer, nil]
60
+ def episode_sequence
61
+ if value = source.dig("ItemAttributes", "EpisodeSequence")
62
+ value.to_i
63
+ end
64
+ end
65
+
66
+ # @return [String, nil]
67
+ def genre
68
+ source.dig("ItemAttributes", "Genre")
69
+ end
70
+
71
+ # @return [Boolean]
72
+ def has_customer_reviews?
73
+ source.dig("CustomerReviews", "HasReviews") == "true"
74
+ end
75
+
76
+ # @return [Rapa::Image, nil]
77
+ def image_hi_res
78
+ find_image("HiResImage")
79
+ end
80
+
81
+ # @return [Rapa::Image, nil]
82
+ def image_large
83
+ find_image("LargeImage")
84
+ end
85
+
86
+ # @return [Rapa::Image, nil]
87
+ def image_medium
88
+ find_image("MediumImage")
89
+ end
90
+
91
+ # @return [Rapa::Image, nil]
92
+ def image_small
93
+ find_image("SmallImage")
94
+ end
95
+
96
+ # @return [Rapa::Image, nil]
97
+ def image_swatch
98
+ find_image("SwatchImage")
99
+ end
100
+
101
+ # @return [Rapa::Image, nil]
102
+ def image_thumbnail
103
+ find_image("ThumbnailImage")
104
+ end
105
+
106
+ # @return [Rapa::Image, nil]
107
+ def image_tiny
108
+ find_image("TinyImage")
109
+ end
110
+
111
+ # @return [String, nil]
112
+ def isbn
113
+ source.dig("ItemAttributes", "ISBN")
114
+ end
115
+
116
+ # @return [Rapa::Quantity]
117
+ def item_height
118
+ if quantity_source = source.dig("ItemAttributes", "ItemDimensions", "Height")
119
+ ::Rapa::Quantity.new(quantity_source)
120
+ end
121
+ end
122
+
123
+ # @return [Rapa::Quantity]
124
+ def item_length
125
+ if quantity_source = source.dig("ItemAttributes", "ItemDimensions", "Length")
126
+ ::Rapa::Quantity.new(quantity_source)
127
+ end
128
+ end
129
+
130
+ # @return [Rapa::Quantity]
131
+ def item_width
132
+ if quantity_source = source.dig("ItemAttributes", "ItemDimensions", "Width")
133
+ ::Rapa::Quantity.new(quantity_source)
134
+ end
135
+ end
136
+
137
+ # @return [String, nil]
138
+ def label
139
+ source.dig("ItemAttributes", "Label")
140
+ end
141
+
142
+ # @return [Array<Rapa::Language>, nil]
143
+ def languages
144
+ if language_sources = source.dig("ItemAttributes", "Languages", "Language")
145
+ language_sources.map do |language_source|
146
+ ::Rapa::Language.new(language_source)
147
+ end
148
+ end
149
+ end
150
+
151
+ # @return [String, nil]
152
+ def manufacturer
153
+ source.dig("ItemAttributes", "Manufacturer")
154
+ end
155
+
156
+ # @return [Integer, nil]
157
+ def number_of_pages
158
+ if value = source.dig("ItemAttributes", "NumberOfPages")
159
+ value.to_i
160
+ end
161
+ end
162
+
163
+ # @return [Rapa::Quantity]
164
+ def package_height
165
+ if quantity_source = source.dig("ItemAttributes", "PackageDimensions", "Height")
166
+ ::Rapa::Quantity.new(quantity_source)
167
+ end
168
+ end
169
+
170
+ # @return [Rapa::Quantity]
171
+ def package_length
172
+ if quantity_source = source.dig("ItemAttributes", "PackageDimensions", "Length")
173
+ ::Rapa::Quantity.new(quantity_source)
174
+ end
175
+ end
176
+
177
+ # @return [Rapa::Quantity]
178
+ def package_weight
179
+ if quantity_source = source.dig("ItemAttributes", "PackageDimensions", "Weight")
180
+ ::Rapa::Quantity.new(quantity_source)
181
+ end
182
+ end
183
+
184
+ # @return [Rapa::Quantity]
185
+ def package_width
186
+ if quantity_source = source.dig("ItemAttributes", "PackageDimensions", "Width")
187
+ ::Rapa::Quantity.new(quantity_source)
188
+ end
189
+ end
190
+
191
+ # @return [String, nil]
192
+ def product_group
193
+ source.dig("ItemAttributes", "ProductGroup")
194
+ end
195
+
196
+ # @return [String, nil]
197
+ def product_type_name
198
+ source.dig("ItemAttributes", "ProductTypeName")
199
+ end
200
+
201
+ # @return [Date, nil]
202
+ def publication_date
203
+ if value = source.dig("ItemAttributes", "PublicationDate")
204
+ ::Date.parse(value)
205
+ end
206
+ end
207
+
208
+ # @return [String, nil]
209
+ def publisher
210
+ source.dig("ItemAttributes", "Publisher")
211
+ end
212
+
213
+ # @return [Integer, nil]
214
+ def related_item_count
215
+ if value = source.dig("RelatedItems", "RelatedItemCount")
216
+ value.to_i
217
+ end
218
+ end
219
+
220
+ # @return [Integer, nil]
221
+ def related_item_page
222
+ if value = source.dig("RelatedItems", "RelatedItemPage")
223
+ value.to_i
224
+ end
225
+ end
226
+
227
+ # @return [Integer, nil]
228
+ def related_item_page_count
229
+ if value = source.dig("RelatedItems", "RelatedItemPageCount")
230
+ value.to_i
231
+ end
232
+ end
233
+
234
+ # @return [Array<Rapa::Resources::ItemResource>, nil]
235
+ def related_items
236
+ if source_or_sources = source.dig("RelatedItems", "RelatedItem")
237
+ if source_or_sources.is_a?(::Array)
238
+ source_or_sources
239
+ else
240
+ [source_or_sources]
241
+ end.map do |related_item_source|
242
+ ::Rapa::Resources::ItemResource.new(related_item_source["Item"])
243
+ end
244
+ end
245
+ end
246
+
247
+ # @return [String, nil]
248
+ def relationship
249
+ source.dig("RelatedItems", "Relationship")
250
+ end
251
+
252
+ # @return [String, nil]
253
+ def relationship_type
254
+ source.dig("RelatedItems", "RelationshipType")
255
+ end
256
+
257
+ # @return [Date, nil]
258
+ def release_date
259
+ if value = source.dig("ItemAttributes", "ReleaseDate")
260
+ ::Date.parse(value)
261
+ end
262
+ end
263
+
264
+ # @return [Rapa::Quantity, nil]
265
+ def running_time
266
+ if value = source.dig("ItemAttributes", "RunningTime")
267
+ ::Rapa::Quantity.new(value)
268
+ end
269
+ end
270
+
271
+ # @return [Integer, nil]
272
+ def sales_rank
273
+ source["SalesRank"]
274
+ end
275
+
276
+ # @return [Integer, nil]
277
+ def season_sequence
278
+ if value = source.dig("ItemAttributes", "SeasonSequence")
279
+ value.to_i
280
+ end
281
+ end
282
+
283
+ # @return [Array<Rapa::SimilarProduct>, nil]
284
+ def similar_products
285
+ if similar_product_sources = source["SimilarProducts"]
286
+ similar_product_sources.map do |similar_product_source|
287
+ ::Rapa::SimilarProduct.new(similar_product_source)
288
+ end
289
+ end
290
+ end
291
+
292
+ # @return [String, nil]
293
+ def studio
294
+ source.dig("ItemAttributes", "Studio")
295
+ end
296
+
297
+ # @return [String, nil]
298
+ def title
299
+ source.dig("ItemAttributes", "Title")
300
+ end
301
+
302
+ # @return [String, nil]
303
+ def url_add_to_wishlist
304
+ item_links["Add To Wishlist"]
305
+ end
306
+
307
+ # @return [String, nil]
308
+ def url_all_customer_reviews
309
+ item_links["All Customer Reviews"]
310
+ end
311
+
312
+ # @return [String, nil]
313
+ def url_all_offers
314
+ item_links["All Offers"]
315
+ end
316
+
317
+ # @return [String, nil]
318
+ def url_customer_reviews_iframe
319
+ source.dig("CustomerReviews", "IFrameURL")
320
+ end
321
+
322
+ # @return [String]
323
+ def url_details_page
324
+ source["DetailPageURL"]
325
+ end
326
+
327
+ # @return [String, nil]
328
+ def url_tell_a_friend
329
+ item_links["Tell A Friend"]
330
+ end
331
+
332
+ private
333
+
334
+ # @param key [String]
335
+ # @return [Rapa::Image, nil]
336
+ def find_image(key)
337
+ if image_source = (source[key] || source.dig("ImageSets", "ImageSet", key))
338
+ ::Rapa::Image.new(image_source)
339
+ end
340
+ end
341
+
342
+ # @private
343
+ # @return [Hash, nil]
344
+ def item_attributes
345
+ source["ItemAttributes"]
346
+ end
347
+
348
+ # @private
349
+ # @return [Hash]
350
+ def item_links
351
+ @item_links ||= source["ItemLinks"]["ItemLink"].each_with_object({}) do |element, result|
352
+ result[element["Description"]] = element["URL"]
353
+ end
354
+ end
355
+ end
356
+ end
357
+ end
@@ -0,0 +1,70 @@
1
+ module Rapa
2
+ module Responses
3
+ class BaseResponse
4
+ include ::Enumerable
5
+
6
+ # @param faraday_response [Faraday::Response]
7
+ def initialize(faraday_response)
8
+ @faraday_response = faraday_response
9
+ end
10
+
11
+ # @return [String]
12
+ def body
13
+ faraday_response.body
14
+ end
15
+
16
+ # @note Implementation for Enumerable
17
+ def each(&block)
18
+ resources.each(&block)
19
+ end
20
+
21
+ # @return [Faraday::Utils::Headers]
22
+ def headers
23
+ faraday_response.headers
24
+ end
25
+
26
+ # @return [Array<Rapa::Resources::ItemResource>]
27
+ def resources
28
+ sources.map do |source|
29
+ resource_class.new(source)
30
+ end
31
+ end
32
+
33
+ # @return [Integer]
34
+ def status
35
+ faraday_response.status
36
+ end
37
+
38
+ private
39
+
40
+ # @private
41
+ # @return [Faraday::Response]
42
+ def faraday_response
43
+ @faraday_response
44
+ end
45
+
46
+ # @return [Class]
47
+ def resource_class
48
+ raise ::NotImplementedError
49
+ end
50
+
51
+ # @private
52
+ def source_or_sources
53
+ raise ::NotImplementedError
54
+ end
55
+
56
+ # @private
57
+ # @return [Array<Hash>]
58
+ def sources
59
+ case source_or_sources
60
+ when ::Array
61
+ source_or_sources
62
+ when nil
63
+ []
64
+ else
65
+ [source_or_sources]
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,17 @@
1
+ module Rapa
2
+ module Responses
3
+ class ListItemsResponse < BaseResponse
4
+ private
5
+
6
+ # @note Override
7
+ def resource_class
8
+ ::Rapa::Resources::ItemResource
9
+ end
10
+
11
+ # @note Override
12
+ def source_or_sources
13
+ body.dig("ItemLookupResponse", "Items", "Item")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ module Rapa
2
+ module Responses
3
+ class SearchItemsResponse < BaseResponse
4
+ # @return [Rapa::Error]
5
+ def error
6
+ if value = body.dig("ItemSearchResponse", "Items", "Request", "Errors", "Error")
7
+ ::Rapa::Error.new(value)
8
+ end
9
+ end
10
+
11
+ # @return [Boolean]
12
+ def has_error?
13
+ !error.nil?
14
+ end
15
+
16
+ # @return [Boolean]
17
+ def has_valid_request?
18
+ body.dig("ItemSearchResponse", "Items", "Request", "IsValid") == "True"
19
+ end
20
+
21
+ # @return [Integer, nil]
22
+ def total_pages
23
+ if value = body.dig("ItemSearchResponse", "Items", "TotalPages")
24
+ value.to_i
25
+ end
26
+ end
27
+
28
+ # @return [Integer, nil]
29
+ def total_results
30
+ if value = body.dig("ItemSearchResponse", "Items", "TotalResults")
31
+ value.to_i
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # @note Override
38
+ def resource_class
39
+ ::Rapa::Resources::ItemResource
40
+ end
41
+
42
+ # @note Override
43
+ def source_or_sources
44
+ body.dig("ItemSearchResponse", "Items", "Item")
45
+ end
46
+ end
47
+ end
48
+ end