acfs 1.4.0 → 1.5.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: 6f998ff3e28801676c732fa44df93e18f651e96eb986c857c61b7f25b312a2c1
4
- data.tar.gz: a122064cb630a664489629ef658d5ecde917ced4cdc43a600b49d0e18e00bea7
3
+ metadata.gz: 53acc88297d3217a5d01db2ce713f935835b05438471fd2b69918029b5480954
4
+ data.tar.gz: d61a2f4e5014dab37d4e1a857d548df8dfb42afcaba219005556f203ea68da65
5
5
  SHA512:
6
- metadata.gz: 7801c96d794f08ad03b9ad204f8e7c8b611300922b12714ce7864a33c5a6268bc47c42e66b86c410358f17a0439d382c358ba15283eee07ff092d19a1f86a8be
7
- data.tar.gz: 78b2c804251fb6aaee270d9c894ff36b7b8dc7bb777148de55963255847fc28adcdbff9c7132352c5448bef7b9980fd72e6a14ffceda38540d661aceaf1e5e9d
6
+ metadata.gz: 35f66d3569256b183cb7c78fed7c41f0ce916f41ec081e60696693af8b869d47e797a53474942c4847cefb621e58d3d52ddf629168c63b7b2d558d1db23cf74a
7
+ data.tar.gz: 5e03be0b16cb469061b55a3c4467a4fa71496925caa086ed5d024ed79aaefdcc568afd970d526c284b08b8db06593f51886d8642f035f78f2ed7f89bd1b8f311
@@ -14,6 +14,16 @@
14
14
  ### Breaks
15
15
 
16
16
 
17
+ ## 1.5.0 - (2020-06-19)
18
+ ---
19
+
20
+ ### New
21
+ * Error classes for more HTTP error responses: `400`, `401`, `403`, `500`, `502`, `503`, `504`.
22
+
23
+ ### Changes
24
+ * Replace deprecated MultiJson with core JSON module
25
+
26
+
17
27
  ## 1.4.0 - (2020-06-12)
18
28
  ---
19
29
 
data/README.md CHANGED
@@ -10,6 +10,7 @@ Acfs is a library to develop API client libraries for single services within a l
10
10
 
11
11
  Acfs covers model and service abstraction, convenient query and filter methods, full middleware stack for pre-processing requests and responses on a per service level and automatic request queuing and parallel processing. See Usage for more.
12
12
 
13
+
13
14
  ## Installation
14
15
 
15
16
  Add this line to your application's Gemfile:
@@ -24,6 +25,7 @@ Or install it yourself as:
24
25
 
25
26
  > gem install acfs
26
27
 
28
+
27
29
  ## Usage
28
30
 
29
31
  First you need to define your service(s):
@@ -145,6 +147,7 @@ Acfs has basic update support using `PUT` requests:
145
147
  @user.persisted? # => true
146
148
  ```
147
149
 
150
+
148
151
  ## Singleton resources
149
152
 
150
153
  Singletons can be used in Acfs by creating a new resource which inherits from `SingletonResource`:
@@ -183,6 +186,7 @@ my_single = Single.find name: 'Max'
183
186
  Acfs.run # sends GET request with param to /single?name=Max
184
187
  ```
185
188
 
189
+
186
190
  ## Resource Inheritance
187
191
 
188
192
  Acfs provides a resource inheritance similar to ActiveRecord Single Table Inheritance. If a
@@ -219,6 +223,7 @@ Acfs.run
219
223
  @computer[2].class # => Pc
220
224
  ```
221
225
 
226
+
222
227
  ## Stubbing
223
228
 
224
229
  You can stub resources in applications using an Acfs service client:
@@ -279,6 +284,7 @@ it 'should find user number one' do
279
284
  end
280
285
  ```
281
286
 
287
+
282
288
  ## Instrumentation
283
289
 
284
290
  Acfs supports [instrumentation via active support][1].
@@ -296,21 +302,6 @@ Read [official guide][2] to see to to subscribe.
296
302
  [1]: http://guides.rubyonrails.org/active_support_instrumentation.html
297
303
  [2]: http://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event
298
304
 
