dustbag 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +92 -0
  4. data/lib/dustbag.rb +47 -0
  5. data/lib/dustbag/accessories.rb +7 -0
  6. data/lib/dustbag/accessory.rb +6 -0
  7. data/lib/dustbag/arguments.rb +8 -0
  8. data/lib/dustbag/availability_attributes.rb +9 -0
  9. data/lib/dustbag/browse_node.rb +15 -0
  10. data/lib/dustbag/browse_nodes.rb +7 -0
  11. data/lib/dustbag/common.rb +7 -0
  12. data/lib/dustbag/customer_reviews.rb +11 -0
  13. data/lib/dustbag/dimension.rb +13 -0
  14. data/lib/dustbag/dimensions.rb +10 -0
  15. data/lib/dustbag/editorial_review.rb +11 -0
  16. data/lib/dustbag/editorial_reviews.rb +7 -0
  17. data/lib/dustbag/http_headers.rb +8 -0
  18. data/lib/dustbag/image.rb +5 -0
  19. data/lib/dustbag/image_set.rb +9 -0
  20. data/lib/dustbag/image_sets.rb +7 -0
  21. data/lib/dustbag/item.rb +21 -0
  22. data/lib/dustbag/item_attributes.rb +79 -0
  23. data/lib/dustbag/item_link.rb +9 -0
  24. data/lib/dustbag/item_links.rb +7 -0
  25. data/lib/dustbag/item_search_request.rb +7 -0
  26. data/lib/dustbag/item_search_response.rb +8 -0
  27. data/lib/dustbag/items.rb +14 -0
  28. data/lib/dustbag/language.rb +7 -0
  29. data/lib/dustbag/languages.rb +7 -0
  30. data/lib/dustbag/offer.rb +52 -0
  31. data/lib/dustbag/offer_summary.rb +12 -0
  32. data/lib/dustbag/offers.rb +7 -0
  33. data/lib/dustbag/operation_request.rb +13 -0
  34. data/lib/dustbag/parser.rb +26 -0
  35. data/lib/dustbag/parser/collection_node.rb +37 -0
  36. data/lib/dustbag/parser/map_collection_node.rb +19 -0
  37. data/lib/dustbag/parser/node.rb +112 -0
  38. data/lib/dustbag/price.rb +13 -0
  39. data/lib/dustbag/request.rb +11 -0
  40. data/lib/dustbag/similar_product.rb +6 -0
  41. data/lib/dustbag/similar_products.rb +7 -0
  42. data/lib/dustbag/simple_product.rb +9 -0
  43. data/lib/dustbag/variation_attribute.rb +7 -0
  44. data/lib/dustbag/variation_attributes.rb +7 -0
  45. data/lib/dustbag/variation_summary.rb +13 -0
  46. data/lib/dustbag/variations.rb +18 -0
  47. data/lib/dustbag/version.rb +3 -0
  48. data/spec/dustbag/accessories_spec.rb +9 -0
  49. data/spec/dustbag/accessory_spec.rb +10 -0
  50. data/spec/dustbag/arguments_spec.rb +9 -0
  51. data/spec/dustbag/availability_attributes_spec.rb +21 -0
  52. data/spec/dustbag/browse_node_spec.rb +33 -0
  53. data/spec/dustbag/browse_nodes_spec.rb +9 -0
  54. data/spec/dustbag/customer_reviews_spec.rb +17 -0
  55. data/spec/dustbag/dimension_spec.rb +17 -0
  56. data/spec/dustbag/dimensions_spec.rb +29 -0
  57. data/spec/dustbag/editorial_review_spec.rb +21 -0
  58. data/spec/dustbag/editorial_reviews_spec.rb +9 -0
  59. data/spec/dustbag/http_headers_spec.rb +11 -0
  60. data/spec/dustbag/image_set_spec.rb +13 -0
  61. data/spec/dustbag/image_sets_spec.rb +9 -0
  62. data/spec/dustbag/image_spec.rb +9 -0
  63. data/spec/dustbag/item_attributes_spec.rb +188 -0
  64. data/spec/dustbag/item_link_spec.rb +17 -0
  65. data/spec/dustbag/item_links_spec.rb +9 -0
  66. data/spec/dustbag/item_search_request_spec.rb +21 -0
  67. data/spec/dustbag/item_search_response_spec.rb +13 -0
  68. data/spec/dustbag/item_spec.rb +110 -0
  69. data/spec/dustbag/items_spec.rb +25 -0
  70. data/spec/dustbag/language_spec.rb +17 -0
  71. data/spec/dustbag/languages_spec.rb +9 -0
  72. data/spec/dustbag/offer_spec.rb +43 -0
  73. data/spec/dustbag/offer_summary_spec.rb +30 -0
  74. data/spec/dustbag/offers_spec.rb +9 -0
  75. data/spec/dustbag/operation_request_spec.rb +27 -0
  76. data/spec/dustbag/parser_spec.rb +23 -0
  77. data/spec/dustbag/price_spec.rb +18 -0
  78. data/spec/dustbag/request_spec.rb +25 -0
  79. data/spec/dustbag/similar_product_spec.rb +18 -0
  80. data/spec/dustbag/similar_products_spec.rb +9 -0
  81. data/spec/dustbag/variation_attribute_spec.rb +17 -0
  82. data/spec/dustbag/variation_attributes_spec.rb +9 -0
  83. data/spec/dustbag/variation_summary_spec.rb +19 -0
  84. data/spec/dustbag/variations_spec.rb +22 -0
  85. data/spec/fixtures/accessories.xml +23 -0
  86. data/spec/fixtures/accessory.xml +4 -0
  87. data/spec/fixtures/arguments.xml +11 -0
  88. data/spec/fixtures/availability_attributes.xml +5 -0
  89. data/spec/fixtures/book_item_attributes.xml +61 -0
  90. data/spec/fixtures/browse_node.xml +23 -0
  91. data/spec/fixtures/browse_nodes.xml +25 -0
  92. data/spec/fixtures/customer_reviews.xml +5 -0
  93. data/spec/fixtures/dimension.xml +1 -0
  94. data/spec/fixtures/dimensions.xml +6 -0
  95. data/spec/fixtures/editorial_review.xml +5 -0
  96. data/spec/fixtures/editorial_reviews.xml +7 -0
  97. data/spec/fixtures/http_headers.xml +3 -0
  98. data/spec/fixtures/image.xml +5 -0
  99. data/spec/fixtures/image_set.xml +32 -0
  100. data/spec/fixtures/image_sets.xml +34 -0
  101. data/spec/fixtures/invalid_request.xml +8 -0
  102. data/spec/fixtures/item.xml +40 -0
  103. data/spec/fixtures/item_attributes.xml +58 -0
  104. data/spec/fixtures/item_large.xml +500 -0
  105. data/spec/fixtures/item_link.xml +4 -0
  106. data/spec/fixtures/item_links.xml +30 -0
  107. data/spec/fixtures/item_medium.xml +123 -0
  108. data/spec/fixtures/item_search_request.xml +5 -0
  109. data/spec/fixtures/item_search_response.xml +433 -0
  110. data/spec/fixtures/item_small.xml +40 -0
  111. data/spec/fixtures/item_with_accessories.xml +122 -0
  112. data/spec/fixtures/item_with_variation_attributes.xml +264 -0
  113. data/spec/fixtures/item_with_variations.xml +1016 -0
  114. data/spec/fixtures/items.xml +411 -0
  115. data/spec/fixtures/language.xml +4 -0
  116. data/spec/fixtures/languages.xml +6 -0
  117. data/spec/fixtures/movie_item_attributes.xml +30 -0
  118. data/spec/fixtures/offer.xml +26 -0
  119. data/spec/fixtures/offer_summary.xml +11 -0
  120. data/spec/fixtures/offers.xml +31 -0
  121. data/spec/fixtures/operation_request.xml +18 -0
  122. data/spec/fixtures/price.xml +5 -0
  123. data/spec/fixtures/request.xml +8 -0
  124. data/spec/fixtures/root_browse_node.xml +11 -0
  125. data/spec/fixtures/similar_product.xml +4 -0
  126. data/spec/fixtures/similar_products.xml +18 -0
  127. data/spec/fixtures/variation_attribute.xml +4 -0
  128. data/spec/fixtures/variation_attributes.xml +6 -0
  129. data/spec/fixtures/variation_summary.xml +12 -0
  130. data/spec/fixtures/variations.xml +1000 -0
  131. data/spec/shared_examples/collection_node.rb +15 -0
  132. data/spec/shared_examples/common_response.rb +7 -0
  133. data/spec/shared_examples/map_collection_node.rb +13 -0
  134. data/spec/shared_examples/node.rb +9 -0
  135. data/spec/shared_examples/node_context.rb +6 -0
  136. data/spec/shared_examples/simple_product.rb +4 -0
  137. data/spec/spec_helper.rb +16 -0
  138. metadata +356 -0
