peddler 0.16.0 → 0.17.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6f67b925cce300aac503662925a525c2a926db0
4
- data.tar.gz: c50b916f201204efff20ad84142b890f87f18db8
3
+ metadata.gz: 000b1310894c1927903fdf0e03c017ba423028ab
4
+ data.tar.gz: 67bb363245360947b26876012006f517c5a02adf
5
5
  SHA512:
6
- metadata.gz: 7b7207770118f4af6786a4394bfd1138b0b89c311e9b20059b9818ae75a84c4ed25f2ea4fd102740e5f98ffa1847e78d8536509e6b73cddf5fc0f4b1fefa6394
7
- data.tar.gz: 171a182338ae07f4e52ddbf846fd12e963ec2c4dce6c9c18b38e8fd8c95f8e3e3148a44b24d264a9b6165158b3a9908ad7531a63a5eacd836c3b569c42f4b31e
6
+ metadata.gz: 88b46c45a57029d3e5491f0d81dfbd840a0ebd5247b217d4b61ca3e8b2996c170436d6538e704aecf0a2a9a931ecd3bfbb6af4784d5b4a5b2f4072edce817f96
7
+ data.tar.gz: 36f0952ba933db954280775c3182acdc0be8c8eda111b81a3af36a483b8472403cd017f816c70456ddbeb37d6893c58aba25403c22461b31d773dcabb52c1ea4
data/README.md CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  # Peddler
3
2
 
