acfs 1.3.1 → 1.5.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 +4 -4
- data/CHANGELOG.md +41 -1
- data/README.md +10 -25
- data/acfs.gemspec +20 -15
- data/lib/acfs.rb +2 -0
- data/lib/acfs/adapter/base.rb +6 -8
- data/lib/acfs/adapter/typhoeus.rb +25 -6
- data/lib/acfs/collection.rb +2 -1
- data/lib/acfs/collections/paginatable.rb +4 -3
- data/lib/acfs/configuration.rb +14 -7
- data/lib/acfs/errors.rb +60 -19
- data/lib/acfs/global.rb +12 -2
- data/lib/acfs/location.rb +9 -5
- data/lib/acfs/middleware/base.rb +5 -1
- data/lib/acfs/middleware/json.rb +5 -3
- data/lib/acfs/middleware/logger.rb +2 -0
- data/lib/acfs/middleware/msgpack.rb +2 -0
- data/lib/acfs/middleware/print.rb +2 -0
- data/lib/acfs/middleware/serializer.rb +2 -0
- data/lib/acfs/operation.rb +20 -3
- data/lib/acfs/request.rb +5 -1
- data/lib/acfs/request/callbacks.rb +5 -1
- data/lib/acfs/resource.rb +2 -0
- data/lib/acfs/resource/attributes.rb +5 -2
- data/lib/acfs/resource/attributes/base.rb +2 -1
- data/lib/acfs/resource/attributes/boolean.rb +2 -0
- data/lib/acfs/resource/attributes/date_time.rb +2 -1
- data/lib/acfs/resource/attributes/dict.rb +2 -0
- data/lib/acfs/resource/attributes/float.rb +5 -3
- data/lib/acfs/resource/attributes/integer.rb +2 -0
- data/lib/acfs/resource/attributes/list.rb +2 -0
- data/lib/acfs/resource/attributes/string.rb +2 -0
- data/lib/acfs/resource/attributes/uuid.rb +4 -3
- data/lib/acfs/resource/dirty.rb +2 -0
- data/lib/acfs/resource/initialization.rb +2 -0
- data/lib/acfs/resource/loadable.rb +2 -0
- data/lib/acfs/resource/locatable.rb +10 -6
- data/lib/acfs/resource/operational.rb +2 -1
- data/lib/acfs/resource/persistence.rb +7 -6
- data/lib/acfs/resource/query_methods.rb +6 -4
- data/lib/acfs/resource/service.rb +3 -1
- data/lib/acfs/resource/validation.rb +3 -1
- data/lib/acfs/response.rb +2 -0
- data/lib/acfs/response/formats.rb +2 -0
- data/lib/acfs/response/status.rb +3 -1
- data/lib/acfs/rspec.rb +2 -0
- data/lib/acfs/runner.rb +6 -1
- data/lib/acfs/service.rb +24 -13
- data/lib/acfs/service/middleware.rb +2 -0
- data/lib/acfs/service/middleware/stack.rb +5 -3
- data/lib/acfs/singleton_resource.rb +4 -2
- data/lib/acfs/stub.rb +32 -11
- data/lib/acfs/util.rb +2 -0
- data/lib/acfs/version.rb +4 -2
- data/lib/acfs/yard.rb +1 -0
- data/spec/acfs/adapter/typhoeus_spec.rb +30 -3
- data/spec/acfs/collection_spec.rb +7 -5
- data/spec/acfs/configuration_spec.rb +2 -0
- data/spec/acfs/global_spec.rb +50 -3
- data/spec/acfs/location_spec.rb +2 -0
- data/spec/acfs/middleware/json_spec.rb +3 -1
- data/spec/acfs/middleware/msgpack_spec.rb +2 -0
- data/spec/acfs/operation_spec.rb +2 -0
- data/spec/acfs/request/callbacks_spec.rb +2 -0
- data/spec/acfs/request_spec.rb +3 -1
- data/spec/acfs/resource/attributes/boolean_spec.rb +2 -0
- data/spec/acfs/resource/attributes/date_time_spec.rb +2 -0
- data/spec/acfs/resource/attributes/dict_spec.rb +4 -2
- data/spec/acfs/resource/attributes/float_spec.rb +3 -1
- data/spec/acfs/resource/attributes/integer_spec.rb +2 -0
- data/spec/acfs/resource/attributes/list_spec.rb +5 -3
- data/spec/acfs/resource/attributes/uuid_spec.rb +2 -0
- data/spec/acfs/resource/attributes_spec.rb +8 -8
- data/spec/acfs/resource/dirty_spec.rb +2 -0
- data/spec/acfs/resource/initialization_spec.rb +8 -2
- data/spec/acfs/resource/loadable_spec.rb +2 -0
- data/spec/acfs/resource/locatable_spec.rb +2 -0
- data/spec/acfs/resource/persistance_spec.rb +10 -4
- data/spec/acfs/resource/query_methods_spec.rb +24 -17
- data/spec/acfs/resource/validation_spec.rb +2 -0
- data/spec/acfs/response/formats_spec.rb +3 -1
- data/spec/acfs/response/status_spec.rb +2 -0
- data/spec/acfs/runner_spec.rb +6 -8
- data/spec/acfs/service/middleware_spec.rb +2 -0
- data/spec/acfs/service_spec.rb +3 -1
- data/spec/acfs/singleton_resource_spec.rb +2 -0
- data/spec/acfs/stub_spec.rb +2 -0
- data/spec/acfs_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/support/hash.rb +2 -0
- data/spec/support/response.rb +2 -0
- data/spec/support/service.rb +1 -0
- data/spec/support/shared/find_callbacks.rb +2 -0
- metadata +13 -28
data/lib/acfs/global.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
#
|
3
5
|
# Global Acfs module methods.
|
@@ -73,7 +75,7 @@ module Acfs
|
|
73
75
|
end
|
74
76
|
return false if block.nil?
|
75
77
|
|
76
|
-
if resource.loaded?
|
78
|
+
if resource.nil? || resource.loaded?
|
77
79
|
block.call resource
|
78
80
|
else
|
79
81
|
resource.__callbacks__ << block
|
@@ -81,9 +83,17 @@ module Acfs
|
|
81
83
|
end
|
82
84
|
|
83
85
|
def on(*resources)
|
86
|
+
# If all resources have already been loaded, we run the callback immediately.
|
87
|
+
if resources.all? {|res| res.nil? || res.loaded? }
|
88
|
+
yield(*resources)
|
89
|
+
return
|
90
|
+
end
|
91
|
+
|
92
|
+
# Otherwise, we add a callback to *each* resource with a guard that ensures
|
93
|
+
# that only the very last resource being loaded executes the callback.
|
84
94
|
resources.each do |resource|
|
85
95
|
add_callback resource do |_|
|
86
|
-
yield(*resources)
|
96
|
+
yield(*resources) if resources.all? {|res| res.nil? || res.loaded? }
|
87
97
|
end
|
88
98
|
end
|
89
99
|
end
|
data/lib/acfs/location.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
# @api private
|
3
5
|
#
|
@@ -6,7 +8,7 @@ module Acfs
|
|
6
8
|
class Location
|
7
9
|
attr_reader :arguments, :raw, :struct, :args
|
8
10
|
|
9
|
-
REGEXP = /^:([A-z][A-z0-9_]*)
|
11
|
+
REGEXP = /^:([A-z][A-z0-9_]*)$/.freeze
|
10
12
|
|
11
13
|
def initialize(uri, args = {})
|
12
14
|
@raw = URI.parse uri
|
@@ -40,13 +42,15 @@ module Acfs
|
|
40
42
|
def raw_uri
|
41
43
|
raw.to_s
|
42
44
|
end
|
43
|
-
|
45
|
+
alias to_s raw_uri
|
44
46
|
|
45
47
|
private
|
46
48
|
|
47
49
|
def extract_arg(key, hashes)
|
48
50
|
hashes.each_with_index do |hash, index|
|
49
|
-
|
51
|
+
if hash.key?(key)
|
52
|
+
return (index.zero? ? hash.delete(key) : hash.fetch(key))
|
53
|
+
end
|
50
54
|
end
|
51
55
|
|
52
56
|
nil
|
@@ -68,9 +72,9 @@ module Acfs
|
|
68
72
|
args.fetch(sym) do
|
69
73
|
if args[:raise].nil? || args[:raise]
|
70
74
|
raise ArgumentError.new "URI path argument `#{sym}' missing on `#{self}'. Given: `#{args}.inspect'"
|
71
|
-
else
|
72
|
-
":#{sym}"
|
73
75
|
end
|
76
|
+
|
77
|
+
":#{sym}"
|
74
78
|
end
|
75
79
|
end
|
76
80
|
end
|
data/lib/acfs/middleware/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
module Middleware
|
3
5
|
# A base middleware that does not modify request or response.
|
@@ -12,7 +14,9 @@ module Acfs
|
|
12
14
|
end
|
13
15
|
|
14
16
|
def call(request)
|
15
|
-
|
17
|
+
if respond_to? :response
|
18
|
+
request.on_complete {|res, nxt| response(res, nxt) }
|
19
|
+
end
|
16
20
|
app.call(request)
|
17
21
|
end
|
18
22
|
end
|
data/lib/acfs/middleware/json.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
2
4
|
|
3
5
|
module Acfs
|
4
6
|
module Middleware
|
@@ -10,11 +12,11 @@ module Acfs
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def encode(data)
|
13
|
-
::
|
15
|
+
::JSON.dump data
|
14
16
|
end
|
15
17
|
|
16
18
|
def decode(body)
|
17
|
-
::
|
19
|
+
::JSON.load body
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
data/lib/acfs/operation.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
# @api private
|
3
5
|
#
|
@@ -6,6 +8,7 @@ module Acfs
|
|
6
8
|
#
|
7
9
|
class Operation
|
8
10
|
attr_reader :action, :params, :resource, :data, :callback, :location, :url
|
11
|
+
|
9
12
|
delegate :service, to: :resource
|
10
13
|
delegate :call, to: :callback
|
11
14
|
|
@@ -19,7 +22,7 @@ module Acfs
|
|
19
22
|
@data = (opts[:data] || {}).dup
|
20
23
|
|
21
24
|
if opts[:url]
|
22
|
-
@url
|
25
|
+
@url = opts[:url]
|
23
26
|
else
|
24
27
|
@location = resource.location(action: @action).extract_from(@params, @data)
|
25
28
|
@url = location.str
|
@@ -29,11 +32,11 @@ module Acfs
|
|
29
32
|
end
|
30
33
|
|
31
34
|
def single?
|
32
|
-
[
|
35
|
+
%i[read update delete].include? action
|
33
36
|
end
|
34
37
|
|
35
38
|
def synchronous?
|
36
|
-
[
|
39
|
+
%i[update delete create].include? action
|
37
40
|
end
|
38
41
|
|
39
42
|
def id
|
@@ -69,10 +72,24 @@ module Acfs
|
|
69
72
|
|
70
73
|
def handle_failure(response)
|
71
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
|
72
81
|
when 404
|
73
82
|
raise ::Acfs::ResourceNotFound.new response: response
|
74
83
|
when 422
|
75
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
|
76
93
|
else
|
77
94
|
raise ::Acfs::ErroneousResponse.new response: response
|
78
95
|
end
|
data/lib/acfs/request.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'acfs/request/callbacks'
|
2
4
|
|
3
5
|
module Acfs
|
@@ -9,7 +11,6 @@ module Acfs
|
|
9
11
|
attr_reader :url, :headers, :params, :data, :method, :operation
|
10
12
|
|
11
13
|
include Request::Callbacks
|
12
|
-
|
13
14
|
def initialize(url, options = {}, &block)
|
14
15
|
@url = URI.parse(url.to_s).tap do |_url|
|
15
16
|
@data = options.delete(:data) || nil
|
@@ -18,7 +19,9 @@ module Acfs
|
|
18
19
|
@params = options.delete(:params) || {}
|
19
20
|
@method = options.delete(:method) || :get
|
20
21
|
end.to_s
|
22
|
+
|
21
23
|
@operation = options.delete(:operation) || nil
|
24
|
+
|
22
25
|
on_complete(&block) if block_given?
|
23
26
|
end
|
24
27
|
|
@@ -29,6 +32,7 @@ module Acfs
|
|
29
32
|
class << self
|
30
33
|
def new(*attrs)
|
31
34
|
return attrs[0] if attrs[0].is_a? self
|
35
|
+
|
32
36
|
super
|
33
37
|
end
|
34
38
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
class Request
|
3
5
|
# Module containing callback handling for Requests.
|
@@ -43,7 +45,9 @@ module Acfs
|
|
43
45
|
private
|
44
46
|
|
45
47
|
def call_callback(res, index)
|
46
|
-
|
48
|
+
return if index >= callbacks.size
|
49
|
+
|
50
|
+
callbacks[index].call(res, proc {|bres| call_callback bres, index + 1 })
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
data/lib/acfs/resource.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Acfs::Resource
|
2
4
|
#
|
3
5
|
# = Acfs Attributes
|
@@ -46,9 +48,11 @@ class Acfs::Resource
|
|
46
48
|
# @return [HashWithIndifferentAccess{Symbol => Object}]
|
47
49
|
# Attributes and their values.
|
48
50
|
#
|
51
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
49
52
|
def attributes
|
50
53
|
@_attrs ||= HashWithIndifferentAccess.new
|
51
54
|
end
|
55
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
52
56
|
|
53
57
|
# @api public
|
54
58
|
#
|
@@ -176,9 +180,8 @@ class Acfs::Resource
|
|
176
180
|
attributes[name.to_s] = value
|
177
181
|
end
|
178
182
|
|
179
|
-
#
|
180
183
|
module ClassMethods
|
181
|
-
ATTR_CLASS_BASE = '::Acfs::Resource::Attributes'
|
184
|
+
ATTR_CLASS_BASE = '::Acfs::Resource::Attributes'
|
182
185
|
|
183
186
|
#
|
184
187
|
# @api public
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs::Resource::Attributes
|
2
4
|
# @api public
|
3
5
|
#
|
@@ -21,9 +23,9 @@ module Acfs::Resource::Attributes
|
|
21
23
|
|
22
24
|
case value
|
23
25
|
when ::Float then value
|
24
|
-
when
|
25
|
-
when
|
26
|
-
when
|
26
|
+
when 'Infinity' then ::Float::INFINITY
|
27
|
+
when '-Infinity' then -::Float::INFINITY
|
28
|
+
when 'NaN' then ::Float::NAN
|
27
29
|
else Float(value)
|
28
30
|
end
|
29
31
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs::Resource::Attributes
|
2
4
|
# @api public
|
3
5
|
#
|
@@ -9,8 +11,7 @@ module Acfs::Resource::Attributes
|
|
9
11
|
# end
|
10
12
|
#
|
11
13
|
class UUID < Base
|
12
|
-
|
13
|
-
UUID_REGEXP = /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/i
|
14
|
+
UUID_REGEXP = /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/i.freeze
|
14
15
|
|
15
16
|
# @api public
|
16
17
|
#
|
@@ -37,7 +38,7 @@ module Acfs::Resource::Attributes
|
|
37
38
|
elsif value.to_s =~ UUID_REGEXP
|
38
39
|
value
|
39
40
|
else
|
40
|
-
raise TypeError.new "Invalid UUID: `#{value
|
41
|
+
raise TypeError.new "Invalid UUID: `#{value}'"
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
data/lib/acfs/resource/dirty.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Acfs::Resource
|
2
4
|
# Provide methods for generation URLs for resources.
|
3
5
|
#
|
@@ -11,7 +13,6 @@ class Acfs::Resource
|
|
11
13
|
module Locatable
|
12
14
|
extend ActiveSupport::Concern
|
13
15
|
|
14
|
-
#
|
15
16
|
module ClassMethods
|
16
17
|
# @overload url(suffix)
|
17
18
|
# @deprecated
|
@@ -40,7 +41,10 @@ class Acfs::Resource
|
|
40
41
|
# @return [String] Generated URL.
|
41
42
|
#
|
42
43
|
def url(suffix = nil, opts = {})
|
43
|
-
|
44
|
+
if suffix.is_a? Hash
|
45
|
+
opts = suffix
|
46
|
+
suffix = nil
|
47
|
+
end
|
44
48
|
|
45
49
|
opts[:action] = :list if suffix
|
46
50
|
|
@@ -85,9 +89,9 @@ class Acfs::Resource
|
|
85
89
|
def location_default_path(action, path)
|
86
90
|
case action
|
87
91
|
when :list, :create
|
88
|
-
|
92
|
+
path
|
89
93
|
when :read, :update, :delete
|
90
|
-
|
94
|
+
"#{path}/:id"
|
91
95
|
end
|
92
96
|
end
|
93
97
|
end
|
@@ -109,8 +113,8 @@ class Acfs::Resource
|
|
109
113
|
return nil if need_primary_key? && !primary_key?
|
110
114
|
|
111
115
|
self.class.service
|
112
|
-
|
113
|
-
|
116
|
+
.location(self.class, opts.reverse_merge(action: :read))
|
117
|
+
.build(attributes).str
|
114
118
|
end
|
115
119
|
|
116
120
|
# @api private
|