@@ -0,0 +1,9 @@
1
+ module Dustbag
2
+ class ItemLink
3
+ include Parser::Node
4
+
5
+ text_attributes :description
6
+
7
+ text_attributes url: 'URL'
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class ItemLinks
3
+ include Parser::CollectionNode
4
+
5
+ member_name 'ItemLink'
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class ItemSearchRequest
3
+ include Parser::Node
4
+
5
+ text_attributes :keywords, :response_group, :search_index
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Dustbag
2
+ class ItemSearchResponse
3
+ include Parser::Node
4
+ include Common
5
+
6
+ children :items
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ module Dustbag
2
+ class Items
3
+ include Parser::Node
4
+ include Parser::CollectionNode
5
+
6
+ member_name 'Item'
7
+
8
+ text_attributes :more_search_results_url
9
+
10
+ numeric_attributes :total_results, :total_pages
11
+
12
+ children :request
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class Language
3
+ include Parser::Node
4
+
5
+ text_attributes :name, :type
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class Languages
3
+ include Parser::CollectionNode
4
+
5
+ member_name 'Language'
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ module Dustbag
2
+ class Offer
3
+ include Parser::Node
4
+
5
+ def condition
6
+ offer_attrs = subnode('OfferAttributes')
7
+ condition = offer_attrs && offer_attrs.locate('Condition').first
8
+ condition && condition.text
9
+ end
10
+
11
+ def id
12
+ id = offer_listing && offer_listing.locate('OfferListingId').first
13
+ id && id.text
14
+ end
15
+
16
+ def price
17
+ price = offer_listing && offer_listing.locate('Price').first
18
+ Price.parse(price)
19
+ end
20
+
21
+ def amount_saved
22
+ savings = offer_listing && offer_listing.locate('AmountSaved').first
23
+ Price.parse(savings)
24
+ end
25
+
26
+ def availability
27
+ availability = offer_listing && offer_listing.locate('Availability').first
28
+ availability && availability.text
29
+ end
30
+
31
+ def eligible_for_super_saver_shipping?
32
+ eligible = offer_listing && offer_listing.locate('IsEligibleForSuperSaverShipping').first
33
+ eligible && eligible.text == '1'
34
+ end
35
+
36
+ def eligible_for_prime?
37
+ eligible = offer_listing && offer_listing.locate('IsEligibleForPrime').first
38
+ eligible && eligible.text == '1'
39
+ end
40
+
41
+ def availability_attributes
42
+ availability = offer_listing && offer_listing.locate('AvailabilityAttributes').first
43
+ AvailabilityAttributes.new(availability)
44
+ end
45
+
46
+ private
47
+
48
+ def offer_listing
49
+ subnode('OfferListing')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,12 @@
1
+ module Dustbag
2
+ class OfferSummary
3
+ include Parser::Node
4
+
5
+ numeric_attributes :total_new, :total_used, :total_collectible,
6
+ :total_refurbished
7
+
8
+ def lowest_new_price
9
+ Price.parse(subnode('LowestNewPrice'))
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class Offers
3
+ include Parser::CollectionNode
4
+
5
+ member_name 'Offer'
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module Dustbag
2
+ class OperationRequest
3
+ include Parser::Node
4
+
5
+ text_attributes :request_id, :request_processing_time
6
+
7
+ children :arguments
8
+
9
+ child name: :http_headers,
10
+ node: 'HTTPHeaders',
11
+ class: HttpHeaders
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ module Dustbag
2
+ module Parser
3
+ extend self
4
+
5
+ class Error < RuntimeError; end
6
+
7
+ def parse(body)
8
+ document = Ox.parse(body)
9
+
10
+ raise Error.new('Not a Ox::Document') unless document.is_a?(Ox::Document)
11
+
12
+ response_type = document.root.name
13
+
14
+ case response_type
15
+ when 'ItemSearchResponse'
16
+ ItemSearchResponse.new(document.root)
17
+ else
18
+ raise Error.new(response_type + ' is not implemented!')
19
+ end
20
+ end
21
+
22
+ autoload :CollectionNode, 'dustbag/parser/collection_node'
23
+ autoload :MapCollectionNode, 'dustbag/parser/map_collection_node'
24
+ autoload :Node, 'dustbag/parser/node'
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ module Dustbag
2
+ module Parser
3
+ module CollectionNode
4
+ include Enumerable
5
+ include Node
6
+
7
+ extend Forwardable
8
+
9
+ def_delegators :collection, :each, :size, :empty?
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+
15
+ def collection
16
+ members = node && node.locate(member_name) || []
17
+ @collection ||= members.map do |member|
18
+ member_class.new(member)
19
+ end
20
+ end
21
+
22
+ def member_name
23
+ self.class.member_name
24
+ end
25
+
26
+ def member_class
27
+ Dustbag.const_get(member_name)
28
+ end
29
+
30
+ module ClassMethods
31
+ def member_name(name = nil)
32
+ @member_name ||= name
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,19 @@
1
+ module Dustbag
2
+ module Parser
3
+ module MapCollectionNode
4
+ extend Forwardable
5
+
6
+ def_delegators(:collection, :[], :keys, :values)
7
+
8
+ private
9
+
10
+ def collection
11
+ members = node && node.locate(member_name) || []
12
+ @collection ||= members.inject({}) do |acc, val|
13
+ acc[val['Name']] = val['Value']
14
+ acc
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,112 @@
1
+ module Dustbag
2
+ module Parser
3
+ module Node
4
+ attr_reader :node, :subnodes
5
+ extend Forwardable
6
+
7
+ def_delegators :node, :value, :text, :attributes
8
+
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ end
12
+
13
+ def initialize(node)
14
+ @node = node
15
+ @subnodes = {}
16
+ end
17
+
18
+ def subnode_text(subnode_name)
19
+ subnode = subnode(subnode_name)
20
+ subnode && subnode.text
21
+ end
22
+
23
+ def subnode(subnode_name)
24
+ subnodes[subnode_name] ||= node.locate(subnode_name).first
25
+ end
26
+
27
+ def repeated_subnodes(subnode_name)
28
+ subnodes[subnode_name] ||= node.locate(subnode_name)
29
+ end
30
+
31
+ def repeated_subnodes_text(subnode_name)
32
+ repeated_subnodes(subnode_name).map(&:text)
33
+ end
34
+
35
+ module ClassMethods
36
+ def text_attributes(*attrs)
37
+ attrs.each do |attr|
38
+ node_name = xml_node_name(attr)
39
+
40
+ if attr.is_a?(Hash)
41
+ attr.each do |key, value|
42
+ define_method(key) do
43
+ subnode_text(value)
44
+ end
45
+ end
46
+ else
47
+ define_method(attr) do
48
+ subnode_text(node_name)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def numeric_attributes(*attrs)
55
+ attrs.each do |attr|
56
+ node_name = xml_node_name(attr)
57
+
58
+ if attr.is_a?(Hash)
59
+ attr.each do |key, value|
60
+ define_method(key) do
61
+ subnode_text(value).to_i
62
+ end
63
+ end
64
+ else
65
+ define_method(attr) do
66
+ subnode_text(node_name).to_i
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def children(*attrs)
73
+ attrs.each do |attr|
74
+
75
+ if attr.is_a?(Hash)
76
+ attr.each do |key, value|
77
+ node_name = xml_node_name(key)
78
+ define_method(key) do
79
+ value.new(subnode(node_name))
80
+ end
81
+ end
82
+ else
83
+ node_name = xml_node_name(attr)
84
+ define_method(attr) do
85
+ Dustbag.const_get(node_name).new(subnode(node_name))
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ def child(name)
92
+ if name.is_a? Hash
93
+ define_method(name[:name]) do
94
+ (name[:class] || Dustbag.const_get(name[:node])).new(subnode(name[:node]))
95
+ end
96
+ else
97
+ node_name = xml_node_name(attr)
98
+ define_method(name) do
99
+ Dustbag.const_get(node_name).new(subnode(node_name))
100
+ end
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def xml_node_name(attr)
107
+ attr.to_s.split('_').map(&:capitalize).join('')
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,13 @@
1
+ module Dustbag
2
+ module Price
3
+ extend self
4
+
5
+ def parse(xml_node)
6
+ xml_node && begin
7
+ amount = xml_node.locate('Amount').first
8
+ currency = xml_node.locate('Currency').first
9
+ Money.new(amount && amount.text, currency && currency.text)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Dustbag
2
+ class Request
3
+ include Parser::Node
4
+
5
+ children :item_search_request
6
+
7
+ def valid?
8
+ subnode_text('IsValid') == 'True'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module Dustbag
2
+ class SimilarProduct
3
+ include Parser::Node
4
+ include SimpleProduct
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class SimilarProducts
3
+ include Parser::CollectionNode
4
+
5
+ member_name 'SimilarProduct'
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Dustbag
2
+ module SimpleProduct
3
+ include Parser::Node
4
+
5
+ text_attributes asin: 'ASIN'
6
+
7
+ text_attributes :title
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class VariationAttribute
3
+ include Parser::Node
4
+
5
+ text_attributes :name, :value
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Dustbag
2
+ class VariationAttributes
3
+ include Parser::CollectionNode
4
+
5
+ member_name 'VariationAttribute'
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module Dustbag
2
+ class VariationSummary
3
+ include Parser::Node
4
+
5
+ def lowest_price
6
+ Price.parse(subnode('LowestPrice'))
7
+ end
8
+
9
+ def highest_price
10
+ Price.parse(subnode('HighestPrice'))
11
+ end
12
+ end
13
+ end