vacuum 0.1.3 → 0.2.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/README.md +69 -27
  2. data/lib/vacuum/endpoint/base.rb +58 -0
  3. data/lib/vacuum/endpoint/mws.rb +59 -0
  4. data/lib/vacuum/endpoint/product_advertising.rb +34 -0
  5. data/lib/vacuum/mws.rb +8 -0
  6. data/lib/vacuum/product_advertising.rb +7 -0
  7. data/lib/vacuum/request/base.rb +96 -0
  8. data/lib/vacuum/request/mws.rb +24 -0
  9. data/lib/vacuum/request/product_advertising.rb +90 -0
  10. data/lib/vacuum/request/signature/authentication.rb +32 -0
  11. data/lib/vacuum/request/signature/builder.rb +70 -0
  12. data/lib/vacuum/request/utils.rb +24 -0
  13. data/lib/vacuum/response/base.rb +57 -0
  14. data/lib/vacuum/response/mws.rb +7 -0
  15. data/lib/vacuum/response/product_advertising.rb +19 -0
  16. data/lib/vacuum/response/utils.rb +48 -0
  17. data/lib/vacuum/version.rb +1 -1
  18. data/lib/vacuum.rb +31 -11
  19. data/spec/fixtures/{http_response → product_advertising} +0 -0
  20. data/spec/spec_helper.rb +5 -4
  21. data/spec/support/shared_examples/endpoint.rb +43 -0
  22. data/spec/support/shared_examples/request.rb +95 -0
  23. data/spec/support/shared_examples/response.rb +51 -0
  24. data/spec/vacuum/endpoint/base_spec.rb +19 -0
  25. data/spec/vacuum/endpoint/mws_spec.rb +47 -0
  26. data/spec/vacuum/endpoint/product_advertising_spec.rb +25 -0
  27. data/spec/vacuum/request/base_spec.rb +22 -0
  28. data/spec/vacuum/request/mws_spec.rb +26 -0
  29. data/spec/vacuum/request/product_advertising_spec.rb +104 -0
  30. data/spec/vacuum/request/signature/authentication_spec.rb +30 -0
  31. data/spec/vacuum/request/signature/builder_spec.rb +76 -0
  32. data/spec/vacuum/request/utils_spec.rb +23 -0
  33. data/spec/vacuum/response/base_spec.rb +38 -0
  34. data/spec/vacuum/response/product_advertising_spec.rb +57 -0
  35. data/spec/vacuum/response/utils_spec.rb +42 -0
  36. metadata +107 -21
  37. data/lib/vacuum/em.rb +0 -21
  38. data/lib/vacuum/request.rb +0 -119
  39. data/lib/vacuum/response.rb +0 -63
  40. data/spec/vacuum/request_spec.rb +0 -130
  41. data/spec/vacuum/response_spec.rb +0 -80
data/README.md CHANGED
@@ -2,42 +2,84 @@
2
2
 
3
3
  [![travis] [1]] [2]
4
4
 
5
- ![vacuum] [3]
5
+ Vacuum is a Ruby wrapper to [various Amazon Web Services (AWS) APIs] [3].
6
6
 
7
- Vacuum is a minimal Ruby wrapper to the [Amazon Product Advertising API] [4].
7
+ ![vacuum] [4]
8
8
 
9
- # Usage
9
+ ## Amazon Product Advertising API
10
+
11
+ Vacuum knows the [Amazon Product Advertising API] [5] [inside out] [6].
10
12
 