299
- ## Roadmap
300
-
301
- * Update
302
- * Better new? detection eg. storing ETag from request resources.
303
- * Use PATCH for with only changed attributes and `If-Unmodifed-Since`
304
- and `If-Match` header fields if resource was surly loaded from service
305
- and not created with an id (e.g `User.new id: 5, name: "john"`).
306
- * Conflict detection (ETag / If-Unmodified-Since)
307
- * High level features
308
- * Support for custom mime types on client and server side. (`application/vnd.myservice.user.v2+msgpack`)
309
- * Server side components
310
- * Reusing model definitions for generating responses?
311
- * Rails responders providing REST operations with integrated ETag,
312
- Modified Headers, conflict detection, ...
313
- * Documentation
314
305
 
315
306
  ## Contributing
316
307
 
@@ -322,14 +313,9 @@ Read [official guide][2] to see to to subscribe.
322
313
  7. Push to the branch (`git push origin my-new-feature`)
323
314
  8. Create new Pull Request
324
315
 
325
- ## Contributors
326
-
327
- * [Nicolas Fricke](https://github.com/nicolas-fricke)
328
- * [Tino Junge](https://github.com/tino-junge)
329
- * [Malte Swart](https://github.com/mswart)
330
316
 
331
317
  ## License
332
318
 
333
319
  MIT License
334
320
 
335
- Copyright (c) 2013 Jan Graichen. MIT license, see LICENSE for more details.
321
+ Copyright (c) 2013-2020 Jan Graichen. MIT license, see LICENSE for more details.
@@ -25,15 +25,11 @@ Gem::Specification.new do |spec|
25
25
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
26
26
  spec.require_paths = %w[lib]
27
27
 
28
- spec.add_runtime_dependency 'actionpack', '>= 4.2'
29
- spec.add_runtime_dependency 'activemodel', '>= 4.2'
30
- spec.add_runtime_dependency 'activesupport', '>= 4.2'
31
- spec.add_runtime_dependency 'multi_json'
32
-
33
- # Bundle update w/o version resolves to 0.3.3 ...
34
- spec.add_runtime_dependency 'typhoeus', '~> 1.0'
35
-
28
+ spec.add_runtime_dependency 'actionpack', '>= 5.2'
29
+ spec.add_runtime_dependency 'activemodel', '>= 5.2'
30
+ spec.add_runtime_dependency 'activesupport', '>= 5.2'
36
31
  spec.add_runtime_dependency 'rack'
32
+ spec.add_runtime_dependency 'typhoeus', '~> 1.0'
37
33
 
38
34
  spec.add_development_dependency 'bundler'
39
35
 
@@ -55,14 +55,14 @@ module Acfs
55
55
  request = ::Typhoeus::Request.new(req.url, **@opts.merge(opts))
56
56
 
57
57
  request.on_complete do |response|
58
- if response.timed_out?
59
- raise ::Acfs::TimeoutError.new(req)
60
- elsif response.code.zero?
58
+ raise ::Acfs::TimeoutError.new(req) if response.timed_out?
59
+
60
+ if response.code.zero?
61
61
  # Failed to get HTTP response
62
62
  raise ::Acfs::RequestError.new(req, response.return_message)
63
- else
64
- req.complete! convert_response(req, response)
65
63
  end
64
+
65
+ req.complete! convert_response(req, response)
66
66
  end
67
67
 
68
68
  request
@@ -68,8 +68,8 @@ module Acfs::Collections
68
68
  def setup_params(params)
69
69
  @current_page = begin
70
70
  Integer params.fetch(:page, 1)
71
- rescue ArgumentError
72
- params[:page]
71
+ rescue ArgumentError
72
+ params[:page]
73
73
  end
74
74
  end
75
75
  end
@@ -26,7 +26,7 @@ module Acfs
26
26
 
27
27
  class TimeoutError < RequestError
28
28
  def initialize(request)
29
- super(request, "Timeout reached")
29
+ super(request, 'Timeout reached')
30
30
  end
31
31
  end
32
32
 
@@ -38,13 +38,13 @@ module Acfs
38
38
  def initialize(opts = {})
39
39
  @response = opts[:response]
40
40
 
41
- if response
42
- message = (opts[:message] ? opts[:message] + ':' : 'Received') +
43
- " #{response.code} for #{response.request.method.upcase}" \
44
- " #{response.request.url} #{response.request.format}"
45
- else
46
- message = opts[:message] || 'Received erroneous response'
47
- end
41
+ message = if response
42
+ (opts[:message] ? opts[:message] + ':' : 'Received') +
43
+ " #{response.code} for #{response.request.method.upcase}" \
44
+ " #{response.request.url} #{response.request.format}"
45
+ else
46
+ opts[:message] || 'Received erroneous response'
47
+ end
48
48
 
49
49
  super opts, message
50
50
  end
@@ -67,11 +67,19 @@ module Acfs
67
67
  end
68
68
  end
69
69
 
70
- # Resource not found error raised on a 404 response
71
- #
72
- class ResourceNotFound < ErroneousResponse
73
- end
70
+ # 400
71
+ class BadRequest < ErroneousResponse; end
72
+
73
+ # 401
74
+ class Unauthorized < ErroneousResponse; end
75
+
76
+ # 403
77
+ class Forbidden < ErroneousResponse; end
74
78
 
79
+ # 404
80
+ class ResourceNotFound < ErroneousResponse; end
81
+
82
+ # 422
75
83
  class InvalidResource < ErroneousResponse
76
84
  attr_reader :errors, :resource
77
85
 
@@ -91,6 +99,18 @@ module Acfs
91
99
  end
92
100
  end
93
101
 
102
+ # 500
103
+ class ServerError < ErroneousResponse; end
104
+
105
+ # 502
106
+ class BadGateway < ErroneousResponse; end
107
+
108
+ # 503
109
+ class ServiceUnavailable < ErroneousResponse; end
110
+
111
+ # 504
112
+ class GatewayTimeout < ErroneousResponse; end
113
+
94
114
  # A ResourceNotLoaded error will be thrown when calling some
95
115
  # modifing methods on not loaded resources as it is usally
96
116
  # unwanted to call e.g. `update_attributes` on a not loaded
@@ -49,7 +49,7 @@ module Acfs
49
49
  def extract_arg(key, hashes)
50
50
  hashes.each_with_index do |hash, index|
51
51
  if hash.key?(key)
52
- return (index == 0 ? hash.delete(key) : hash.fetch(key))
52
+ return (index.zero? ? hash.delete(key) : hash.fetch(key))
53
53
  end
54
54
  end
55
55
 
@@ -72,9 +72,9 @@ module Acfs
72
72
  args.fetch(sym) do
73
73
  if args[:raise].nil? || args[:raise]
74
74
  raise ArgumentError.new "URI path argument `#{sym}' missing on `#{self}'. Given: `#{args}.inspect'"
75
- else
76
- ":#{sym}"
77
75
  end
76
+
77
+ ":#{sym}"
78
78
  end
79
79
  end
80
80
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'multi_json'
3
+ require 'json'
4
4
 
5
5
  module Acfs
6
6
  module Middleware
@@ -12,11 +12,11 @@ module Acfs
12
12
  end
13
13
 
14
14
  def encode(data)
15
- ::MultiJson.dump data
15
+ ::JSON.dump data
16
16
  end
17
17
 
18
18
  def decode(body)
19
- ::MultiJson.load body
19
+ ::JSON.load body
20
20
  end
21
21
  end
22
22
 
@@ -8,6 +8,7 @@ module Acfs
8
8
  #
9
9
  class Operation
10
10
  attr_reader :action, :params, :resource, :data, :callback, :location, :url
11
+
11
12
  delegate :service, to: :resource
12
13
  delegate :call, to: :callback
13
14
 
@@ -71,10 +72,24 @@ module Acfs
71
72
 
72
73
  def handle_failure(response)
73
74
  case response.code
75
+ when 400
76
+ raise ::Acfs::BadRequest.new response: response
77
+ when 401
78
+ raise ::Acfs::Unauthorized.new response: response
79
+ when 403
80
+ raise ::Acfs::Forbidden.new response: response
74
81
  when 404
75
82
  raise ::Acfs::ResourceNotFound.new response: response
76
83
  when 422
77
84
  raise ::Acfs::InvalidResource.new response: response, errors: response.data.try(:[], 'errors')
85
+ when 500
86
+ raise ::Acfs::ServerError.new response: response
87
+ when 502
88
+ raise ::Acfs::BadGateway.new response: response
89
+ when 503
90
+ raise ::Acfs::ServiceUnavailable.new response: response
91
+ when 504
92
+ raise ::Acfs::GatewayTimeout.new response: response
78
93
  else
79
94
  raise ::Acfs::ErroneousResponse.new response: response
80
95
  end
@@ -11,7 +11,6 @@ module Acfs
11
11
  attr_reader :url, :headers, :params, :data, :method, :operation
12
12
 
13
13
  include Request::Callbacks
14
-
15
14
  def initialize(url, options = {}, &block)
16
15
  @url = URI.parse(url.to_s).tap do |_url|
17
16
  @data = options.delete(:data) || nil
@@ -20,7 +19,9 @@ module Acfs
20
19
  @params = options.delete(:params) || {}
21
20
  @method = options.delete(:method) || :get
22
21
  end.to_s
22
+
23
23
  @operation = options.delete(:operation) || nil
24
+
24
25
  on_complete(&block) if block_given?
25
26
  end
26
27
 
@@ -45,9 +45,9 @@ module Acfs
45
45
  private
46
46
 
47
47
  def call_callback(res, index)
48
- if index < callbacks.size
49
- callbacks[index].call res, proc {|bres| call_callback bres, index + 1 }
50
- end
48
+ return if index >= callbacks.size
49
+
50
+ callbacks[index].call(res, proc {|bres| call_callback bres, index + 1 })
51
51
  end
52
52
  end
53
53
  end
@@ -48,9 +48,11 @@ class Acfs::Resource
48
48
  # @return [HashWithIndifferentAccess{Symbol => Object}]
49
49
  # Attributes and their values.
50
50
  #
51
+ # rubocop:disable Naming/MemoizedInstanceVariableName
51
52
  def attributes
52
53
  @_attrs ||= HashWithIndifferentAccess.new
53
54
  end
55
+ # rubocop:enable Naming/MemoizedInstanceVariableName
54
56
 
55
57
  # @api public
56
58
  #
@@ -244,8 +244,6 @@ class Acfs::Resource
244
244
  end
245
245
  end
246
246
 
247
- private
248
-
249
247
  def update_with(data)
250
248
  self.attributes = data
251
249
  loaded!
@@ -258,7 +258,7 @@ class Acfs::Resource
258
258
  end
259
259
 
260
260
  klass
261
- rescue NameError, NoMethodError
261
+ rescue NameError
262
262
  raise Acfs::ResourceTypeError.new type_name: type, base_class: self
263
263
  end
264
264
  end
@@ -40,21 +40,23 @@ module Acfs
40
40
 
41
41
  action = opts[:action] || :list
42
42
 
43
- path = if opts[:path].is_a?(Hash) && opts[:path].key?(action)
44
- opts[:path].fetch(action)
45
- else
46
- path = if opts[:path].is_a?(Hash)
47
- opts[:path][:all].to_s
48
- else
49
- opts[:path].to_s
50
- end
43
+ path = begin
44
+ if opts[:path].is_a?(Hash) && opts[:path].key?(action)
45
+ opts[:path].fetch(action)
46
+ else
47
+ path = if opts[:path].is_a?(Hash)
48
+ opts[:path][:all].to_s
49
+ else
50
+ opts[:path].to_s
51
+ end
51
52
 
52
- if path.blank?
53
- path = (resource_class.name || 'class').pluralize.underscore
54
- end
53
+ if path.blank?
54
+ path = (resource_class.name || 'class').pluralize.underscore
55
+ end
55
56
 
56
- resource_class.location_default_path(action, path.strip)
57
- end
57
+ resource_class.location_default_path(action, path.strip)
58
+ end
59
+ end
58
60
 
59
61
  if path.nil?
60
62
  raise ArgumentError.new "Location for `#{action}' explicit disabled by set to nil."
@@ -87,7 +89,10 @@ module Acfs
87
89
  #
88
90
  def base_url
89
91
  unless (base = Acfs::Configuration.current.locate identity)
90
- raise ArgumentError.new "#{identity} not configured. Add `locate '#{identity.to_s.underscore}', 'http://service.url/'` to your configuration."
92
+ raise ArgumentError.new \
93
+ "#{identity} not configured. Add `locate '" \
94
+ "#{identity.to_s.underscore}', 'http://service.url/'` " \
95
+ 'to your configuration.'
91
96
  end
92
97
 
93
98
  base.to_s
@@ -16,7 +16,7 @@ module Acfs
16
16
  @opts[:with].stringify_keys! if @opts[:with].is_a? Hash
17
17
  @opts[:return].stringify_keys! if @opts[:return].is_a? Hash
18
18
 
19
- if @opts[:return].is_a? Array
19
+ if @opts[:return].is_a?(Array) # rubocop:disable Style/GuardClause
20
20
  @opts[:return].map! {|h| h.stringify_keys! if h.is_a? Hash }
21
21
  end
22
22
  end
@@ -53,9 +53,8 @@ module Acfs
53
53
  end
54
54
 
55
55
  def called?(count = nil)
56
- if count.respond_to? :count
57
- count = count.count
58
- end # For `5.times` Enumerators
56
+ count = count.count if count.respond_to?(:count)
57
+
59
58
  count.nil? ? calls.any? : calls.size == count
60
59
  end
61
60
 
@@ -3,7 +3,7 @@
3
3
  module Acfs
4
4
  module VERSION
5
5
  MAJOR = 1
6
- MINOR = 4
6
+ MINOR = 5
7
7
  PATCH = 0
8
8
  STAGE = nil
9
9
 
@@ -122,8 +122,8 @@ describe ::Acfs::Global do
122
122
 
123
123
  describe '#runner' do
124
124
  it 'returns per-thread runner' do
125
- runner1 = Thread.new { acfs.runner } .value
126
- runner2 = Thread.new { acfs.runner } .value
125
+ runner1 = Thread.new { acfs.runner }.value
126
+ runner2 = Thread.new { acfs.runner }.value
127
127
 
128
128
  expect(runner1).to_not equal runner2
129
129
  end
@@ -47,7 +47,7 @@ describe Acfs::Middleware::JSON do
47
47
  let(:body) { data.to_json[4..-4] }
48
48
 
49
49
  it 'should raise an error' do
50
- expect { request.complete! response }.to raise_error(MultiJson::LoadError)
50
+ expect { request.complete! response }.to raise_error(::JSON::ParserError)
51
51
  end
52
52
  end
53
53
 
@@ -35,7 +35,7 @@ describe Acfs::Resource::Attributes::Float do
35
35
 
36
36
  context 'with -Infinity' do
37
37
  let(:value) { '-Infinity' }
38
- it { expect(subject.call).to eq -::Float::INFINITY }
38
+ it { expect(subject.call).to eq(-::Float::INFINITY) }
39
39
  end
40
40
 
41
41
  context 'with NaN' do
@@ -85,11 +85,9 @@ describe Acfs::Resource::Attributes do
85
85
 
86
86
  it do
87
87
  expect do
88
- begin
89
- subject.call
90
- rescue StandardError
91
- true
92
- end
88
+ subject.call
89
+ rescue StandardError
90
+ true
93
91
  end.to_not change(m, :attributes)
94
92
  end
95
93
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-12 00:00:00.000000000 Z
11
+ date: 2020-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -16,44 +16,44 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '5.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4.2'
26
+ version: '5.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activemodel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '4.2'
33
+ version: '5.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '4.2'
40
+ version: '5.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: activesupport
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '4.2'
47
+ version: '5.2'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '4.2'
54
+ version: '5.2'
55
55
  - !ruby/object:Gem::Dependency
56
- name: multi_json
56
+ name: rack
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.0'
83
- - !ruby/object:Gem::Dependency
84
- name: rack
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: bundler
99
85
  requirement: !ruby/object:Gem::Requirement