my_api_client 0.11.0 → 0.12.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
  SHA256:
3
- metadata.gz: e2bc661b02a6845ae92ba2548be624861c3438fd094ab9644ae8fe340cf4adf7
4
- data.tar.gz: 99b85fe9d44cf89095318ebfcff92996d688d0aacf5ef86c65943aab13086c43
3
+ metadata.gz: 9e5581dc65458d9130b465c89479fa8fc877c78f67d1cf701c225d64cbef9577
4
+ data.tar.gz: 86cae4eade33446a4ef2a5e54f44600e72ee868add6e3cfa5690fe8f1336df01
5
5
  SHA512:
6
- metadata.gz: ac1dcb549f29b4c5abfecf3ec38b87c17758fe4ac2d442b9d6ff873c0ca6a140bafe6d9c5d84ee3a0fde54f098c439ebde7d072a87c883aec138681d8bbb7b4a
7
- data.tar.gz: 0e18aadcfa83643371ea029552240b8d67826f5c65ffd7ff1a4c9e8c26e0af71839ffccf19a9426fc57182e23601865615ed4d06f060e61c8a5e797f6298ec5d
6
+ metadata.gz: fce2d580f7c2622b2c2b1acc506e585434c29946ac81b6311e255cb53ac8e98276f30b79171e87610076376711f024b08b86724dcc5413328ba7488c9b52e983
7
+ data.tar.gz: 9475d69090e5748e511e7000df1db586da11ee5f62fc5f35fad30fce203a6ca2beabcafcf28e8eaf505e4a58d45cd4f771da86dea74bdcc70cee7e072267751e
data/.rubocop.yml CHANGED
@@ -23,6 +23,9 @@ Metrics/MethodLength:
23
23
  Metrics/LineLength:
24
24
  Max: 100
25
25
 
26
+ Naming/AccessorMethodName:
27
+ Enabled: false
28
+
26
29
  Style/ClassAndModuleChildren:
27
30
  Exclude:
28
31
  - 'spec/**/*'
@@ -33,6 +36,10 @@ Style/TrailingCommaInArrayLiteral:
33
36
  Style/TrailingCommaInHashLiteral:
34
37
  EnforcedStyleForMultiline: comma
35
38
 
39
+ RSpec/DescribeClass:
40
+ Exclude:
41
+ - 'spec/lib/my_api_client/rspec/matchers/**/*'
42
+
36
43
  RSpec/ExampleLength:
37
44
  Max: 10
38
45
 
@@ -43,7 +50,7 @@ RSpec/FilePath:
43
50
  - 'spec/lib/my_api_client/rspec/**/*'
44
51
 
45
52
  RSpec/NestedGroups:
46
- Max: 4
53
+ Max: 5
47
54
 
48
55
  RSpec/MultipleExpectations:
49
56
  Max: 4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Change log
2
2
 