11
13
  ```ruby
12
- require 'vacuum'
13
-
14
- # Create a request.
15
- req = Vacuum.new key: 'key',
16
- secret: 'secret',
17
- tag: 'tag',
18
- locale: 'us'
19
-
20
- # Build query.
21
- req.build 'Operation' => 'ItemSearch',
22
- 'SearchIndex' => 'All',
23
- 'Keywords' => 'Gilles Deleuze'
24
-
25
- # Execute.
26
- res = request.get
27
-
28
- # Consume response.
29
- if res.valid?
30
- # res.to_hash
31
- res.find('Item') do |item|
14
+ request = Vacuum.new(:product_advertising) do |config|
15
+ config.locale 'US'
16
+
17
+ config.key 'key'
18
+ config.secret 'secret'
19
+ config.tag 'tag'
20
+ end
21
+
22
+ # Use an alternative Faraday adapter.
23
+ # request.connection do |builder|
24
+ # builder.adapter :typhoeus
25
+ # end
26
+
27
+ # A barebone search request.
28
+ request.build operation: 'ItemSearch',
29
+ search_index: 'Books',
30
+ keywords: 'Deleuze'
31
+ response = request.get
32
+
33
+ # A less verbose search.
34
+ request.search :books, 'Deleuze'
35
+
36
+ if response.valid?
37
+ # response.code
38
+ # response.body
39
+ # response.errors
40
+ # response.xml # The Nokogiri XML doc
41
+ # response.to_hash
42
+ response.find('Item') do |item|
32
43
  p item['ASIN']
33
44
  end
34
45
  end
35
46
  ```
47
+ ## Amazon Marketplace Web Services API
48
+
49
+ The wrapper to the [Amazon Marketplace Web Services API] [7] is a
50
+ work-in-progress.
51
+
52
+ ```ruby
53
+ request = Vacuum.new(:mws_products) do |config|
54
+ config.locale 'US'
55
+
56
+ config.key 'key'
57
+ config.secret 'secret'
58
+ config.marketplace 'marketplace'
59
+ config.seller 'seller'
60
+ end
61
+
62
+ request.build 'Action' => 'GetLowestOfferListingsForASIN',
63
+ 'ASINList.ASIN.1' => '0231081596'
64
+ offers = request.get.find 'GetLowestOfferListingsForASINResult'
65
+ ```
66
+
67
+ ## Other AWS APIs
68
+
69
+ Vacuum should work with EC2, S3, IAM, SimpleDB, SQS, SNS, SES, ELB, CW, and so
70
+ on. Implement and send a pull request.
71
+
72
+ # Addendum
73
+
74
+ ![vacuums] [8]
36
75
 
37
- Read further [here] [5].
76
+ > Workers queuing to crawl AWS.
38
77
 
39
78
  [1]: https://secure.travis-ci.org/hakanensari/vacuum.png
40
79
  [2]: http://travis-ci.org/hakanensari/vacuum
