my_api_client 0.11.0 → 0.12.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
  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
  - - ">="