acfs 1.3.1 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Acfs::Resource
|
2
4
|
# @api private
|
3
5
|
#
|
@@ -11,7 +13,6 @@ class Acfs::Resource
|
|
11
13
|
extend ActiveSupport::Concern
|
12
14
|
delegate :operation, to: :'self.class'
|
13
15
|
|
14
|
-
#
|
15
16
|
module ClassMethods
|
16
17
|
# Invoke CRUD operation.
|
17
18
|
def operation(action, opts = {}, &block)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Acfs::Resource
|
2
4
|
#
|
3
5
|
# Allow to track the persistence state of a model.
|
@@ -40,7 +42,7 @@ class Acfs::Resource
|
|
40
42
|
def new?
|
41
43
|
!loaded?
|
42
44
|
end
|
43
|
-
|
45
|
+
alias new_record? new?
|
44
46
|
|
45
47
|
# @api public
|
46
48
|
#
|
@@ -86,9 +88,9 @@ class Acfs::Resource
|
|
86
88
|
operation((new? ? :create : :update), opts) do |data|
|
87
89
|
update_with data
|
88
90
|
end
|
89
|
-
rescue ::Acfs::InvalidResource =>
|
90
|
-
self.remote_errors =
|
91
|
-
raise
|
91
|
+
rescue ::Acfs::InvalidResource => e
|
92
|
+
self.remote_errors = e.errors
|
93
|
+
raise e
|
92
94
|
end
|
93
95
|
|
94
96
|
# @api public
|
@@ -242,8 +244,6 @@ class Acfs::Resource
|
|
242
244
|
end
|
243
245
|
end
|
244
246
|
|
245
|
-
private
|
246
|
-
|
247
247
|
def update_with(data)
|
248
248
|
self.attributes = data
|
249
249
|
loaded!
|
@@ -251,6 +251,7 @@ class Acfs::Resource
|
|
251
251
|
|
252
252
|
def check_loaded!(opts = {})
|
253
253
|
return if loaded? || opts[:force]
|
254
|
+
|
254
255
|
raise ::Acfs::ResourceNotLoaded.new resource: self
|
255
256
|
end
|
256
257
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Acfs::Resource
|
2
4
|
# Methods providing the query interface for finding resouces.
|
3
5
|
#
|
@@ -14,7 +16,6 @@ class Acfs::Resource
|
|
14
16
|
module QueryMethods
|
15
17
|
extend ActiveSupport::Concern
|
16
18
|
|
17
|
-
#
|
18
19
|
module ClassMethods
|
19
20
|
# @api public
|
20
21
|
#
|
@@ -89,7 +90,7 @@ class Acfs::Resource
|
|
89
90
|
|
90
91
|
collection
|
91
92
|
end
|
92
|
-
|
93
|
+
alias where all
|
93
94
|
|
94
95
|
# @api public
|
95
96
|
#
|
@@ -140,7 +141,7 @@ class Acfs::Resource
|
|
140
141
|
raise Acfs::ResourceNotFound.new message: 'Received erroneous ' \
|
141
142
|
"response: no `#{name}` with params #{params} found"
|
142
143
|
end
|
143
|
-
block
|
144
|
+
block&.call m
|
144
145
|
end
|
145
146
|
end
|
146
147
|
|
@@ -249,6 +250,7 @@ class Acfs::Resource
|
|
249
250
|
|
250
251
|
def resource_class_lookup(type)
|
251
252
|
return self if type.nil?
|
253
|
+
|
252
254
|
klass = type.camelize.constantize
|
253
255
|
|
254
256
|
unless klass <= self
|
@@ -256,7 +258,7 @@ class Acfs::Resource
|
|
256
258
|
end
|
257
259
|
|
258
260
|
klass
|
259
|
-
rescue NameError
|
261
|
+
rescue NameError
|
260
262
|
raise Acfs::ResourceTypeError.new type_name: type, base_class: self
|
261
263
|
end
|
262
264
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Acfs::Resource
|
2
4
|
# Included by Acfs::Model. Allows to configure the service
|
3
5
|
# a resource belongs to.
|
@@ -5,7 +7,6 @@ class Acfs::Resource
|
|
5
7
|
module Service
|
6
8
|
extend ActiveSupport::Concern
|
7
9
|
|
8
|
-
#
|
9
10
|
module ClassMethods
|
10
11
|
# @api public
|
11
12
|
#
|
@@ -35,6 +36,7 @@ class Acfs::Resource
|
|
35
36
|
#
|
36
37
|
def service(klass = nil, options = {})
|
37
38
|
return (@service = klass.new options) if klass
|
39
|
+
|
38
40
|
@service || superclass.service
|
39
41
|
end
|
40
42
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Acfs::Resource
|
2
|
-
#
|
3
4
|
module Validation
|
4
5
|
def valid?(*args)
|
5
6
|
super
|
@@ -31,6 +32,7 @@ class Acfs::Resource
|
|
31
32
|
unless valid?(new? ? :create : :save)
|
32
33
|
raise ::Acfs::InvalidResource.new resource: self, errors: errors.to_a
|
33
34
|
end
|
35
|
+
|
34
36
|
super
|
35
37
|
end
|
36
38
|
end
|
data/lib/acfs/response.rb
CHANGED
data/lib/acfs/response/status.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
class Response
|
3
5
|
# Method to fetch information about response status.
|
@@ -11,7 +13,7 @@ module Acfs
|
|
11
13
|
# return response.response_code unless response.nil?
|
12
14
|
# 0
|
13
15
|
end
|
14
|
-
|
16
|
+
alias code status_code
|
15
17
|
|
16
18
|
# Return true if response was successful indicated by
|
17
19
|
# response status code.
|
data/lib/acfs/rspec.rb
CHANGED
data/lib/acfs/runner.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'acfs/service/middleware'
|
2
4
|
|
3
5
|
module Acfs
|
@@ -59,7 +61,7 @@ module Acfs
|
|
59
61
|
|
60
62
|
enqueue_operations
|
61
63
|
start_all
|
62
|
-
rescue
|
64
|
+
rescue StandardError
|
63
65
|
queue.clear
|
64
66
|
raise
|
65
67
|
end
|
@@ -87,10 +89,13 @@ module Acfs
|
|
87
89
|
|
88
90
|
def op_request(op)
|
89
91
|
return if Acfs::Stub.enabled? && Acfs::Stub.stubbed(op)
|
92
|
+
|
90
93
|
req = op.service.prepare op.request
|
91
94
|
return unless req.is_a? Acfs::Request
|
95
|
+
|
92
96
|
req = prepare req
|
93
97
|
return unless req.is_a? Acfs::Request
|
98
|
+
|
94
99
|
yield req
|
95
100
|
end
|
96
101
|
end
|
data/lib/acfs/service.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'acfs/service/middleware'
|
2
4
|
|
3
5
|
module Acfs
|
@@ -38,21 +40,27 @@ module Acfs
|
|
38
40
|
|
39
41
|
action = opts[:action] || :list
|
40
42
|
|
41
|
-
path =
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
49
52
|
|
50
|
-
|
53
|
+
if path.blank?
|
54
|
+
path = (resource_class.name || 'class').pluralize.underscore
|
55
|
+
end
|
51
56
|
|
52
|
-
|
53
|
-
|
57
|
+
resource_class.location_default_path(action, path.strip)
|
58
|
+
end
|
59
|
+
end
|
54
60
|
|
55
|
-
|
61
|
+
if path.nil?
|
62
|
+
raise ArgumentError.new "Location for `#{action}' explicit disabled by set to nil."
|
63
|
+
end
|
56
64
|
|
57
65
|
Location.new [self.class.base_url.to_s, path.to_s].join('/')
|
58
66
|
end
|
@@ -81,7 +89,10 @@ module Acfs
|
|
81
89
|
#
|
82
90
|
def base_url
|
83
91
|
unless (base = Acfs::Configuration.current.locate identity)
|
84
|
-
raise ArgumentError.new
|
92
|
+
raise ArgumentError.new \
|
93
|
+
"#{identity} not configured. Add `locate '" \
|
94
|
+
"#{identity.to_s.underscore}', 'http://service.url/'` " \
|
95
|
+
'to your configuration.'
|
85
96
|
end
|
86
97
|
|
87
98
|
base.to_s
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
class Service
|
3
5
|
module Middleware
|
@@ -5,7 +7,7 @@ module Acfs
|
|
5
7
|
include Enumerable
|
6
8
|
|
7
9
|
MUTEX = Mutex.new
|
8
|
-
IDENTITY = ->
|
10
|
+
IDENTITY = ->(i) { i }
|
9
11
|
|
10
12
|
attr_reader :middlewares
|
11
13
|
|
@@ -41,7 +43,7 @@ module Acfs
|
|
41
43
|
next_middleware.call(klass.call(env, *args))
|
42
44
|
end
|
43
45
|
else
|
44
|
-
|
46
|
+
raise "Invalid middleware, doesn't respond to `call`: #{klass.inspect}"
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
@@ -51,7 +53,7 @@ module Acfs
|
|
51
53
|
end
|
52
54
|
|
53
55
|
def each
|
54
|
-
middlewares.each {
|
56
|
+
middlewares.each {|x| yield x.first }
|
55
57
|
end
|
56
58
|
|
57
59
|
def clear
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Acfs
|
2
4
|
# Acfs SingletonResources
|
3
5
|
#
|
@@ -71,8 +73,8 @@ module Acfs
|
|
71
73
|
def all
|
72
74
|
raise ::Acfs::UnsupportedOperation.new
|
73
75
|
end
|
74
|
-
|
75
|
-
|
76
|
+
alias find_by all
|
77
|
+
alias find_by! all
|
76
78
|
|
77
79
|
# @api private
|
78
80
|
def location_default_path(_, path)
|
data/lib/acfs/stub.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
|
3
5
|
module Acfs
|
4
6
|
# Global handler for stubbing resources.
|
5
7
|
#
|
6
8
|
class Stub
|
7
|
-
ACTIONS = [
|
9
|
+
ACTIONS = %i[read create update delete list].freeze
|
8
10
|
|
9
11
|
attr_reader :opts
|
10
12
|
|
@@ -13,7 +15,10 @@ module Acfs
|
|
13
15
|
|
14
16
|
@opts[:with].stringify_keys! if @opts[:with].is_a? Hash
|
15
17
|
@opts[:return].stringify_keys! if @opts[:return].is_a? Hash
|
16
|
-
|
18
|
+
|
19
|
+
if @opts[:return].is_a?(Array) # rubocop:disable Style/GuardClause
|
20
|
+
@opts[:return].map! {|h| h.stringify_keys! if h.is_a? Hash }
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
def accept?(op)
|
@@ -28,8 +33,13 @@ module Acfs
|
|
28
33
|
case opts.fetch(:match, :inclusion)
|
29
34
|
when :legacy
|
30
35
|
return true if with.empty? && params.empty? && data.empty?
|
31
|
-
|
32
|
-
|
36
|
+
if with.reject {|_, v| v.nil? } == params.reject {|_, v| v.nil? }
|
37
|
+
return true
|
38
|
+
end
|
39
|
+
if with.reject {|_, v| v.nil? } == data.reject {|_, v| v.nil? }
|
40
|
+
return true
|
41
|
+
end
|
42
|
+
|
33
43
|
false
|
34
44
|
when :inclusion
|
35
45
|
with.each_pair.all? do |k, v|
|
@@ -43,7 +53,8 @@ module Acfs
|
|
43
53
|
end
|
44
54
|
|
45
55
|
def called?(count = nil)
|
46
|
-
count = count.count if count.respond_to?
|
56
|
+
count = count.count if count.respond_to?(:count)
|
57
|
+
|
47
58
|
count.nil? ? calls.any? : calls.size == count
|
48
59
|
end
|
49
60
|
|
@@ -60,8 +71,8 @@ module Acfs
|
|
60
71
|
|
61
72
|
response = Acfs::Response.new op.request,
|
62
73
|
headers: opts[:headers] || {},
|
63
|
-
status:
|
64
|
-
data:
|
74
|
+
status: opts[:status] || 200,
|
75
|
+
data: data || {}
|
65
76
|
op.call data, response
|
66
77
|
else
|
67
78
|
raise ArgumentError.new 'Unsupported stub.'
|
@@ -72,6 +83,7 @@ module Acfs
|
|
72
83
|
|
73
84
|
def raise_error(op, name, data)
|
74
85
|
raise name if name.is_a? Class
|
86
|
+
|
75
87
|
data.stringify_keys! if data.respond_to? :stringify_keys!
|
76
88
|
|
77
89
|
op.handle_failure ::Acfs::Response.new op.request, status: Rack::Utils.status_code(name), data: data
|
@@ -83,7 +95,9 @@ module Acfs
|
|
83
95
|
#
|
84
96
|
def resource(klass, action, opts = {}, &_block)
|
85
97
|
action = action.to_sym
|
86
|
-
|
98
|
+
unless ACTIONS.include? action
|
99
|
+
raise ArgumentError.new "Unknown action `#{action}`."
|
100
|
+
end
|
87
101
|
|
88
102
|
Stub.new(opts).tap do |stub|
|
89
103
|
stubs[klass] ||= {}
|
@@ -128,7 +142,9 @@ module Acfs
|
|
128
142
|
|
129
143
|
accepted_stubs = stubs.select {|stub| stub.accept? op }
|
130
144
|
|
131
|
-
|
145
|
+
if accepted_stubs.size > 1
|
146
|
+
raise AmbiguousStubError.new stubs: accepted_stubs, operation: op
|
147
|
+
end
|
132
148
|
|
133
149
|
accepted_stubs.first
|
134
150
|
end
|
@@ -137,6 +153,7 @@ module Acfs
|
|
137
153
|
stub = stub_for op
|
138
154
|
unless stub
|
139
155
|
return false if allow_requests?
|
156
|
+
|
140
157
|
raise RealRequestsNotAllowedError.new <<-MSG.strip.gsub(/^[ ]{12}/, '')
|
141
158
|
No stub found for `#{op.action}' on `#{op.resource.name}' with params `#{op.full_params.inspect}', data `#{op.data.inspect}' and id `#{op.id}'.
|
142
159
|
|
@@ -159,8 +176,12 @@ module Acfs
|
|
159
176
|
stubs.each do |stub|
|
160
177
|
out << " #{action}"
|
161
178
|
out << " with #{stub.opts[:with].inspect}" if stub.opts[:with]
|
162
|
-
|
163
|
-
|
179
|
+
if stub.opts[:return]
|
180
|
+
out << " and return #{stub.opts[:return].inspect}"
|
181
|
+
end
|
182
|
+
if stub.opts[:raise]
|
183
|
+
out << " and raise #{stub.opts[:raise].inspect}"
|
184
|
+
end
|
164
185
|
out << "\n"
|
165
186
|
end
|
166
187
|
end
|
data/lib/acfs/util.rb
CHANGED