4
3
  [![Build Status](https://travis-ci.org/hakanensari/peddler.svg)](https://travis-ci.org/hakanensari/peddler)
@@ -39,29 +38,36 @@ client = MWS::Orders::Client.new(
39
38
  aws_access_key_id: "baz",
40
39
  aws_secret_access_key: "qux"
41
40
  )
41
+ ```
42
42
 
43
- Alternatively, you can set these globally in the shell.
43
+ Alternatively, set these globally in the shell.
44
44
 
45
- ```sh
45
+ ```bash
46
46
  export MWS_MARKETPLACE_ID=foo
47
47
  export MWS_MERCHANT_ID=bar
48
48
  export AWS_ACCESS_KEY_ID=baz
49
49
  export AWS_SECRET_ACCESS_KEY=qux
50
50
  ```
51
51
 
52
+ You can now instantiate a client without passing credentials.
53
+
54
+ ```ruby
55
+ client = MWS::Orders::Client.new
56
+ ```
57
+
52
58
  If you are creating a client for another seller, pass the latter's `MWSAuthToken` to the client.
53
59
 
54
60
  ```ruby
55
61
  client.auth_token = "corge"
56
62
  ```
57
63
 
58
- Once you have a client with credentials, you can make requests to the API.
64
+ Once you have a client with valid credentials, you should be able to make requests to the API.
59
65
 
60
- Peddler returns the response wrapped in a simple parser that handles both XML documents and flat files.
66
+ Peddler returns the response wrapped in a parser that handles both XML documents and flat files.
61
67
 
62
68
  ```ruby
63
69
  parser = client.get_service_status
64
- parser.parse # will return Hash or a CSV object
70
+ parser.parse # will return a Hash or CSV object
65
71
  ```
66
72
 
67
73
  You can swap the default parser with a purpose-built one.
@@ -75,20 +81,21 @@ For a sample implementation, see my [MWS Orders](https://github.com/hakanensari/
75
81
  Finally, you can handle network errors caused by throttling or other transient issues by defining an error handler.
76
82
 
77
83
  ```ruby
78
- MWS::Orders::Client.on_error do |request, response|
79
- if response.status == 503
80
- logger.info "I was throttled"
84
+ MWS::Orders::Client.on_error do |e|
85
+ if e.response.status == 503
86
+ logger.warn e.response.message
81
87
  end
82
88
  end
83
89
  ```
84
90
 
85
- Alternatively, you can simply rescue.
91
+ Alternatively, rescue.
86
92
 
87
93
  ```ruby
88
94
  begin
89
95
  client.some_method
90
- rescue Excon::Errors::ServiceUnavailable
91
- sleep 1 and retry
96
+ rescue Excon::Errors::ServiceUnavailable => e
97
+ logger.warn e.response.message
98
+ retry
92
99
  end
93
100
  ```
94
101
 
@@ -28,7 +28,7 @@ module MWS
28
28
  # categories for a specific marketplace
29
29
  #
30
30
  # @see http://docs.developer.amazonservices.com/en_US/recommendations/Recommendations_ListRecommendations.html
31
- # @overload list_recommendations(opts = { marketplace_id: marketplace_id })
31
+ # @overload list_recommendations(opts = { marketplace_id: primary_marketplace_id })
32
32
  # @param opts [Hash]
33
33
  # @option opts [String] :marketplace_id
34
34
  # @option opts [String] :recommendation_category
@@ -31,22 +31,12 @@ module MWS
31
31
 
32
32
  # Gets the service status of the API
33
33
  #
34
- # @see http://docs.developer.amazonservices.com/en_US/sellers/MWS_GetServiceStatus.html
34
+ # @see http://docs.developer.amazonservices.com/en_US/sellers/Sellers_GetServiceStatus.html
35
35
  # @return [Peddler::XMLParser]
36
36
  def get_service_status
37
37
  operation('GetServiceStatus')
38
38
  run
39
39
  end
40
-
41
- # Gets the MWS Auth Token of the seller account
42
- #
43
- # @see http://docs.developer.amazonservices.com/en_US/auth_token/AuthToken_GetAuthToken.html
44
- # @todo Remove this method after June 30, 2015 as it will no longer be available.
45
- # @return [Peddler::XMLParser]
46
- def get_auth_token
47
- operation('GetAuthToken')
48
- run
49
- end
50
40
  end
51
41
  end
52
42
  end
@@ -20,7 +20,7 @@ module MWS
20
20
  # including the items that are subscribed to
21
21
  #
22
22
  # @see http://docs.developer.amazonservices.com/en_US/webstore/Webstore_ListSubscriptionsCount.html
23
- # @overload list_subscriptions_count(subscription_state, opts = { marketplace_id: marketplace_id })
23
+ # @overload list_subscriptions_count(subscription_state, opts = { marketplace_id: primary_marketplace_id })
24
24
  # @param subscription_state [String]
25
25
  # @param opts [Hash]
26
26
  # @option opts [String] :marketplace_id
@@ -69,14 +69,16 @@ module Peddler
69
69
 
70
70
  def inherited(base)
71
71
  base.params(params)
72
- base.on_error(&@error_handler) if @error_handler
72
+ base.on_error(&@error_handler)
73
73
  end
74
74
  end
75
75
 
76
+ @error_handler = -> (e) { fail e }
77
+
76
78
  # Creates a new client instance
77
79
  #
78
80
  # @param opts [Hash]
79
- # @option opts [String] :marketplace_id
81
+ # @option opts [String] :primary_marketplace_id
80
82
  # @option opts [String] :merchant_id
81
83
  # @option opts [String] :aws_access_key_id
82
84
  # @option opts [String] :aws_secret_access_key
@@ -97,12 +99,12 @@ module Peddler
97
99
  @primary_marketplace_id ||= ENV['MWS_MARKETPLACE_ID']
98
100
  end
99
101
 
100
- # @deprecated Use {#primary_marketplace_id} instead.
102
+ # @deprecated Use {#primary_marketplace_id}.
101
103
  def marketplace_id
102
104
  @primary_marketplace_id
103
105
  end
104
106
 
105
- # @deprecated Use {#primary_marketplace_id=} instead.
107
+ # @deprecated Use {#primary_marketplace_id=}.
106
108
  def marketplace_id=(marketplace_id)
107
109
  @primary_marketplace_id = marketplace_id
108
110
  end
@@ -165,24 +167,14 @@ module Peddler
165
167
  end
166
168
 
167
169
  # @api private
168
- # rubocop:disable AbcSize, MethodLength
169
170
  def run
170
- opts = defaults.merge(query: operation, headers: headers)
171
- opts.store(:body, body) if body
171
+ opts = build_options
172
172
  opts.store(:response_block, Proc.new) if block_given?
173
173
  res = post(opts)
174
174
 
175
175
  parser.new(res, encoding)
176
176
  rescue Excon::Errors::Error => e
177
- handle_error(e) or raise
178
- rescue NoMethodError => e
179
- if e.message == "undefined method `new' for #{parser}"
180
- warn "[DEPRECATION] `Parser.parse` is deprecated. "\
181
- "Please use `Parser.new` instead."
182
- parser.parse(res, encoding)
183
- else
184
- raise
185
- end
177
+ handle_error(e)
186
178
  end
187
179
 
188
180
  private
@@ -207,9 +199,31 @@ module Peddler
207
199
  self.class.parser
208
200
  end
209
201
 
202
+ def build_options
203
+ opts = defaults.merge(query: operation, headers: headers)
204
+ body ? opts.update(body: body) : opts
205
+ end
206
+
210
207
  def handle_error(e)
211
- return false unless error_handler
212
- error_handler.call(e.request, e.response)
208
+ e = decorate_error(e)
209
+ error_handler.call(*deprecate_error_handler_arguments(e))
210
+ end
211
+
212
+ def decorate_error(e)
213
+ if e.is_a?(::Excon::Errors::HTTPStatusError)
214
+ e.instance_variable_set(:@response, ErrorParser.new(e.response))
215
+ end
216
+
217
+ e
218
+ end
219
+
220
+ def deprecate_error_handler_arguments(e)
221
+ if error_handler.parameters.size == 2
222
+ warn "[DEPRECATION] Error handler now expects exception as argument."
223
+ [e.request, e.response]
224
+ else
225
+ [e]
226
+ end
213
227
  end
214
228
  end
215
229
  end
@@ -0,0 +1,26 @@
1
+ require 'peddler/xml_parser'
2
+
3
+ module Peddler
4
+ # @api private
5
+ class ErrorParser < XMLParser
6
+ def message
7
+ parse['Message']
8
+ end
9
+
10
+ def type
11
+ parse['Type']
12
+ end
13
+
14
+ def code
15
+ parse['Code']
16
+ end
17
+
18
+ private
19
+
20
+ def find_data
21
+ xml
22
+ .fetch('ErrorResponse', {})
23
+ .fetch('Error', {})
24
+ end
25
+ end
26
+ end
@@ -11,6 +11,7 @@ module Peddler
11
11
  'A21TJRUUN4KGV' => 'mws.amazonservices.in',
12
12
  'APJ6JRA9NG5V4' => 'mws-eu.amazonservices.com',
13
13
  'A1VC38T7YXB528' => 'mws.amazonservices.jp',
14
+ 'A1AM78C64UM0Y8' => 'mws.amazonservices.com.mx',
14
15
  'ATVPDKIKX0DER' => 'mws.amazonservices.com'
15
16
  }
16
17
 
@@ -1,19 +1,19 @@
1
1
  require 'peddler/flat_file_parser'
2
- require 'peddler/xml_parser'
2
+ require 'peddler/xml_response_parser'
3
3
 
4
4
  module Peddler
5
5
  # @api private
6
6
  module Parser
7
7
  class << self
8
- # The inevitable messiness of massaging data produced by a motley army of
9
- # Amazon developers
8
+ # The inevitable-seeming messiness of massaging data produced by a motley
9
+ # army of Amazon developers
10
10
  def new(res, encoding = 'ISO-8859-1')
11
11
  # Don't parse if there's no body
12
12
  return res unless res.body
13
13
 
14
14
  content_type = res.headers['Content-Type']
15
15
  if content_type.start_with?('text/xml')
16
- XMLParser.new(res)
16
+ XMLResponseParser.new(res)
17
17
  else
18
18
  # Amazon returns a variety of content types for flat files, so we
19
19
  # simply assume that anything not XML is a flat file rather than code
@@ -1,3 +1,3 @@
1
1
  module Peddler
2
- VERSION = '0.16.0'
2
+ VERSION = '0.17.0'
3
3
  end
@@ -4,12 +4,8 @@ require 'multi_xml'
4
4
  module Peddler
5
5
  # @api private
6
6
  class XMLParser < SimpleDelegator
7
- def next_token
8
- parse.fetch('NextToken', false)
9
- end
10
-
11
7
  def parse
12
- @result ||= find_result
8
+ @data ||= find_data
13
9
  end
14
10
 
15
11
  def xml
@@ -17,14 +13,14 @@ module Peddler
17
13
  end
18
14
 
19
15
  def valid?
20
- headers['Content-Length'].to_i == body.size if headers['Content-Length']
16
+ return unless headers['Content-Length']
17
+ headers['Content-Length'].to_i == body.size
21
18
  end
22
19
 
23
20
  private
24
21
 
25
- def find_result
26
- results = xml.values[0].find { |k, _| k.include?('Result') }
27
- results ? results.last : nil
22
+ def find_data
23
+ fail NotImplementedError
28
24
  end
29
25
  end
30
26
  end
@@ -0,0 +1,17 @@
1
+ require 'peddler/xml_parser'
2
+
3
+ module Peddler
4
+ # @api private
5
+ class XMLResponseParser < XMLParser
6
+ def next_token
7
+ parse.fetch('NextToken', false)
8
+ end
9
+
10
+ private
11
+
12
+ def find_data
13
+ results = xml.values.first.find { |k, _| k.include?('Result') }
14
+ results ? results.last : nil
15
+ end
16
+ end
17
+ end
@@ -42,16 +42,4 @@ class TestMWSSellersClient < MiniTest::Test
42
42
 
43
43
  assert_equal operation, @client.operation
44
44
  end
45
-
46
- def test_gets_auth_token
47
- operation = {
48
- 'Action' => 'GetAuthToken'
49
- }
50
-
51
- @client.stub(:run, nil) do
52
- @client.get_auth_token
53
- end
54
-
55
- assert_equal operation, @client.operation
56
- end
57
45
  end
@@ -143,14 +143,12 @@ class TestPeddlerClient < MiniTest::Test
143
143
  @client.run
144
144
  end
145
145
 
146
- @klass.on_error do |_, res|
147
- assert_equal 503, res.status
146
+ @klass.on_error do |e|
147
+ assert_equal 503, e.response.status
148
148
  end
149
-
150
- @client.run
149
+ @client.run # no longer raises
151
150
 
152
151
  Excon.stubs.clear
153
- @klass.instance_variable_set(:@error_handler, nil)
154
152
  end
155
153
 
156
154
  def test_error_callback_on_instance
@@ -160,10 +158,9 @@ class TestPeddlerClient < MiniTest::Test
160
158
  @client.run
161
159
  end
162
160
 
163
- @client.on_error do |_, res|
164
- assert_equal 503, res.status
161
+ @client.on_error do |e|
162
+ assert_equal 503, e.response.status
165
163
  end
166
-
167
164
  @client.run
168
165
 
169
166
  Excon.stubs.clear
@@ -172,53 +169,54 @@ class TestPeddlerClient < MiniTest::Test
172
169
  def test_error_callback_on_client_ancestor
173
170
  Excon.stub({}, status: 503)
174
171
 
175
- assert_raises(Excon::Errors::ServiceUnavailable) do
176
- @client.run
177
- end
178
-
179
- Peddler::Client.on_error do |_, res|
180
- assert_equal 503, res.status
172
+ @klass.on_error do |e|
173
+ assert_equal 503, e.response.status
181
174
  end
175
+ @client.run # no longer raises
182
176
 
183
177
  klass = Class.new(Peddler::Client)
184
178
  klass.parser = Parser
185
- client = klass.new
186
- client.aws_access_key_id = 'key'
187
- client.aws_secret_access_key = 'secret'
188
- client.merchant_id = 'seller'
189
- client.primary_marketplace_id = 'ATVPDKIKX0DER' # US
190
- client.operation('Foo')
191
- client.run
179
+ other_client = klass.new
180
+ other_client.aws_access_key_id = 'key'
181
+ other_client.aws_secret_access_key = 'secret'
182
+ other_client.merchant_id = 'seller'
183
+ other_client.primary_marketplace_id = 'ATVPDKIKX0DER' # US
184
+ other_client.operation('Foo')
185
+ assert_raises(Excon::Errors::ServiceUnavailable) do
186
+ other_client.run
187
+ end
192
188
 
193
189
  Excon.stubs.clear
194
- Peddler::Client.instance_variable_set(:@error_handler, nil)
195
190
  end
196
191
 
197
- def test_deprecates_call_to_parser_parse
198
- deprecated_parser = Module.new do
199
- def self.parse(res, *)
200
- res
201
- end
202
- end
203
- @client.stub :warn, nil do
204
- @klass.parser = deprecated_parser
205
- res = @client.run
206
- assert_equal @body, res.body
192
+ def test_decorates_error_response
193
+ res = {
194
+ body: '<ErrorResponse><Error>Foo</Error></ErrorResponse>',
195
+ status: 503
196
+ }
197
+ Excon.stub({}, res)
198
+ e = nil
199
+
200
+ begin
201
+ @client.run
202
+ rescue => e
203
+ assert e.response.parse
207
204
  end
205
+
206
+ assert e
208
207
  end
209
208
 
210
- def test_raises_no_method_errors_not_related_to_deprecated_parser
211
- bad_parser = Module.new do
212
- def self.new(*)
213
- fail NoMethodError, "foo"
214
- end
209
+ def test_deprecated_error_callback
210
+ Excon.stub({}, status: 503)
211
+
212
+ @client.on_error do |_, res|
213
+ assert_equal 503, res.status
215
214
  end
216
- @klass.parser = bad_parser
217
- @client.stub :warn, nil do
218
- assert_raises NoMethodError do
219
- @client.run
220
- end
215
+ assert_output nil, /DEPRECATION/ do
216
+ @client.run
221
217
  end
218
+
219
+ Excon.stubs.clear
222
220
  end
223
221
 
224
222
  def test_deprecated_marketplace_id_accessor
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+ require 'peddler/error_parser'
3
+
4
+ class TestPeddlerErrorParser < MiniTest::Test
5
+ def setup
6
+ body = <<-XML
7
+ <ErrorResponse>
8
+ <Error>
9
+ <Type>Foo</Type>
10
+ <Code>Bar</Code>
11
+ <Message>Baz</Message>
12
+ </Error>
13
+ <RequestID>123</RequestID>
14
+ </ErrorResponse>
15
+ XML
16
+ res = OpenStruct.new(
17
+ body: body,
18
+ headers: {
19
+ 'Content-Type' => 'text/xml',
20
+ 'Content-Length' => body.size.to_s
21
+ }
22
+ )
23
+
24
+ @parser = Peddler::ErrorParser.new(res)
25
+ end
26
+
27
+ def test_parses_data
28
+ assert @parser.parse
29
+ end
30
+
31
+ def test_has_a_message
32
+ assert @parser.message
33
+ end
34
+
35
+ def test_has_code
36
+ assert @parser.code
37
+ end
38
+
39
+ def test_has_type
40
+ assert @parser.type
41
+ end
42
+ end
@@ -3,22 +3,23 @@ require 'peddler/xml_parser'
3
3
 
4
4
  class TestPeddlerXMLParser < MiniTest::Test
5
5
  def setup
6
- body = '<Response><Result><NextToken>123</NextToken>'\
7
- '<Foo>Bar</Foo></Result></Response>'
6
+ body = '<Foo>Bar</Foo>'
7
+
8
8
  res = OpenStruct.new(
9
9
  body: body,
10
- headers: { 'Content-Type' => 'text/xml', 'Content-Length' => '78' }
10
+ headers: {
11
+ 'Content-Type' => 'text/xml',
12
+ 'Content-Length' => body.size.to_s
13
+ }
11
14
  )
12
15
 
13
16
  @parser = Peddler::XMLParser.new(res)
14
17
  end
15
18
 
16
- def test_parses_data
17
- assert_equal 'Bar', @parser.parse['Foo']
18
- end
19
-
20
- def test_next_token
21
- assert_equal '123', @parser.next_token
19
+ def test_does_not_implement_parsing
20
+ assert_raises NotImplementedError do
21
+ @parser.parse
22
+ end
22
23
  end
23
24
 
24
25
  def test_validates
@@ -0,0 +1,23 @@
1
+ require 'helper'
2
+ require 'peddler/xml_response_parser'
3
+
4
+ class TestPeddlerXMLResponseParser < MiniTest::Test
5
+ def setup
6
+ body = '<Response><Result><NextToken>123</NextToken>'\
7
+ '<Foo>Bar</Foo></Result></Response>'
8
+ res = OpenStruct.new(
9
+ body: body,
10
+ headers: { 'Content-Type' => 'text/xml', 'Content-Length' => '78' }
11
+ )
12
+
13
+ @parser = Peddler::XMLResponseParser.new(res)
14
+ end
15
+
16
+ def test_parses_data
17
+ assert_equal 'Bar', @parser.parse['Foo']
18
+ end
19
+
20
+ def test_next_token
21
+ assert_equal '123', @parser.next_token
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: peddler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hakan Ensari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-28 00:00:00.000000000 Z
11
+ date: 2015-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jeff
@@ -78,6 +78,7 @@ files:
78
78
  - lib/mws/webstore/client.rb
79
79
  - lib/peddler.rb
80
80
  - lib/peddler/client.rb
81
+ - lib/peddler/error_parser.rb
81
82
  - lib/peddler/flat_file_parser.rb
82
83
  - lib/peddler/marketplace.rb
83
84
  - lib/peddler/operation.rb
@@ -85,6 +86,7 @@ files:
85
86
  - lib/peddler/structured_list.rb
86
87
  - lib/peddler/version.rb
87
88
  - lib/peddler/xml_parser.rb
89
+ - lib/peddler/xml_response_parser.rb
88
90
  - test/helper.rb
89
91
  - test/integration/test_cart_information.rb
90
92
  - test/integration/test_customer_information.rb
@@ -116,12 +118,14 @@ files:
116
118
  - test/unit/mws/test_subscriptions_client.rb
117
119
  - test/unit/mws/test_webstore_client.rb
118
120
  - test/unit/peddler/test_client.rb
121
+ - test/unit/peddler/test_error_parser.rb
119
122
  - test/unit/peddler/test_flat_file_parser.rb
120
123
  - test/unit/peddler/test_marketplace.rb
121
124
  - test/unit/peddler/test_operation.rb
122
125
  - test/unit/peddler/test_parser.rb
123
126
  - test/unit/peddler/test_structured_list.rb
124
127
  - test/unit/peddler/test_xml_parser.rb
128
+ - test/unit/peddler/test_xml_response_parser.rb
125
129
  - test/unit/test_mws.rb
126
130
  - test/vcr_cassettes/CartInformation.yml
127
131
  - test/vcr_cassettes/CustomerInformation.yml
@@ -193,12 +197,14 @@ test_files:
193
197
  - test/unit/mws/test_subscriptions_client.rb
194
198
  - test/unit/mws/test_webstore_client.rb
195
199
  - test/unit/peddler/test_client.rb
200
+ - test/unit/peddler/test_error_parser.rb
196
201
  - test/unit/peddler/test_flat_file_parser.rb
197
202
  - test/unit/peddler/test_marketplace.rb
198
203
  - test/unit/peddler/test_operation.rb
199
204
  - test/unit/peddler/test_parser.rb
200
205
  - test/unit/peddler/test_structured_list.rb
201
206
  - test/unit/peddler/test_xml_parser.rb
207
+ - test/unit/peddler/test_xml_response_parser.rb
202
208
  - test/unit/test_mws.rb
203
209
  - test/vcr_cassettes/CartInformation.yml
204
210
  - test/vcr_cassettes/CustomerInformation.yml