3
+ ## v0.12.0 (Jan 19, 2020)
4
+
5
+ ### Feature
6
+
7
+ * [#173](https://github.com/ryz310/my_api_client/pull/173) Avoid sleep on testing ([@ryz310](https://github.com/ryz310))
8
+ * [#175](https://github.com/ryz310/my_api_client/pull/175) Verify arguments on error handling definition ([@ryz310](https://github.com/ryz310))
9
+ * [#176](https://github.com/ryz310/my_api_client/pull/176) Provides a syntax sugar of `retry_on` on `error_handling` ([@ryz310](https://github.com/ryz310))
10
+
11
+ ### Bugfix
12
+
13
+ * [#174](https://github.com/ryz310/my_api_client/pull/174) Fix warning on ruby 2.7 ([@ryz310](https://github.com/ryz310))
14
+
3
15
  ## v0.11.0 (Jan 16, 2020)
4
16
 
5
17
  ### Feature
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- my_api_client (0.11.0)
4
+ my_api_client (0.12.0)
5
5
  activesupport (>= 4.2.0)
6
6
  faraday (>= 0.17.1)
7
7
  jsonpath
@@ -93,7 +93,7 @@ GEM
93
93
  to_regexp (0.2.1)
94
94
  tzinfo (1.2.6)
95
95
  thread_safe (~> 0.1)
96
- unicode-display_width (1.6.0)
96
+ unicode-display_width (1.6.1)
97
97
  webmock (3.8.0)
98
98
  addressable (>= 2.3.6)
99
99
  crack (>= 0.3.2)
data/README.jp.md CHANGED
@@ -228,6 +228,36 @@ API リクエストを何度も実行していると回線の不調などによ
228
228
 
229
229
  ちなみに一応 `discard_on` も実装していますが、作者自身が有効な用途を見出せていないので、詳細は割愛します。良い利用方法があれば教えてください。
230
230
 
231
+ #### 便利な使い方
232
+
233
+ `error_handling` に `retry` オプションを付与する事で `retry_on` の定義を省略できます。
234
+ 例えば以下の 2 つのコードは同じ意味になります。
235
+
236
+ ```ruby
237
+ retry_on MyApiClient::ApiLimitError, wait: 30.seconds, attempts: 3
238
+ error_handling json: { '$.errors.code': 20 },
239
+ raise: MyApiClient::ApiLimitError
240
+ ```
241
+
242
+ ```ruby
243
+ error_handling json: { '$.errors.code': 20 },
244
+ raise: MyApiClient::ApiLimitError,
245
+ retry: { wait: 30.seconds, attempts: 3 }
246
+ ```
247
+
248
+ `retry_on` で `wait` や `attempts` を指定する必要がない場合は `retry: true` という記述で動作します。
249
+
250
+ ```ruby
251
+ error_handling json: { '$.errors.code': 20 },
252
+ raise: MyApiClient::ApiLimitError,
253
+ retry: true
254
+ ```
255
+
256
+ `retry` オプションを使用する際は以下の点に注意が必要です。
257
+
258
+ * `error_handling` に `raise` オプションの指定が必須となります。
259
+ * Block を使った `error_handling` の定義は禁止されます。
260
+
231
261
  #### MyApiClient::NetworkError
232
262
 
233
263
  前述の通りですが、 `MyApiClient` ではネットワーク系の例外はまとめて `MyApiClient::NetworkError` として `raise` されます。他の例外と同じく `MyApiClient::Error` を親クラスとしています。 `MyApiClient::NetworkError` として扱われる例外クラスの一覧は `MyApiClient::NETWORK_ERRORS` で参照できます。また、元となった例外は `#original_error` で参照できます。
data/lib/my_api_client.rb CHANGED
@@ -7,9 +7,11 @@ require 'jsonpath'
7
7
  require 'active_support'
8
8
  require 'active_support/core_ext'
9
9
  require 'sawyer'
10
+ require 'my_api_client/service_abstract'
10
11
  require 'my_api_client/version'
11
12
  require 'my_api_client/config'
12
13
  require 'my_api_client/error_handling/generator'
14
+ require 'my_api_client/error_handling/process_retry_option'
13
15
  require 'my_api_client/error_handling'
14
16
  require 'my_api_client/exceptions'
15
17
  require 'my_api_client/logger'
@@ -18,6 +20,7 @@ require 'my_api_client/params/params'
18
20
  require 'my_api_client/params/request'
19
21
  require 'my_api_client/request'
20
22
  require 'my_api_client/base'
23
+ require 'my_api_client/sleeper'
21
24
 
22
25
  # Loads gems for feature of integrations
23
26
  begin
@@ -26,7 +26,7 @@ module MyApiClient
26
26
 
27
27
  HTTP_METHODS.each do |http_method|
28
28
  class_eval <<~METHOD, __FILE__, __LINE__ + 1
29
- # Description of #undefined
29
+ # Description of ##{http_method}
30
30
  #
31
31
  # @param pathname [String]
32
32
  # @param headers [Hash, nil]
@@ -34,15 +34,22 @@ module MyApiClient
34
34
  # @option with [Symbol]
35
35
  # Calls specified method when error detected
36
36
  # @option raise [MyApiClient::Error]
37
- # Raises specified error when error detected. default: MyApiClient::Error
37
+ # Raises specified error when an invalid response detected.
38
+ # Should be inherited `MyApiClient::Error` class.
39
+ # default: MyApiClient::Error
40
+ # @option retry [TrueClass, Hash]
41
+ # If the error detected, retries the API request. Requires `raise` option.
42
+ # You can set `true` or `retry_on` options (`wait` and `attempts`).
38
43
  # @yield [MyApiClient::Params::Params, MyApiClient::Logger]
39
- # Executes the block when error detected
44
+ # Executes the block when error detected.
45
+ # Forbid to be used with the` retry` option.
40
46
  def error_handling(**options, &block)
41
- options[:raise] ||= MyApiClient::Error
42
- options[:block] = block if block_given?
47
+ options[:block] = block
48
+ retry_options = ProcessRetryOption.call(error_handling_options: options)
49
+ retry_on(options[:raise], **retry_options) if retry_options
43
50
 
44
51
  temp = error_handlers.dup
45
- temp << ->(response) { Generator.call(options.merge(response: response)) }
52
+ temp << ->(response) { Generator.call(**options.merge(response: response)) }
46
53
  self.error_handlers = temp
47
54
  end
48
55
  end
@@ -3,8 +3,8 @@
3
3
  module MyApiClient
4
4
  module ErrorHandling
5
5
  # Generates an error handler proc (or symbol)
6
- class Generator
7
- private_class_method :new
6
+ class Generator < ServiceAbstract
7
+ ARGUMENTS = %i[response status_code json with raise block].freeze
8
8
 
9
9
  # @param options [Hash]
10
10
  # Options for this generator
@@ -25,17 +25,14 @@ module MyApiClient
25
25
  # Returns value as `Proc` if given `raise` or `block` option
26
26
  # @return [Symbol]
27
27
  # Returns value as `Symbol` if given `with` option
28
- def self.call(**options)
29
- new(options).send(:call)
28
+ def initialize(**options)
29
+ options[:raise] ||= MyApiClient::Error
30
+ verify_and_set_arguments(**options)
30
31
  end
31
32
 
32
33
  private
33
34
 
34
- attr_reader :_response, :_status_code, :_json, :_with, :_raise, :_block
35
-
36
- def initialize(**options)
37
- options.each { |k, v| instance_variable_set("@_#{k}", v) }
38
- end
35
+ attr_reader(*ARGUMENTS.map { |argument| :"_#{argument}" })
39
36
 
40
37
  def call
41
38
  return unless match?(_status_code, _response.status)
@@ -46,7 +43,23 @@ module MyApiClient
46
43
  elsif _with
47
44
  _with
48
45
  else
49
- ->(params, _logger) { raise _raise, params }
46
+ ->(params, _) { raise _raise, params }
47
+ end
48
+ end
49
+
50
+ # Verify given options and raise error if they are incorrect.
51
+ # If not, set them to instance variables.
52
+ #
53
+ # @param options [Hash]
54
+ # @raise [RuntimeError]
55
+ def verify_and_set_arguments(**options)
56
+ options.each do |k, v|
57
+ if ARGUMENTS.exclude? k
58
+ raise "Specified an incorrect option: `#{k}`\n" \
59
+ "You can use options that: #{ARGUMENTS}"
60
+ end
61
+
62
+ instance_variable_set("@_#{k}", v)
50
63
  end
51
64
  end
52
65
 
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyApiClient
4
+ module ErrorHandling
5
+ # Processes the `retry` option.
6
+ class ProcessRetryOption < ServiceAbstract
7
+ # @param error_handling_options [Hash]
8
+ # Options for the retry.
9
+ # @option raise [MyApiClient::Error]
10
+ # Raises specified error when an invalid response detected.
11
+ # Should be inherited `MyApiClient::Error` class.
12
+ # @option retry [TrueClass, Hash]
13
+ # If the error detected, retries the API request. Requires `raise` option.
14
+ # You can set `true` or `retry_on` options (`wait` and `attempts`).
15
+ # @option block [Proc, nil]
16
+ # Executes the block when error detected.
17
+ # The `block` option is forbidden to be used with the` retry` option.
18
+ # @return [Hash]
19
+ # Options for `retry_on`.
20
+ # @return [nil]
21
+ # If `retry` is not specified.
22
+ def initialize(error_handling_options:)
23
+ @error_handling_options = error_handling_options
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :error_handling_options
29
+
30
+ def call
31
+ retry_options = error_handling_options.delete(:retry)
32
+ return unless retry_options
33
+
34
+ verify_error_handling_options
35
+ retry_options = {} unless retry_options.is_a? Hash
36
+ retry_options
37
+ end
38
+
39
+ # Requires `retry` option and forbid `block` option.
40
+ def verify_error_handling_options
41
+ if !error_handling_options[:raise]
42
+ raise 'The `retry` option requires `raise` option. ' \
43
+ 'Please set any `raise` option, which inherits `MyApiClient::Error` class.'
44
+ elsif error_handling_options[:block]
45
+ raise 'The `block` option is forbidden to be used with the` retry` option.'
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -51,7 +51,7 @@ module MyApiClient
51
51
  end
52
52
 
53
53
  def retry_calling(wait)
54
- sleep(wait)
54
+ Sleeper.call(wait: wait)
55
55
  @retry_count += 1
56
56
  @retry_result = call(*args)
57
57
  end
@@ -16,9 +16,9 @@ RSpec::Matchers.define :be_handled_as_an_error do |expected_error_class|
16
16
  handle_error(api_request).nil?
17
17
  end
18
18
 
19
- chain :after_retry, :retry_count
20
- chain(:times) { nil }
21
- chain :when_receive, :expected_response
19
+ chain(:after_retry, :retry_count)
20
+ chain(:times) {}
21
+ chain(:when_receive, :expected_response)
22
22
 
23
23
  description do
24
24
  message = "be handled as #{expected_error_class || 'an error'}"
@@ -54,6 +54,7 @@ RSpec::Matchers.define :be_handled_as_an_error do |expected_error_class|
54
54
  )
55
55
  @sawyer = instance_double(Sawyer::Agent, call: response)
56
56
  allow(Sawyer::Agent).to receive(:new).and_return(sawyer)
57
+ allow(MyApiClient::Sleeper).to receive(:call)
57
58
  end
58
59
 
59
60
  def set_validation_for_retry_count
@@ -23,7 +23,7 @@ module MyApiClient
23
23
  # @return [InstanceDouble]
24
24
  # Returns a spy object of the stubbed ApiClient.
25
25
  def stub_api_client_all(klass, **actions_and_options)
26
- instance = stub_api_client(klass, actions_and_options)
26
+ instance = stub_api_client(klass, **actions_and_options)
27
27
  allow(klass).to receive(:new).and_return(instance)
28
28
  instance
29
29
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyApiClient
4
+ # The abstract class for service classes
5
+ class ServiceAbstract
6
+ private_class_method :new
7
+
8
+ def self.call(**args, &block)
9
+ new(**args, &block).send(:call)
10
+ end
11
+
12
+ # private
13
+
14
+ # def initialize(**_args)
15
+ # raise "You must implement #{self.class}##{__method__}"
16
+ # end
17
+
18
+ # def call
19
+ # raise "You must implement #{self.class}##{__method__}"
20
+ # end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyApiClient
4
+ # Sleep arbitrary time
5
+ class Sleeper < ServiceAbstract
6
+ # @param wait [Integer, Float] Sleep time
7
+ def initialize(wait:)
8
+ @wait = wait
9
+ end
10
+
11
+ private
12
+
13
+ attr_reader :wait
14
+
15
+ def call
16
+ sleep(wait)
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MyApiClient
4
- VERSION = '0.11.0'
4
+ VERSION = '0.12.0'
5
5
  end
@@ -22,6 +22,8 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ['lib']
24
24
 
25
+ spec.required_ruby_version = '>= 2.4.0'
26
+
25
27
  spec.add_dependency 'activesupport', '>= 4.2.0'
26
28
  spec.add_dependency 'faraday', '>= 0.17.1'
27
29
  spec.add_dependency 'jsonpath'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: my_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ryz310
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-15 00:00:00.000000000 Z
11
+ date: 2020-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -262,6 +262,7 @@ files:
262
262
  - lib/my_api_client/config.rb
263
263
  - lib/my_api_client/error_handling.rb
264
264
  - lib/my_api_client/error_handling/generator.rb
265
+ - lib/my_api_client/error_handling/process_retry_option.rb
265
266
  - lib/my_api_client/errors.rb
266
267
  - lib/my_api_client/exceptions.rb
267
268
  - lib/my_api_client/integrations/bugsnag.rb
@@ -274,6 +275,8 @@ files:
274
275
  - lib/my_api_client/rspec/matchers/be_handled_as_an_error.rb
275
276
  - lib/my_api_client/rspec/matchers/request_to.rb
276
277
  - lib/my_api_client/rspec/stub.rb
278
+ - lib/my_api_client/service_abstract.rb
279
+ - lib/my_api_client/sleeper.rb
277
280
  - lib/my_api_client/version.rb
278
281
  - my_api_client.gemspec
279
282
  - renovate.json
@@ -289,7 +292,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
289
292
  requirements:
290
293
  - - ">="
291
294
  - !ruby/object:Gem::Version
292
- version: '0'
295
+ version: 2.4.0
293
296
  required_rubygems_version: !ruby/object:Gem::Requirement
294
297
  requirements:
295
298
  - - ">="