acfs 1.4.0 → 1.7.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 +26 -0
- data/README.md +22 -39
- data/acfs.gemspec +8 -14
- data/lib/acfs/adapter/base.rb +2 -0
- data/lib/acfs/adapter/typhoeus.rb +16 -11
- data/lib/acfs/collections/paginatable.rb +1 -1
- data/lib/acfs/configuration.rb +13 -3
- data/lib/acfs/errors.rb +41 -21
- data/lib/acfs/global.rb +2 -2
- data/lib/acfs/location.rb +26 -32
- data/lib/acfs/middleware/base.rb +2 -2
- data/lib/acfs/middleware/json.rb +4 -2
- data/lib/acfs/middleware/logger.rb +4 -6
- data/lib/acfs/middleware/serializer.rb +1 -1
- data/lib/acfs/operation.rb +21 -8
- data/lib/acfs/request/callbacks.rb +4 -4
- data/lib/acfs/request.rb +4 -11
- data/lib/acfs/resource/attributes/date_time.rb +1 -1
- data/lib/acfs/resource/attributes/uuid.rb +1 -1
- data/lib/acfs/resource/attributes.rb +16 -15
- data/lib/acfs/resource/dirty.rb +2 -2
- data/lib/acfs/resource/initialization.rb +5 -5
- data/lib/acfs/resource/locatable.rb +11 -8
- data/lib/acfs/resource/operational.rb +6 -3
- data/lib/acfs/resource/persistence.rb +13 -15
- data/lib/acfs/resource/query_methods.rb +10 -10
- data/lib/acfs/resource/service.rb +2 -2
- data/lib/acfs/resource/validation.rb +17 -7
- data/lib/acfs/response.rb +5 -5
- data/lib/acfs/runner.rb +15 -15
- data/lib/acfs/service.rb +16 -19
- data/lib/acfs/singleton_resource.rb +2 -2
- data/lib/acfs/stub.rb +41 -31
- data/lib/acfs/version.rb +2 -2
- data/spec/acfs/adapter/typhoeus_spec.rb +2 -2
- data/spec/acfs/collection_spec.rb +66 -41
- data/spec/acfs/configuration_spec.rb +22 -12
- data/spec/acfs/global_spec.rb +11 -9
- data/spec/acfs/location_spec.rb +2 -2
- data/spec/acfs/middleware/json_spec.rb +22 -8
- data/spec/acfs/middleware/{msgpack_spec.rb → message_pack_spec.rb} +6 -6
- data/spec/acfs/operation_spec.rb +3 -2
- data/spec/acfs/request/callbacks_spec.rb +19 -10
- data/spec/acfs/request_spec.rb +16 -20
- data/spec/acfs/resource/attributes/boolean_spec.rb +32 -32
- data/spec/acfs/resource/attributes/date_time_spec.rb +16 -8
- data/spec/acfs/resource/attributes/dict_spec.rb +15 -9
- data/spec/acfs/resource/attributes/float_spec.rb +20 -10
- data/spec/acfs/resource/attributes/integer_spec.rb +10 -5
- data/spec/acfs/resource/attributes/list_spec.rb +13 -8
- data/spec/acfs/resource/attributes/uuid_spec.rb +12 -6
- data/spec/acfs/resource/attributes_spec.rb +37 -38
- data/spec/acfs/resource/dirty_spec.rb +6 -3
- data/spec/acfs/resource/initialization_spec.rb +4 -5
- data/spec/acfs/resource/loadable_spec.rb +3 -1
- data/spec/acfs/resource/locatable_spec.rb +24 -18
- data/spec/acfs/resource/{persistance_spec.rb → persistence_spec.rb} +122 -90
- data/spec/acfs/resource/query_methods_spec.rb +143 -110
- data/spec/acfs/resource/validation_spec.rb +34 -27
- data/spec/acfs/response/formats_spec.rb +8 -8
- data/spec/acfs/response/status_spec.rb +16 -9
- data/spec/acfs/runner_spec.rb +10 -8
- data/spec/acfs/service/middleware_spec.rb +3 -3
- data/spec/acfs/service_spec.rb +6 -5
- data/spec/acfs/singleton_resource_spec.rb +2 -1
- data/spec/acfs/stub_spec.rb +57 -53
- data/spec/acfs_spec.rb +111 -93
- data/spec/spec_helper.rb +1 -2
- data/spec/support/response.rb +2 -2
- data/spec/support/service.rb +1 -1
- data/spec/support/shared/find_callbacks.rb +14 -10
- metadata +30 -29
data/lib/acfs/operation.rb
CHANGED
@@ -8,10 +8,11 @@ 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
|
|
14
|
-
def initialize(resource, action, opts
|
15
|
+
def initialize(resource, action, **opts, &block)
|
15
16
|
@resource = resource
|
16
17
|
@action = action.to_sym
|
17
18
|
|
@@ -20,9 +21,7 @@ module Acfs
|
|
20
21
|
@params = (opts[:params] || {}).dup
|
21
22
|
@data = (opts[:data] || {}).dup
|
22
23
|
|
23
|
-
|
24
|
-
@url = opts[:url]
|
25
|
-
else
|
24
|
+
unless (@url = opts[:url])
|
26
25
|
@location = resource.location(action: @action).extract_from(@params, @data)
|
27
26
|
@url = location.str
|
28
27
|
end
|
@@ -44,11 +43,11 @@ module Acfs
|
|
44
43
|
end
|
45
44
|
|
46
45
|
def full_params
|
47
|
-
(id ? params.merge(id: id) : params).merge
|
46
|
+
(id ? params.merge(id: id) : params).merge(location_vars)
|
48
47
|
end
|
49
48
|
|
50
|
-
def
|
51
|
-
location ? location.
|
49
|
+
def location_vars
|
50
|
+
location ? location.vars : {}
|
52
51
|
end
|
53
52
|
|
54
53
|
def method
|
@@ -57,7 +56,7 @@ module Acfs
|
|
57
56
|
|
58
57
|
def request
|
59
58
|
request = ::Acfs::Request.new url, method: method, params: params,
|
60
|
-
|
59
|
+
data: data, operation: self
|
61
60
|
request.on_complete do |response|
|
62
61
|
::ActiveSupport::Notifications.instrument 'acfs.operation.complete',
|
63
62
|
operation: self,
|
@@ -71,10 +70,24 @@ module Acfs
|
|
71
70
|
|
72
71
|
def handle_failure(response)
|
73
72
|
case response.code
|
73
|
+
when 400
|
74
|
+
raise ::Acfs::BadRequest.new response: response
|
75
|
+
when 401
|
76
|
+
raise ::Acfs::Unauthorized.new response: response
|
77
|
+
when 403
|
78
|
+
raise ::Acfs::Forbidden.new response: response
|
74
79
|
when 404
|
75
80
|
raise ::Acfs::ResourceNotFound.new response: response
|
76
81
|
when 422
|
77
82
|
raise ::Acfs::InvalidResource.new response: response, errors: response.data.try(:[], 'errors')
|
83
|
+
when 500
|
84
|
+
raise ::Acfs::ServerError.new response: response
|
85
|
+
when 502
|
86
|
+
raise ::Acfs::BadGateway.new response: response
|
87
|
+
when 503
|
88
|
+
raise ::Acfs::ServiceUnavailable.new response: response
|
89
|
+
when 504
|
90
|
+
raise ::Acfs::GatewayTimeout.new response: response
|
78
91
|
else
|
79
92
|
raise ::Acfs::ErroneousResponse.new response: response
|
80
93
|
end
|
@@ -21,7 +21,7 @@ module Acfs
|
|
21
21
|
# @return [ Acfs::Request ] The request itself.
|
22
22
|
#
|
23
23
|
def on_complete(&block)
|
24
|
-
callbacks.insert 0, block if
|
24
|
+
callbacks.insert 0, block if block
|
25
25
|
self
|
26
26
|
end
|
27
27
|
|
@@ -45,9 +45,9 @@ module Acfs
|
|
45
45
|
private
|
46
46
|
|
47
47
|
def call_callback(res, index)
|
48
|
-
if index
|
49
|
-
|
50
|
-
|
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
|
data/lib/acfs/request.rb
CHANGED
@@ -11,8 +11,7 @@ module Acfs
|
|
11
11
|
attr_reader :url, :headers, :params, :data, :method, :operation
|
12
12
|
|
13
13
|
include Request::Callbacks
|
14
|
-
|
15
|
-
def initialize(url, options = {}, &block)
|
14
|
+
def initialize(url, **options, &block)
|
16
15
|
@url = URI.parse(url.to_s).tap do |_url|
|
17
16
|
@data = options.delete(:data) || nil
|
18
17
|
@format = options.delete(:format) || :json
|
@@ -20,20 +19,14 @@ 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
|
25
26
|
end
|
26
27
|
|
27
28
|
def data?
|
28
29
|
!data.nil?
|
29
30
|
end
|
30
|
-
|
31
|
-
class << self
|
32
|
-
def new(*attrs)
|
33
|
-
return attrs[0] if attrs[0].is_a? self
|
34
|
-
|
35
|
-
super
|
36
|
-
end
|
37
|
-
end
|
38
31
|
end
|
39
32
|
end
|
@@ -22,7 +22,7 @@ module Acfs::Resource::Attributes
|
|
22
22
|
def cast_value(value)
|
23
23
|
if value.blank?
|
24
24
|
nil
|
25
|
-
elsif value.
|
25
|
+
elsif !value.is_a?(::String) && value.respond_to?(:to_datetime)
|
26
26
|
value.to_datetime
|
27
27
|
else
|
28
28
|
::DateTime.iso8601 value
|
@@ -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
|
#
|
@@ -66,7 +68,7 @@ class Acfs::Resource
|
|
66
68
|
# @see #write_attributes Delegates attributes hash to {#write_attributes}.
|
67
69
|
#
|
68
70
|
def attributes=(attributes)
|
69
|
-
write_attributes
|
71
|
+
write_attributes(attributes)
|
70
72
|
end
|
71
73
|
|
72
74
|
# @api public
|
@@ -101,17 +103,16 @@ class Acfs::Resource
|
|
101
103
|
#
|
102
104
|
# @see #write_attribute Delegates attribute values to `#write_attribute`.
|
103
105
|
#
|
104
|
-
def write_attributes(attributes, opts
|
106
|
+
def write_attributes(attributes, **opts)
|
105
107
|
unless attributes.respond_to?(:each) && attributes.respond_to?(:keys)
|
106
108
|
return false
|
107
109
|
end
|
108
110
|
|
109
|
-
if opts.fetch(:unknown, :ignore) == :raise
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
111
|
+
if opts.fetch(:unknown, :ignore) == :raise &&
|
112
|
+
(attributes.keys.map(&:to_s) - self.class.attributes.keys).any?
|
113
|
+
missing = attributes.keys - self.class.attributes.keys
|
114
|
+
missing.map!(&:inspect)
|
115
|
+
raise ArgumentError.new "Unknown attributes: #{missing.join(', ')}"
|
115
116
|
end
|
116
117
|
|
117
118
|
procs = {}
|
@@ -120,12 +121,12 @@ class Acfs::Resource
|
|
120
121
|
if attributes[key].is_a? Proc
|
121
122
|
procs[key] = attributes[key]
|
122
123
|
else
|
123
|
-
write_local_attribute
|
124
|
+
write_local_attribute(key, attributes[key], **opts)
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
127
128
|
procs.each do |key, proc|
|
128
|
-
write_local_attribute
|
129
|
+
write_local_attribute(key, instance_exec(&proc), **opts)
|
129
130
|
end
|
130
131
|
|
131
132
|
true
|
@@ -199,12 +200,12 @@ class Acfs::Resource
|
|
199
200
|
# @param [Symbol, String, Class] type Attribute
|
200
201
|
# type identifier or type class.
|
201
202
|
#
|
202
|
-
def attribute(name, type, opts
|
203
|
+
def attribute(name, type, **opts)
|
203
204
|
if type.is_a?(Symbol) || type.is_a?(String)
|
204
205
|
type = "#{ATTR_CLASS_BASE}::#{type.to_s.classify}".constantize
|
205
206
|
end
|
206
207
|
|
207
|
-
define_attribute
|
208
|
+
define_attribute(name.to_sym, type, **opts)
|
208
209
|
end
|
209
210
|
|
210
211
|
# @api public
|
@@ -242,9 +243,9 @@ class Acfs::Resource
|
|
242
243
|
@local_attributes ||= {}
|
243
244
|
end
|
244
245
|
|
245
|
-
def define_attribute(name, type, opts
|
246
|
+
def define_attribute(name, type, **opts)
|
246
247
|
name = name.to_s
|
247
|
-
attribute = type.new
|
248
|
+
attribute = type.new(**opts)
|
248
249
|
|
249
250
|
local_attributes[name] = attribute
|
250
251
|
define_attribute_method name
|
@@ -263,7 +264,7 @@ end
|
|
263
264
|
|
264
265
|
# Load attribute type classes.
|
265
266
|
#
|
266
|
-
Dir[File.
|
267
|
+
Dir[File.join(__dir__, 'attributes/*.rb')].sort.each do |path|
|
267
268
|
filename = File.basename(path)
|
268
269
|
require "acfs/resource/attributes/#{filename}"
|
269
270
|
end
|
data/lib/acfs/resource/dirty.rb
CHANGED
@@ -8,7 +8,7 @@ class Acfs::Resource
|
|
8
8
|
#
|
9
9
|
# @api public
|
10
10
|
#
|
11
|
-
# Initializes a new model with the given `params`.
|
11
|
+
# Initializes a new model with the given `params`.
|
12
12
|
#
|
13
13
|
# @example
|
14
14
|
# class User < Acfs::Resource
|
@@ -17,15 +17,15 @@ class Acfs::Resource
|
|
17
17
|
# attribute :age, :integer, default: 18
|
18
18
|
# end
|
19
19
|
#
|
20
|
-
# user = User.new(name: 'bob')
|
20
|
+
# user = User.new({name: 'bob'})
|
21
21
|
# user.name # => "bob"
|
22
22
|
# user.email # => "bob@dom.tld"
|
23
23
|
# user.age # => 18
|
24
24
|
#
|
25
|
-
# @param
|
25
|
+
# @param attributes [Hash{Symbol => Object}] Attributes to set on resource.
|
26
26
|
#
|
27
|
-
def initialize(
|
28
|
-
write_attributes
|
27
|
+
def initialize(attributes = {})
|
28
|
+
write_attributes(attributes) if attributes
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -40,15 +40,18 @@ class Acfs::Resource
|
|
40
40
|
# usually `:list`, `:create`, `:read`, `:update` or`:delete`.
|
41
41
|
# @return [String] Generated URL.
|
42
42
|
#
|
43
|
-
def url(suffix = nil, opts
|
43
|
+
def url(suffix = nil, **opts)
|
44
44
|
if suffix.is_a? Hash
|
45
45
|
opts = suffix
|
46
46
|
suffix = nil
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
kwargs = {}
|
50
|
+
kwargs[:path] = opts[:path] if opts.key?(:path)
|
51
|
+
kwargs[:action] = opts.delete(:action) if opts.key?(:action)
|
52
|
+
kwargs[:action] = :list if suffix
|
50
53
|
|
51
|
-
url = location(
|
54
|
+
url = location(**kwargs).build(opts.stringify_keys).str
|
52
55
|
url += "/#{suffix}" if suffix.to_s.present?
|
53
56
|
url
|
54
57
|
end
|
@@ -81,8 +84,8 @@ class Acfs::Resource
|
|
81
84
|
#
|
82
85
|
# @return [Location] Location object.
|
83
86
|
#
|
84
|
-
def location(opts
|
85
|
-
service.location(self, opts)
|
87
|
+
def location(**opts)
|
88
|
+
service.location(self, **opts)
|
86
89
|
end
|
87
90
|
|
88
91
|
# @api private
|
@@ -109,12 +112,12 @@ class Acfs::Resource
|
|
109
112
|
# @return [ String ] Generated URL.
|
110
113
|
# @see ClassMethods#url
|
111
114
|
#
|
112
|
-
def url(opts
|
115
|
+
def url(**opts)
|
113
116
|
return nil if need_primary_key? && !primary_key?
|
114
117
|
|
115
118
|
self.class.service
|
116
|
-
|
117
|
-
|
119
|
+
.location(self.class, **opts, action: :read)
|
120
|
+
.build(attributes).str
|
118
121
|
end
|
119
122
|
|
120
123
|
# @api private
|
@@ -11,12 +11,15 @@ class Acfs::Resource
|
|
11
11
|
#
|
12
12
|
module Operational
|
13
13
|
extend ActiveSupport::Concern
|
14
|
-
|
14
|
+
|
15
|
+
def operation(*args, **kwargs, &block)
|
16
|
+
self.class.operation(*args, **kwargs, &block)
|
17
|
+
end
|
15
18
|
|
16
19
|
module ClassMethods
|
17
20
|
# Invoke CRUD operation.
|
18
|
-
def operation(action, opts
|
19
|
-
Acfs.runner.process ::Acfs::Operation.new
|
21
|
+
def operation(action, **opts, &block)
|
22
|
+
Acfs.runner.process ::Acfs::Operation.new(self, action, **opts, &block)
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
@@ -57,8 +57,8 @@ class Acfs::Resource
|
|
57
57
|
# false otherwise.
|
58
58
|
# @see #save! See {#save!} for available options.
|
59
59
|
#
|
60
|
-
def save(
|
61
|
-
save!(
|
60
|
+
def save(**opts)
|
61
|
+
save!(**opts)
|
62
62
|
true
|
63
63
|
rescue Acfs::Error
|
64
64
|
false
|
@@ -82,10 +82,10 @@ class Acfs::Resource
|
|
82
82
|
#
|
83
83
|
# @see #save
|
84
84
|
#
|
85
|
-
def save!(opts
|
85
|
+
def save!(**opts)
|
86
86
|
opts[:data] = attributes unless opts[:data]
|
87
87
|
|
88
|
-
operation((new? ? :create : :update), opts) do |data|
|
88
|
+
operation((new? ? :create : :update), **opts) do |data|
|
89
89
|
update_with data
|
90
90
|
end
|
91
91
|
rescue ::Acfs::InvalidResource => e
|
@@ -109,11 +109,11 @@ class Acfs::Resource
|
|
109
109
|
# @see #attributes=
|
110
110
|
# @see #update_attributes!
|
111
111
|
#
|
112
|
-
def update_attributes(attrs, opts
|
113
|
-
check_loaded!
|
112
|
+
def update_attributes(attrs, **opts)
|
113
|
+
check_loaded!(**opts)
|
114
114
|
|
115
115
|
self.attributes = attrs
|
116
|
-
save
|
116
|
+
save(**opts)
|
117
117
|
end
|
118
118
|
|
119
119
|
# @api public
|
@@ -136,11 +136,11 @@ class Acfs::Resource
|
|
136
136
|
# @see #attributes=
|
137
137
|
# @see #update_attributes
|
138
138
|
#
|
139
|
-
def update_attributes!(attrs, opts
|
139
|
+
def update_attributes!(attrs, **opts)
|
140
140
|
check_loaded! opts
|
141
141
|
|
142
142
|
self.attributes = attrs
|
143
|
-
save!
|
143
|
+
save!(**opts)
|
144
144
|
end
|
145
145
|
|
146
146
|
# @api public
|
@@ -152,8 +152,8 @@ class Acfs::Resource
|
|
152
152
|
# @return [Boolean]
|
153
153
|
# @see #delete!
|
154
154
|
#
|
155
|
-
def delete(opts
|
156
|
-
delete!
|
155
|
+
def delete(**opts)
|
156
|
+
delete!(**opts)
|
157
157
|
true
|
158
158
|
rescue Acfs::Error
|
159
159
|
false
|
@@ -172,11 +172,11 @@ class Acfs::Resource
|
|
172
172
|
# @return [undefined]
|
173
173
|
# @see #delete
|
174
174
|
#
|
175
|
-
def delete!(opts
|
175
|
+
def delete!(**opts)
|
176
176
|
opts[:params] ||= {}
|
177
177
|
opts[:params] = attributes_for_url(:delete).merge opts[:params]
|
178
178
|
|
179
|
-
operation
|
179
|
+
operation(:delete, **opts) do |data|
|
180
180
|
update_with data
|
181
181
|
freeze
|
182
182
|
end
|
@@ -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!
|
@@ -56,7 +56,7 @@ class Acfs::Resource
|
|
56
56
|
#
|
57
57
|
# @return [Collection] Collection of requested resources.
|
58
58
|
#
|
59
|
-
def find(id_or_ids, opts
|
59
|
+
def find(id_or_ids, **opts, &block)
|
60
60
|
if id_or_ids.respond_to? :each
|
61
61
|
find_multiple id_or_ids, opts, &block
|
62
62
|
else
|
@@ -81,7 +81,7 @@ class Acfs::Resource
|
|
81
81
|
collection = ::Acfs::Collection.new self
|
82
82
|
collection.__callbacks__ << block if block
|
83
83
|
|
84
|
-
operation
|
84
|
+
operation(:list, **opts, params: params) do |data, response|
|
85
85
|
data.each {|obj| collection << create_resource(obj) }
|
86
86
|
collection.process_response response
|
87
87
|
collection.loaded!
|
@@ -109,7 +109,7 @@ class Acfs::Resource
|
|
109
109
|
def find_by(params, &block)
|
110
110
|
Acfs::Util::ResourceDelegator.new(new).tap do |m|
|
111
111
|
m.__callbacks__ << block unless block.nil?
|
112
|
-
operation
|
112
|
+
operation(:list, params: params) do |data|
|
113
113
|
if data.empty?
|
114
114
|
m.__setobj__ nil
|
115
115
|
else
|
@@ -139,7 +139,7 @@ class Acfs::Resource
|
|
139
139
|
find_by params do |m|
|
140
140
|
if m.nil?
|
141
141
|
raise Acfs::ResourceNotFound.new message: 'Received erroneous ' \
|
142
|
-
|
142
|
+
"response: no `#{name}` with params #{params} found"
|
143
143
|
end
|
144
144
|
block&.call m
|
145
145
|
end
|
@@ -210,11 +210,11 @@ class Acfs::Resource
|
|
210
210
|
model = Acfs::Util::ResourceDelegator.new new
|
211
211
|
|
212
212
|
opts[:params] ||= {}
|
213
|
-
opts[:params]
|
213
|
+
opts[:params][:id] = id unless id.nil?
|
214
214
|
|
215
215
|
model.__callbacks__ << block unless block.nil?
|
216
216
|
|
217
|
-
operation
|
217
|
+
operation(:read, **opts) do |data|
|
218
218
|
model.__setobj__ create_resource data, origin: model.__getobj__
|
219
219
|
model.__invoke__
|
220
220
|
end
|
@@ -228,7 +228,7 @@ class Acfs::Resource
|
|
228
228
|
|
229
229
|
counter = 0
|
230
230
|
ids.each_with_index do |id, index|
|
231
|
-
find_single
|
231
|
+
find_single(id, opts) do |resource|
|
232
232
|
collection[index] = resource
|
233
233
|
if (counter += 1) == ids.size
|
234
234
|
collection.loaded!
|
@@ -239,11 +239,11 @@ class Acfs::Resource
|
|
239
239
|
end
|
240
240
|
end
|
241
241
|
|
242
|
-
def create_resource(data, opts
|
242
|
+
def create_resource(data, **opts)
|
243
243
|
type = data.delete 'type'
|
244
244
|
klass = resource_class_lookup(type)
|
245
245
|
(opts[:origin].is_a?(klass) ? opts[:origin] : klass.new).tap do |m|
|
246
|
-
m.write_attributes
|
246
|
+
m.write_attributes(data, **opts)
|
247
247
|
m.loaded!
|
248
248
|
end
|
249
249
|
end
|
@@ -258,7 +258,7 @@ class Acfs::Resource
|
|
258
258
|
end
|
259
259
|
|
260
260
|
klass
|
261
|
-
rescue NameError
|
261
|
+
rescue NameError
|
262
262
|
raise Acfs::ResourceTypeError.new type_name: type, base_class: self
|
263
263
|
end
|
264
264
|
end
|
@@ -34,8 +34,8 @@ class Acfs::Resource
|
|
34
34
|
# @param options [Object] Option delegated to
|
35
35
|
# service class initializer.
|
36
36
|
#
|
37
|
-
def service(klass = nil, options
|
38
|
-
return (@service = klass.new
|
37
|
+
def service(klass = nil, **options)
|
38
|
+
return (@service = klass.new(**options)) if klass
|
39
39
|
|
40
40
|
@service || superclass.service
|
41
41
|
end
|
@@ -2,12 +2,6 @@
|
|
2
2
|
|
3
3
|
class Acfs::Resource
|
4
4
|
module Validation
|
5
|
-
def valid?(*args)
|
6
|
-
super
|
7
|
-
remote_errors.each {|f, e| errors.add f, e }
|
8
|
-
errors.empty?
|
9
|
-
end
|
10
|
-
|
11
5
|
def remote_errors
|
12
6
|
@remote_errors ||= ActiveModel::Errors.new self
|
13
7
|
end
|
@@ -28,12 +22,28 @@ class Acfs::Resource
|
|
28
22
|
end
|
29
23
|
end
|
30
24
|
|
31
|
-
def save!(
|
25
|
+
def save!(**kwargs)
|
32
26
|
unless valid?(new? ? :create : :save)
|
33
27
|
raise ::Acfs::InvalidResource.new resource: self, errors: errors.to_a
|
34
28
|
end
|
35
29
|
|
36
30
|
super
|
37
31
|
end
|
32
|
+
|
33
|
+
if ::ActiveModel.version >= Gem::Version.new('6.1')
|
34
|
+
def valid?(*args)
|
35
|
+
super
|
36
|
+
|
37
|
+
remote_errors.each {|e| errors.add(e.attribute, e.message) }
|
38
|
+
errors.empty?
|
39
|
+
end
|
40
|
+
else
|
41
|
+
def valid?(*args)
|
42
|
+
super
|
43
|
+
|
44
|
+
remote_errors.each {|f, e| errors.add(f, e) }
|
45
|
+
errors.empty?
|
46
|
+
end
|
47
|
+
end
|
38
48
|
end
|
39
49
|
end
|
data/lib/acfs/response.rb
CHANGED
@@ -19,12 +19,12 @@ module Acfs
|
|
19
19
|
# :response_body, :response_headers, :response_code, :headers,
|
20
20
|
# to: :response
|
21
21
|
|
22
|
-
def initialize(request,
|
22
|
+
def initialize(request, **opts)
|
23
23
|
@request = request
|
24
|
-
@status =
|
25
|
-
@headers =
|
26
|
-
@body =
|
27
|
-
@data =
|
24
|
+
@status = opts[:status] || 0
|
25
|
+
@headers = opts[:headers] || {}
|
26
|
+
@body = opts[:body] || ''
|
27
|
+
@data = opts[:data] || nil
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
data/lib/acfs/runner.rb
CHANGED
@@ -17,16 +17,16 @@ module Acfs
|
|
17
17
|
# Process an operation. Synchronous operations will be run
|
18
18
|
# and parallel operations will be queued.
|
19
19
|
#
|
20
|
-
def process(
|
21
|
-
::ActiveSupport::Notifications.instrument
|
22
|
-
|
20
|
+
def process(operation)
|
21
|
+
::ActiveSupport::Notifications.instrument('acfs.operation.before_process', operation: operation)
|
22
|
+
operation.synchronous? ? run(operation) : enqueue(operation)
|
23
23
|
end
|
24
24
|
|
25
25
|
# Run operation right now skipping queue.
|
26
26
|
#
|
27
|
-
def run(
|
28
|
-
::ActiveSupport::Notifications.instrument
|
29
|
-
|
27
|
+
def run(operation)
|
28
|
+
::ActiveSupport::Notifications.instrument('acfs.runner.sync_run', operation: operation) do
|
29
|
+
operation_request(operation) {|req| adapter.run req }
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -38,12 +38,12 @@ module Acfs
|
|
38
38
|
|
39
39
|
# Enqueue operation to be run later.
|
40
40
|
#
|
41
|
-
def enqueue(
|
42
|
-
::ActiveSupport::Notifications.instrument
|
41
|
+
def enqueue(operation)
|
42
|
+
::ActiveSupport::Notifications.instrument('acfs.runner.enqueue', operation: operation) do
|
43
43
|
if running?
|
44
|
-
|
44
|
+
operation_request(operation) {|req| adapter.queue req }
|
45
45
|
else
|
46
|
-
queue <<
|
46
|
+
queue << operation
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -82,15 +82,15 @@ module Acfs
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def enqueue_operations
|
85
|
-
while (
|
86
|
-
|
85
|
+
while (operation = queue.shift)
|
86
|
+
operation_request(operation) {|req| adapter.queue req }
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
def
|
91
|
-
return if Acfs::Stub.enabled? && Acfs::Stub.stubbed(
|
90
|
+
def operation_request(operation)
|
91
|
+
return if Acfs::Stub.enabled? && Acfs::Stub.stubbed(operation)
|
92
92
|
|
93
|
-
req =
|
93
|
+
req = operation.service.prepare(operation.request)
|
94
94
|
return unless req.is_a? Acfs::Request
|
95
95
|
|
96
96
|
req = prepare req
|