41
- [3]: http://f.cl.ly/items/2k2X0e2u0G3k1c260D2u/vacuum.png
42
- [4]: https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html
43
- [5]: https://github.com/hakanensari/vacuum/blob/master/examples/
80
+ [3]: http://aws.amazon.com/
81
+ [4]: http://f.cl.ly/items/2k2X0e2u0G3k1c260D2u/vacuum.png
82
+ [5]: https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html
83
+ [6]: https://github.com/hakanensari/vacuum/blob/master/examples/product_advertising/
84
+ [7]: https://developer.amazonservices.com/gp/mws/docs.html
85
+ [8]: http://f.cl.ly/items/1Q3W372A0H3M0w2H1e0W/hoover.jpeg
@@ -0,0 +1,58 @@
1
+ module Vacuum
2
+ module Endpoint
3
+ # An Amazon Web Services (AWS) API endpoint.
4
+ class Base
5
+ LOCALES = %w(CA CN DE ES FR IT JP UK US)
6
+
7
+ # Raises a Not Implemented Error.
8
+ #
9
+ # When implemented, this should return a String AWS API host.
10
+ def host
11
+ raise NotImplementedError
12
+ end
13
+
14
+ # Returns the String AWS access key ID.
15
+ #
16
+ # Raises a Missing Key error if key is missing.
17
+ def key
18
+ @key or raise MissingKey
19
+ end
20
+
21
+ # Sets the String AWS access key ID.
22
+ attr_writer :key
23
+
24
+ # Returns the String AWS API locale (default: US).
25
+ #
26
+ # Raises a Bad Locale error if locale is not valid.
27
+ def locale
28
+ @locale ||= 'US'
29
+ LOCALES.include? @locale or raise BadLocale
30
+
31
+ @locale
32
+ end
33
+
34
+ # Sets the String AWS API locale.
35
+ attr_writer :locale
36
+
37
+ # Returns the String AWS access secret key.
38
+ #
39
+ # Raises a Missing Secret error if secret is missing.
40
+ def secret
41
+ @secret or raise MissingSecret
42
+ end
43
+
44
+ # Sets the String AWS access secret key.
45
+ attr_writer :secret
46
+
47
+ # Returns a String user agent for the AWS API request.
48
+ def user_agent
49
+ engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
50
+ language = [engine, RUBY_VERSION, "p#{RUBY_PATCHLEVEL}"].join ' '
51
+ hostname = `hostname`.chomp
52
+ version = Vacuum::VERSION
53
+
54
+ "Vacuum/#{version} (Language=#{language}; Host=#{hostname})"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,59 @@
1
+ module Vacuum
2
+ module Endpoint
3
+ # A Marketplace Web Services (MWS) API endpoint.
4
+ class MWS < Base
5
+ # A list of MWS API hosts.
6
+ HOSTS = {
7
+ 'CA' => 'mws.amazonservices.ca',
8
+ 'CN' => 'mws.amazonservices.com.cn',
9
+ 'DE' => 'mws-eu.amazonservices.com',
10
+ 'ES' => 'mws-eu.amazonservices.com',
11
+ 'FR' => 'mws-eu.amazonservices.com',
12
+ 'IT' => 'mws-eu.amazonservices.com',
13
+ 'JP' => 'mws.amazonservices.jp',
14
+ 'UK' => 'mws-eu.amazonservices.com',
15
+ 'US' => 'mws.amazonservices.com'
16
+ }
17
+
18
+ # Internal: Gets/Sets the Symbol MWS API type.
19
+ attr_accessor :api
20
+
21
+ # Returns a String MWS API host.
22
+ def host
23
+ HOSTS[locale]
24
+ end
25
+
26
+ # Sets the String marketplace ID.
27
+ #
28
+ # Raises a Missing Marketplace error if marketplace ID is missing.
29
+ def marketplace
30
+ @marketplace or raise MissingMarketplace
31
+ end
32
+
33
+ # Sets the String marketplace ID tag.
34
+ attr_writer :marketplace
35
+
36
+ # Returns a String MWS API URL path.
37
+ #
38
+ # Raises a Not Implemented Error if API is not implemented.
39
+ def path
40
+ case api
41
+ when :products
42
+ '/Products/2011-10-01'
43
+ else
44
+ raise NotImplementedError
45
+ end
46
+ end
47
+
48
+ # Sets the String seller ID.
49
+ #
50
+ # Raises a Missing Seller error if seller ID is missing.
51
+ def seller
52
+ @seller or raise MissingSeller
53
+ end
54
+
55
+ # Sets the String seller ID tag.
56
+ attr_writer :seller
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ module Vacuum
2
+ module Endpoint
3
+ # A Product Advertising API endpoint.
4
+ class ProductAdvertising < Base
5
+ # A list of Product Advertising API hosts.
6
+ HOSTS = {
7
+ 'CA' => 'ecs.amazonaws.ca',
8
+ 'CN' => 'webservices.amazon.cn',
9
+ 'DE' => 'ecs.amazonaws.de',
10
+ 'ES' => 'webservices.amazon.es',
11
+ 'FR' => 'ecs.amazonaws.fr',
12
+ 'IT' => 'webservices.amazon.it',
13
+ 'JP' => 'ecs.amazonaws.jp',
14
+ 'UK' => 'ecs.amazonaws.co.uk',
15
+ 'US' => 'ecs.amazonaws.com'
16
+ }
17
+
18
+ # Returns a String Product Advertising API host.
19
+ def host
20
+ HOSTS[locale]
21
+ end
22
+
23
+ # Sets the String Associate tag.
24
+ #
25
+ # Raises a Missing Tag error if tag is missing.
26
+ def tag
27
+ @tag or raise MissingTag
28
+ end
29
+
30
+ # Sets the String Associate tag.
31
+ attr_writer :tag
32
+ end
33
+ end
34
+ end
data/lib/vacuum/mws.rb ADDED
@@ -0,0 +1,8 @@
1
+ %w(endpoint request response).each do |path|
2
+ require "vacuum/#{path}/mws"
3
+ end
4
+
5
+ module Vacuum
6
+ class MissingMarketplace < ArgumentError; end
7
+ class MissingSeller < ArgumentError; end
8
+ end
@@ -0,0 +1,7 @@
1
+ %w(endpoint request response).each do |path|
2
+ require "vacuum/#{path}/product_advertising"
3
+ end
4
+
5
+ module Vacuum
6
+ class MissingTag < ArgumentError; end
7
+ end
@@ -0,0 +1,96 @@
1
+ module Vacuum
2
+ module Request
3
+ # An Amazon Web Services (AWS) API request.
4
+ class Base
5
+ # Returns the AWS API Endpoint.
6
+ attr :endpoint
7
+
8
+ # Creates a new request for given locale and credentials.
9
+ #
10
+ # Yields the AWS API endpoint if a block is given.
11
+ def initialize(&blk)
12
+ @parameters = {}
13
+ @endpoint = Endpoint.const_get(class_basename).new
14
+
15
+ configure &blk if block_given?
16
+ end
17
+
18
+ # Adds given parameters to the request.
19
+ #
20
+ # hsh - A Hash of parameter key and value pairs.
21
+ #
22
+ # Returns self.
23
+ def build(hsh)
24
+ hsh.each do |k, v|
25
+ k = Utils.camelize k.to_s if k.is_a? Symbol
26
+ @parameters[k] = v.is_a?(Array) ? v.join(',') : v.to_s
27
+ end
28
+
29
+ self
30
+ end
31
+
32
+ # Resets the request to the given parameters.
33
+ #
34
+ # hsh - A Hash of parameter key and value pairs.
35
+ #
36
+ # Returns self.
37
+ def build!(hsh = {})
38
+ @parameters = {}
39
+ build hsh
40
+ end
41
+
42
+ # Yields the AWS API Endpoint.
43
+ #
44
+ # Returns nothing.
45
+ def configure(&blk)
46
+ yield @endpoint
47
+ end
48
+
49
+ # Returns a Faraday::Connection.
50
+ #
51
+ # Yields a Faraday::Builder to configure the connection if a block is
52
+ # given.
53
+ def connection
54
+ @connection ||= Faraday.new do |builder|
55
+ builder.use Signature::Authentication, endpoint.secret
56
+
57
+ yield builder if block_given?
58
+
59
+ unless builder.handlers.any? { |h| h.name.include? ':Adapter:' }
60
+ builder.adapter Faraday.default_adapter
61
+ end
62
+ end
63
+ end
64
+
65
+ # Performs the AWS API request.
66
+ #
67
+ # Returns a Vacuum::Response::Base or a subclass thereof.
68
+ def get
69
+ res = connection.get url
70
+ Response.const_get(class_basename).new res.body, res.status
71
+ end
72
+
73
+ # Returns the Hash parameters of the AWS API request.
74
+ def parameters
75
+ default_parameters.merge @parameters
76
+ end
77
+
78
+ # Raises a Not Implemented Error.
79
+ #
80
+ # When implemented, this should return an Addressable::URI.
81
+ def url
82
+ raise NotImplementedError
83
+ end
84
+
85
+ private
86
+
87
+ def class_basename
88
+ self.class.name.split('::').last
89
+ end
90
+
91
+ def default_parameters
92
+ { 'AWSAccessKeyId' => endpoint.key }
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,24 @@
1
+ module Vacuum
2
+ module Request
3
+ # A Marketplace Web Services (MWS) API request.
4
+ class MWS < Base
5
+ # Returns the Addressable::URI URL of the MWS API request.
6
+ def url
7
+ Addressable::URI.new :scheme => 'https',
8
+ :host => endpoint.host,
9
+ :path => endpoint.path,
10
+ :query_values => parameters
11
+ end
12
+
13
+ private
14
+
15
+ def default_parameters
16
+ super.merge 'MarketplaceId' => endpoint.marketplace,
17
+ 'SellerId' => endpoint.seller,
18
+ 'Service' => 'AWSECommerceService',
19
+ 'SignatureMethod' => 'HmacSHA256',
20
+ 'SignatureVersion' => 2
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,90 @@
1
+ module Vacuum
2
+ module Request
3
+ # A Product Advertising API request.
4
+ class ProductAdvertising < Base
5
+ # Looks up attributes of up to twenty items.
6
+ #
7
+ # item_ids - Splat Array of item IDs. The last element may optionally
8
+ # specify a Hash of parameter key and value pairs.
9
+ #
10
+ # Examples
11
+ #
12
+ # request.find '0679753354', response_group: 'Images'
13
+ #
14
+ # Returns a Vacuum::Response.
15
+ def find(*item_ids)
16
+ given_params = item_ids.last.is_a?(Hash) ? item_ids.pop : {}
17
+
18
+ params =
19
+ case item_ids.size
20
+ when 1..10
21
+ {
22
+ 'Operation' => 'ItemLookup',
23
+ 'ItemId' => item_ids
24
+ }.merge given_params
25
+ when 11..20
26
+ default = {
27
+ 'Operation' => 'ItemLookup',
28
+ 'ItemId.1.ItemId' => item_ids.shift(10),
29
+ 'ItemId.2.ItemId' => item_ids
30
+ }
31
+ given_params.reduce(default) do |a, (k, v)|
32
+ a.merge "ItemLookup.Shared.#{Utils.camelize k.to_s}" => v
33
+ end
34
+ else
35
+ raise ArgumentError, "Can't look up #{item_ids.size} items"
36
+ end
37
+ build! params
38
+
39
+ get
40
+ end
41
+
42
+ # Searches for items that satisfy the given criteria, including one or
43
+ # more search indices.
44
+ #
45
+ # index - Symbol search index
46
+ # query_or_params - String keyword query or Hash of parameter key and
47
+ # value pairs (default: nil).
48
+ #
49
+ # Examples
50
+ #
51
+ # # Search the entire Amazon catalog for Deleuze.
52
+ # request.search :all, 'Deleuze'
53
+ #
54
+ # # Search books for non-fiction titles authored by Deleuze and sort
55
+ # # results by relevance.
56
+ # request.search :books, power: 'author:lacan and not fiction',
57
+ # sort: 'relevancerank'
58
+ #
59
+ def search(index, query_or_params = nil)
60
+ params = case query_or_params
61
+ when String
62
+ { 'Keywords' => query_or_params }
63
+ else
64
+ query_or_params
65
+ end
66
+ build! params.merge! 'Operation' => 'ItemSearch',
67
+ 'SearchIndex' => Utils.camelize(index.to_s)
68
+
69
+ get
70
+ end
71
+
72
+ # Returns the Addressable::URI URL of the Product Advertising API
73
+ # request.
74
+ def url
75
+ Addressable::URI.new :scheme => 'http',
76
+ :host => endpoint.host,
77
+ :path => '/onca/xml',
78
+ :query_values => parameters
79
+ end
80
+
81
+ private
82
+
83
+ def default_parameters
84
+ super.merge 'AssociateTag' => endpoint.tag,
85
+ 'Service' => 'AWSECommerceService',
86
+ 'Version' => '2011-08-01'
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,32 @@
1
+ module Vacuum
2
+ module Request
3
+ module Signature
4
+ # Internal: Middleware that signs REST requests to various Amazon API
5
+ # endpoints.
6
+ class Authentication < Faraday::Middleware
7
+ # Initializes the middleware.
8
+ #
9
+ # app - An Object that responds to `call` and returns a
10
+ # Faraday::Response.
11
+ # secret - The String Amazon AWS access secret key.
12
+ def initialize(app, secret)
13
+ @secret = secret
14
+ super app
15
+ end
16
+
17
+ # Signs the request.
18
+ #
19
+ # env - A Hash that contains info about the request.
20
+ #
21
+ # Returns an Object that responds to `call` and returns a
22
+ # Faraday::Response.
23
+ def call(env)
24
+ builder = Builder.new env, @secret
25
+ builder.timestamp.sort_query.sign
26
+
27
+ @app.call builder.env
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,70 @@
1
+ module Vacuum
2
+ module Request
3
+ module Signature
4
+ # Internal: Signs a request to an Amazon API with an HMAC-SHA256
5
+ # signature.
6
+ class Builder
7
+ # Returns a Hash that contains info about the request.
8
+ attr :env
9
+
10
+ # Returns the String Amazon AWS access secret key.
11
+ attr :secret
12
+
13
+ # Initializes a new Builder.
14
+ #
15
+ # env - A Hash that contains info about the request.
16
+ def initialize(env, secret)
17
+ env[:url] = Addressable::URI.parse env[:url]
18
+ @env, @secret = env, secret
19
+ end
20
+
21
+ # Returns the String name of the HTTP method used by the request.
22
+ def method
23
+ env[:method].to_s.upcase
24
+ end
25
+
26
+ # Signs the request.
27
+ #
28
+ # Returns self.
29
+ def sign
30
+ url.query = url.query.to_s + "&Signature=#{Utils.encode signature}"
31
+ self
32
+ end
33
+
34
+ # Returns a String signature.
35
+ def signature
36
+ sha256 = OpenSSL::Digest::SHA256.new
37
+ hash = OpenSSL::HMAC.digest sha256, secret, string_to_sign
38
+
39
+ Base64.encode64(hash).chomp
40
+ end
41
+
42
+ # Sorts the URL query values of the request.
43
+ #
44
+ # Returns self.
45
+ def sort_query
46
+ url.query_values = url.query_values
47
+ self
48
+ end
49
+
50
+ # Returns a String to sign based on pseudo-grammar specified by Amazon.
51
+ def string_to_sign
52
+ [method, url.host, url.path, url.query].join "\n"
53
+ end
54
+
55
+ # Timestamps the request.
56
+ #
57
+ # Returns self.
58
+ def timestamp
59
+ url.query = url.query.to_s + "&Timestamp=#{Utils.encode Time.now.utc.iso8601}"
60
+ self
61
+ end
62
+
63
+ # Returns the Addressable::URI URL of the request.
64
+ def url
65
+ env[:url]
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,24 @@
1
+ module Vacuum
2
+ module Request
3
+ module Utils
4
+ # Camelizes a value.
5
+ #
6
+ # val - A String value.
7
+ #
8
+ # Returns an upper-camelcased String.
9
+ def self.camelize(val)
10
+ val.split('_').map(&:capitalize).join
11
+ end
12
+
13
+ # Percent encodes a URI component.
14
+ #
15
+ # component - The String URI component to encode.
16
+ #
17
+ # Returns the String encoded component.
18
+ def self.encode(component)
19
+ Addressable::URI.encode_component \
20
+ component, Addressable::URI::CharacterClasses::UNRESERVED
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,57 @@
1
+ module Vacuum
2
+ module Response
3
+ # An Amazon Web Services (AWS) API response.
4
+ class Base
5
+ # Gets/Sets the String response body.
6
+ attr_accessor :body
7
+
8
+ # Gets/Sets the Integer HTTP response code.
9
+ attr_accessor :code
10
+
11
+ # Initializes a new Response.
12
+ #
13
+ # body - The String response body.
14
+ # code - An HTTP response code that responds to to_i.
15
+ def initialize(body, code)
16
+ @body, @code = body, code.to_i
17
+ end
18
+
19
+ # Queries the response.
20
+ #
21
+ # query - String attribute to be queried.
22
+ #
23
+ # Yields matching nodes to a given block if one is given.
24
+ #
25
+ # Returns an Array of matching nodes or the return values of the yielded
26
+ # block if latter was given.
27
+ def find(query)
28
+ path = if xml.namespaces.empty?
29
+ "//#{query}"
30
+ else
31
+ "//xmlns:#{query}"
32
+ end
33
+
34
+ xml.xpath(path).map do |node|
35
+ hsh = Utils.xml_to_hash node
36
+ block_given? ? yield(hsh) : hsh
37
+ end
38
+ end
39
+ alias [] find
40
+
41
+ # Returns a Hash representation of the response.
42
+ def to_hash
43
+ Utils.xml_to_hash xml
44
+ end
45
+
46
+ # Returns whether the HTTP response is OK.
47
+ def valid?
48
+ code == 200
49
+ end
50
+
51
+ # Returns an XML document.
52
+ def xml
53
+ @xml ||= Nokogiri::XML.parse @body
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,7 @@
1
+ module Vacuum
2
+ module Response
3
+ # A Marketplace Web Services (MWS) API response.
4
+ class MWS < Base
5
+ end
6
+ end
7
+ end