peddler 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
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