acfs 0.42.0 → 0.43.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 +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
|