acfs 0.42.0 → 0.43.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 +6 -0
- data/README.md +8 -9
- data/acfs.gemspec +3 -3
- data/lib/acfs.rb +0 -2
- data/lib/acfs/adapter/base.rb +0 -2
- data/lib/acfs/adapter/typhoeus.rb +6 -9
- data/lib/acfs/collection.rb +3 -3
- data/lib/acfs/collections/paginatable.rb +16 -16
- data/lib/acfs/configuration.rb +3 -5
- data/lib/acfs/errors.rb +8 -7
- data/lib/acfs/global.rb +1 -1
- data/lib/acfs/location.rb +11 -11
- data/lib/acfs/middleware/base.rb +1 -2
- data/lib/acfs/middleware/json.rb +0 -1
- data/lib/acfs/middleware/logger.rb +0 -2
- data/lib/acfs/middleware/print.rb +0 -2
- data/lib/acfs/middleware/serializer.rb +3 -6
- data/lib/acfs/operation.rb +3 -4
- data/lib/acfs/request.rb +2 -3
- data/lib/acfs/request/callbacks.rb +2 -3
- data/lib/acfs/resource.rb +34 -5
- data/lib/acfs/{model → resource}/attributes.rb +70 -46
- data/lib/acfs/{model → resource}/attributes/base.rb +10 -6
- data/lib/acfs/resource/attributes/boolean.rb +33 -0
- data/lib/acfs/resource/attributes/date_time.rb +32 -0
- data/lib/acfs/{model → resource}/attributes/dict.rb +1 -3
- data/lib/acfs/{model → resource}/attributes/float.rb +3 -6
- data/lib/acfs/{model → resource}/attributes/integer.rb +3 -6
- data/lib/acfs/{model → resource}/attributes/list.rb +2 -5
- data/lib/acfs/{model → resource}/attributes/string.rb +4 -6
- data/lib/acfs/{model → resource}/attributes/uuid.rb +18 -8
- data/lib/acfs/resource/dirty.rb +47 -0
- data/lib/acfs/{model → resource}/initialization.rb +8 -10
- data/lib/acfs/{model → resource}/loadable.rb +3 -4
- data/lib/acfs/{model → resource}/locatable.rb +22 -23
- data/lib/acfs/{model → resource}/operational.rb +2 -3
- data/lib/acfs/resource/persistence.rb +257 -0
- data/lib/acfs/{model → resource}/query_methods.rb +81 -66
- data/lib/acfs/{model → resource}/service.rb +10 -9
- data/lib/acfs/resource/validation.rb +28 -0
- data/lib/acfs/response.rb +1 -2
- data/lib/acfs/response/formats.rb +1 -2
- data/lib/acfs/response/status.rb +3 -5
- data/lib/acfs/runner.rb +4 -5
- data/lib/acfs/service.rb +4 -6
- data/lib/acfs/service/middleware.rb +1 -3
- data/lib/acfs/singleton_resource.rb +11 -24
- data/lib/acfs/stub.rb +30 -22
- data/lib/acfs/util.rb +1 -1
- data/lib/acfs/version.rb +4 -2
- data/spec/acfs/adapter/typhoeus_spec.rb +4 -4
- data/spec/acfs/collection_spec.rb +33 -33
- data/spec/acfs/configuration_spec.rb +0 -1
- data/spec/acfs/global_spec.rb +3 -3
- data/spec/acfs/middleware/json_spec.rb +2 -2
- data/spec/acfs/middleware/msgpack_spec.rb +4 -4
- data/spec/acfs/request/callbacks_spec.rb +8 -8
- data/spec/acfs/request_spec.rb +5 -5
- data/spec/acfs/{model → resource}/attributes/boolean_spec.rb +2 -2
- data/spec/acfs/{model → resource}/attributes/date_time_spec.rb +7 -7
- data/spec/acfs/{model → resource}/attributes/dict_spec.rb +6 -6
- data/spec/acfs/{model → resource}/attributes/float_spec.rb +3 -3
- data/spec/acfs/{model → resource}/attributes/list_spec.rb +5 -5
- data/spec/acfs/{model → resource}/attributes/uuid_spec.rb +6 -6
- data/spec/acfs/{model → resource}/attributes_spec.rb +31 -17
- data/spec/acfs/{model → resource}/dirty_spec.rb +7 -5
- data/spec/acfs/{model → resource}/initialization_spec.rb +7 -7
- data/spec/acfs/{model → resource}/loadable_spec.rb +4 -3
- data/spec/acfs/{model → resource}/locatable_spec.rb +24 -14
- data/spec/acfs/{model → resource}/persistance_spec.rb +34 -34
- data/spec/acfs/{model → resource}/query_methods_spec.rb +171 -130
- data/spec/acfs/{model → resource}/validation_spec.rb +5 -6
- data/spec/acfs/response/formats_spec.rb +1 -1
- data/spec/acfs/response/status_spec.rb +1 -1
- data/spec/acfs/runner_spec.rb +2 -3
- data/spec/acfs/service/middleware_spec.rb +1 -1
- data/spec/acfs/service_spec.rb +3 -5
- data/spec/acfs/singleton_resource_spec.rb +3 -3
- data/spec/acfs/stub_spec.rb +52 -24
- data/spec/acfs_spec.rb +22 -19
- data/spec/spec_helper.rb +1 -1
- data/spec/support/hash.rb +9 -0
- data/spec/support/service.rb +4 -7
- data/spec/support/shared/find_callbacks.rb +7 -7
- metadata +52 -52
- data/lib/acfs/model.rb +0 -43
- data/lib/acfs/model/attributes/boolean.rb +0 -38
- data/lib/acfs/model/attributes/date_time.rb +0 -30
- data/lib/acfs/model/dirty.rb +0 -49
- data/lib/acfs/model/persistence.rb +0 -243
- data/lib/acfs/model/relations.rb +0 -10
- data/lib/acfs/model/validation.rb +0 -30
@@ -1,15 +1,14 @@
|
|
1
1
|
module Acfs
|
2
2
|
module Middleware
|
3
|
-
|
4
3
|
# A base middleware that does not modify request or response.
|
5
4
|
# Can be used as super class for custom middleware implementations.
|
6
5
|
#
|
7
6
|
class Serializer < Base
|
8
|
-
def encode(
|
7
|
+
def encode(_data)
|
9
8
|
raise NotImplementedError
|
10
9
|
end
|
11
10
|
|
12
|
-
def decode(
|
11
|
+
def decode(_data)
|
13
12
|
raise NotImplementedError
|
14
13
|
end
|
15
14
|
|
@@ -28,9 +27,7 @@ module Acfs
|
|
28
27
|
request.headers['Accept'] = accept.join(',')
|
29
28
|
|
30
29
|
request.on_complete do |response, nxt|
|
31
|
-
if mime == response.content_type
|
32
|
-
response.data = decode response.body
|
33
|
-
end
|
30
|
+
response.data = decode response.body if mime == response.content_type
|
34
31
|
|
35
32
|
nxt.call response
|
36
33
|
end
|
data/lib/acfs/operation.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module Acfs
|
2
|
-
|
3
2
|
# @api private
|
4
3
|
#
|
5
4
|
# Describes a CRUD operation. Handle request creation and response
|
@@ -51,7 +50,7 @@ module Acfs
|
|
51
50
|
end
|
52
51
|
|
53
52
|
def method
|
54
|
-
{
|
53
|
+
{read: :get, list: :get, update: :put, create: :post, delete: :delete}[action]
|
55
54
|
end
|
56
55
|
|
57
56
|
def request
|
@@ -59,8 +58,8 @@ module Acfs
|
|
59
58
|
data: data, operation: self
|
60
59
|
request.on_complete do |response|
|
61
60
|
::ActiveSupport::Notifications.instrument 'acfs.operation.complete',
|
62
|
-
|
63
|
-
|
61
|
+
operation: self,
|
62
|
+
response: response
|
64
63
|
|
65
64
|
handle_failure response unless response.success?
|
66
65
|
callback.call response.data, response
|
data/lib/acfs/request.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'acfs/request/callbacks'
|
2
2
|
|
3
3
|
module Acfs
|
4
|
-
|
5
4
|
# Encapsulate all data required to make up a request to the
|
6
5
|
# underlaying http library.
|
7
6
|
#
|
@@ -12,7 +11,7 @@ module Acfs
|
|
12
11
|
include Request::Callbacks
|
13
12
|
|
14
13
|
def initialize(url, options = {}, &block)
|
15
|
-
@url = URI.parse(url.to_s).tap do |
|
14
|
+
@url = URI.parse(url.to_s).tap do |_url|
|
16
15
|
@data = options.delete(:data) || nil
|
17
16
|
@format = options.delete(:format) || :json
|
18
17
|
@headers = options.delete(:headers) || {}
|
@@ -20,7 +19,7 @@ module Acfs
|
|
20
19
|
@method = options.delete(:method) || :get
|
21
20
|
end.to_s
|
22
21
|
@operation = options.delete(:operation) || nil
|
23
|
-
on_complete
|
22
|
+
on_complete(&block) if block_given?
|
24
23
|
end
|
25
24
|
|
26
25
|
def data?
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Acfs
|
2
2
|
class Request
|
3
|
-
|
4
3
|
# Module containing callback handling for Requests.
|
5
4
|
# Current the only callback type is `on_complete`:
|
6
5
|
#
|
@@ -8,7 +7,6 @@ module Acfs
|
|
8
7
|
# request.on_complete { |response| ... }
|
9
8
|
#
|
10
9
|
module Callbacks
|
11
|
-
|
12
10
|
# Add a new `on_complete` callback for this request.
|
13
11
|
#
|
14
12
|
# @example Set on_complete.
|
@@ -43,8 +41,9 @@ module Acfs
|
|
43
41
|
end
|
44
42
|
|
45
43
|
private
|
44
|
+
|
46
45
|
def call_callback(res, index)
|
47
|
-
callbacks[index].call res, proc {
|
46
|
+
callbacks[index].call res, proc {|bres| call_callback bres, index + 1 } if index < callbacks.size
|
48
47
|
end
|
49
48
|
end
|
50
49
|
end
|
data/lib/acfs/resource.rb
CHANGED
@@ -1,8 +1,37 @@
|
|
1
|
-
|
1
|
+
require 'active_model'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
# @api public
|
4
|
+
#
|
5
|
+
class Acfs::Resource
|
6
|
+
require 'acfs/resource/initialization'
|
7
|
+
require 'acfs/resource/attributes'
|
8
|
+
require 'acfs/resource/dirty'
|
9
|
+
require 'acfs/resource/loadable'
|
10
|
+
require 'acfs/resource/locatable'
|
11
|
+
require 'acfs/resource/operational'
|
12
|
+
require 'acfs/resource/persistence'
|
13
|
+
require 'acfs/resource/query_methods'
|
14
|
+
require 'acfs/resource/service'
|
15
|
+
require 'acfs/resource/validation'
|
16
|
+
|
17
|
+
if ActiveModel::VERSION::MAJOR >= 4
|
18
|
+
include ActiveModel::Model
|
19
|
+
else
|
20
|
+
extend ActiveModel::Naming
|
21
|
+
extend ActiveModel::Translation
|
22
|
+
include ActiveModel::Conversion
|
23
|
+
include ActiveModel::Validations
|
7
24
|
end
|
25
|
+
|
26
|
+
include Initialization
|
27
|
+
|
28
|
+
include Attributes
|
29
|
+
include Loadable
|
30
|
+
include Persistence
|
31
|
+
include Locatable
|
32
|
+
include Operational
|
33
|
+
include QueryMethods
|
34
|
+
include Service
|
35
|
+
include Dirty
|
36
|
+
include Validation
|
8
37
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
class Acfs::Resource
|
2
|
+
#
|
3
3
|
# = Acfs Attributes
|
4
4
|
#
|
5
|
-
# Allows to specify attributes of a class with default
|
5
|
+
# Allows to specify attributes of a class with default
|
6
|
+
# values and type safety.
|
6
7
|
#
|
7
8
|
# @example
|
8
|
-
# class User
|
9
|
-
# include Acfs::Model
|
9
|
+
# class User < Acfs::Resource
|
10
10
|
# attribute :name, :string, default: 'Anon'
|
11
11
|
# attribute :age, :integer
|
12
12
|
# attribute :special, My::Special::Type
|
@@ -27,7 +27,7 @@ module Acfs::Model
|
|
27
27
|
# @see ClassMethods#attributes
|
28
28
|
#
|
29
29
|
def initialize(*attrs)
|
30
|
-
|
30
|
+
write_attributes self.class.attributes
|
31
31
|
reset_changes
|
32
32
|
super
|
33
33
|
end
|
@@ -37,14 +37,14 @@ module Acfs::Model
|
|
37
37
|
# Returns ActiveModel compatible list of attributes and values.
|
38
38
|
#
|
39
39
|
# @example
|
40
|
-
# class User
|
41
|
-
# include Acfs::Model
|
40
|
+
# class User < Acfs::Resource
|
42
41
|
# attribute :name, type: String, default: 'Anon'
|
43
42
|
# end
|
44
43
|
# user = User.new(name: 'John')
|
45
44
|
# user.attributes # => { "name" => "John" }
|
46
45
|
#
|
47
|
-
# @return [
|
46
|
+
# @return [HashWithIndifferentAccess{Symbol => Object}]
|
47
|
+
# Attributes and their values.
|
48
48
|
#
|
49
49
|
def attributes
|
50
50
|
@attributes ||= HashWithIndifferentAccess.new
|
@@ -59,8 +59,9 @@ module Acfs::Model
|
|
59
59
|
# user.attributes = { :name => 'Adam' }
|
60
60
|
# user.name # => 'Adam'
|
61
61
|
#
|
62
|
-
# @param [
|
63
|
-
#
|
62
|
+
# @param [Hash{String, Symbol => Object}, #each{|key, value|}]
|
63
|
+
# Attributes to set in resource.
|
64
|
+
# @see #write_attributes Delegates attributes hash to {#write_attributes}.
|
64
65
|
#
|
65
66
|
def attributes=(attributes)
|
66
67
|
write_attributes attributes
|
@@ -70,11 +71,11 @@ module Acfs::Model
|
|
70
71
|
#
|
71
72
|
# Read an attribute from instance variable.
|
72
73
|
#
|
73
|
-
# @param [
|
74
|
-
# @return [
|
74
|
+
# @param [Symbol, String] name Attribute name.
|
75
|
+
# @return [Object] Attribute value.
|
75
76
|
#
|
76
77
|
def read_attribute(name)
|
77
|
-
|
78
|
+
attributes[name.to_s]
|
78
79
|
end
|
79
80
|
|
80
81
|
# @api public
|
@@ -89,11 +90,13 @@ module Acfs::Model
|
|
89
90
|
# class definition.
|
90
91
|
#
|
91
92
|
# @example
|
92
|
-
# user.write_attributes
|
93
|
+
# user.write_attributes name: 'john', email: ->{ "#{name}@example.org" }
|
93
94
|
# user.name # => 'john'
|
94
95
|
# user.email # => 'john@example.org'
|
95
96
|
#
|
96
|
-
# @param [
|
97
|
+
# @param [Hash{String, Symbol => Object, Proc}, #each{|key, value|}]
|
98
|
+
# Attributes to write.
|
99
|
+
#
|
97
100
|
# @see #write_attribute Delegates attribute values to `#write_attribute`.
|
98
101
|
#
|
99
102
|
def write_attributes(attributes, opts = {})
|
@@ -101,9 +104,11 @@ module Acfs::Model
|
|
101
104
|
return false
|
102
105
|
end
|
103
106
|
|
104
|
-
if opts.fetch(:unknown
|
107
|
+
if opts.fetch(:unknown, :ignore) == :raise
|
105
108
|
if (attributes.keys.map(&:to_s) - self.class.attributes.keys).any?
|
106
|
-
|
109
|
+
missing = attributes.keys - self.class.attributes.keys
|
110
|
+
missing.map!(&:inspect)
|
111
|
+
raise ArgumentError.new "Unknown attributes: #{missing.join(', ')}"
|
107
112
|
end
|
108
113
|
end
|
109
114
|
|
@@ -145,9 +150,9 @@ module Acfs::Model
|
|
145
150
|
# Write single attribute with given value. Value will be casted
|
146
151
|
# to defined attribute type.
|
147
152
|
#
|
148
|
-
# @param [
|
149
|
-
# @param [
|
150
|
-
# @raise [
|
153
|
+
# @param [String, Symbol] name Attribute name.
|
154
|
+
# @param [Object] value Value to write.
|
155
|
+
# @raise [ArgumentError] If no attribute with given name is defined.
|
151
156
|
#
|
152
157
|
def write_attribute(name, value, opts = {})
|
153
158
|
attr_type = self.class.defined_attributes[name.to_s]
|
@@ -164,15 +169,18 @@ module Acfs::Model
|
|
164
169
|
# value to attributes type. Value be stored in an instance variable
|
165
170
|
# named after attribute name.
|
166
171
|
#
|
167
|
-
# @param [
|
168
|
-
# @param [
|
172
|
+
# @param [String, Symbol] name Attribute name.
|
173
|
+
# @param [Object] value Attribute value.
|
169
174
|
#
|
170
175
|
def write_raw_attribute(name, value, _ = {})
|
171
|
-
|
176
|
+
attributes[name.to_s] = value
|
172
177
|
end
|
173
178
|
|
179
|
+
#
|
174
180
|
module ClassMethods
|
181
|
+
ATTR_CLASS_BASE = '::Acfs::Resource::Attributes'.freeze
|
175
182
|
|
183
|
+
#
|
176
184
|
# @api public
|
177
185
|
#
|
178
186
|
# Define a model attribute by name and type. Will create getter and
|
@@ -181,18 +189,18 @@ module Acfs::Model
|
|
181
189
|
# Available types can be found in `Acfs::Model::Attributes::*`.
|
182
190
|
#
|
183
191
|
# @example
|
184
|
-
# class User
|
185
|
-
# include Acfs::Model
|
192
|
+
# class User < Acfs::Resource
|
186
193
|
# attribute :name, :string, default: 'Anon'
|
187
194
|
# attribute :email, :string, default: lambda{ "#{name}@example.org"}
|
188
195
|
# end
|
189
196
|
#
|
190
|
-
# @param [
|
191
|
-
# @param [
|
197
|
+
# @param [#to_sym] name Attribute name.
|
198
|
+
# @param [Symbol, String, Class] type Attribute
|
199
|
+
# type identifier or type class.
|
192
200
|
#
|
193
201
|
def attribute(name, type, opts = {})
|
194
|
-
if type.is_a?
|
195
|
-
type = "
|
202
|
+
if type.is_a?(Symbol) || type.is_a?(String)
|
203
|
+
type = "#{ATTR_CLASS_BASE}::#{type.to_s.classify}".constantize
|
196
204
|
end
|
197
205
|
|
198
206
|
define_attribute name.to_sym, type, opts
|
@@ -200,20 +208,21 @@ module Acfs::Model
|
|
200
208
|
|
201
209
|
# @api public
|
202
210
|
#
|
203
|
-
# Return list of possible attributes and default
|
211
|
+
# Return list of possible attributes and default
|
212
|
+
# values for this model class.
|
204
213
|
#
|
205
214
|
# @example
|
206
|
-
# class User
|
207
|
-
# include Acfs::Model
|
215
|
+
# class User < Acfs::Resource
|
208
216
|
# attribute :name, :string
|
209
217
|
# attribute :age, :integer, default: 25
|
210
218
|
# end
|
211
219
|
# User.attributes # => { "name": nil, "age": 25 }
|
212
220
|
#
|
213
|
-
# @return [
|
221
|
+
# @return [Hash{String => Object, Proc}]
|
222
|
+
# Attributes with default values.
|
214
223
|
#
|
215
224
|
def attributes
|
216
|
-
|
225
|
+
{}.tap do |attrs|
|
217
226
|
defined_attributes.each do |key, attr|
|
218
227
|
attrs[key] = attr.default_value
|
219
228
|
end
|
@@ -221,7 +230,14 @@ module Acfs::Model
|
|
221
230
|
end
|
222
231
|
|
223
232
|
def defined_attributes
|
224
|
-
@attributes ||=
|
233
|
+
@attributes ||= begin
|
234
|
+
attributes = {}
|
235
|
+
if superclass.respond_to?(:defined_attributes)
|
236
|
+
attributes.merge superclass.defined_attributes
|
237
|
+
end
|
238
|
+
|
239
|
+
attributes
|
240
|
+
end
|
225
241
|
end
|
226
242
|
|
227
243
|
# @api public
|
@@ -229,32 +245,40 @@ module Acfs::Model
|
|
229
245
|
# Return hash of attributes and there types.
|
230
246
|
#
|
231
247
|
# @example
|
232
|
-
# class User
|
233
|
-
# include Acfs::Model
|
248
|
+
# class User < Acfs::Resource
|
234
249
|
# attribute :name, :string
|
235
250
|
# attribute :age, :integer, default: 25
|
236
251
|
# end
|
237
|
-
# User.attributes # => {
|
252
|
+
# User.attributes # => {"name": Acfs::Model::Attributes::String,
|
253
|
+
# # "age": Acfs::Model::Attributes::Integer}
|
238
254
|
#
|
239
|
-
# @return [
|
255
|
+
# @return [Hash{Symbol => Class}] Attributes and their types.
|
240
256
|
#
|
241
257
|
def attribute_types
|
242
|
-
@attribute_types ||=
|
258
|
+
@attribute_types ||= begin
|
259
|
+
attribute_types = {}
|
260
|
+
if superclass.respond_to?(:attribute_types)
|
261
|
+
attribute_types.merge superclass.attribute_types
|
262
|
+
end
|
263
|
+
|
264
|
+
attribute_types
|
265
|
+
end
|
243
266
|
end
|
244
267
|
|
245
268
|
private
|
269
|
+
|
246
270
|
def define_attribute(name, type, opts = {})
|
247
|
-
name
|
248
|
-
attribute
|
271
|
+
name = name.to_s
|
272
|
+
attribute = type.new opts
|
249
273
|
|
250
274
|
defined_attributes[name] = attribute
|
251
275
|
define_attribute_method name
|
252
276
|
|
253
|
-
|
277
|
+
send :define_method, name do
|
254
278
|
read_attribute name
|
255
279
|
end
|
256
280
|
|
257
|
-
|
281
|
+
send :define_method, :"#{name}=" do |value|
|
258
282
|
write_attribute name, value
|
259
283
|
end
|
260
284
|
end
|
@@ -266,5 +290,5 @@ end
|
|
266
290
|
#
|
267
291
|
Dir[File.dirname(__FILE__) + '/attributes/*.rb'].sort.each do |path|
|
268
292
|
filename = File.basename(path)
|
269
|
-
require "acfs/
|
293
|
+
require "acfs/resource/attributes/#{filename}"
|
270
294
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
module Acfs::
|
2
|
-
|
1
|
+
module Acfs::Resource::Attributes
|
2
|
+
#
|
3
3
|
class Base
|
4
4
|
attr_reader :options
|
5
5
|
|
@@ -9,15 +9,19 @@ module Acfs::Model::Attributes
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def nil_allowed?
|
12
|
-
|
12
|
+
options[:allow_nil]
|
13
13
|
end
|
14
14
|
|
15
15
|
def blank_allowed?
|
16
|
-
|
16
|
+
options[:allow_blank]
|
17
17
|
end
|
18
18
|
|
19
19
|
def default_value
|
20
|
-
options[:default].is_a?
|
20
|
+
if options[:default].is_a? Proc
|
21
|
+
options[:default]
|
22
|
+
else
|
23
|
+
cast options[:default]
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
def cast(obj)
|
@@ -25,7 +29,7 @@ module Acfs::Model::Attributes
|
|
25
29
|
cast_type obj
|
26
30
|
end
|
27
31
|
|
28
|
-
def cast_type(
|
32
|
+
def cast_type(_obj)
|
29
33
|
raise NotImplementedError
|
30
34
|
end
|
31
35
|
end
|