acfs 1.0.0.dev.1.b305 → 1.0.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 +5 -13
- data/CHANGELOG.md +64 -0
- data/README.md +2 -2
- data/acfs.gemspec +4 -4
- data/lib/acfs.rb +7 -5
- data/lib/acfs/adapter/base.rb +0 -2
- data/lib/acfs/adapter/typhoeus.rb +17 -13
- data/lib/acfs/collections/paginatable.rb +10 -10
- data/lib/acfs/configuration.rb +4 -5
- data/lib/acfs/errors.rb +10 -9
- data/lib/acfs/global.rb +16 -7
- data/lib/acfs/location.rb +11 -11
- data/lib/acfs/middleware/base.rb +1 -2
- data/lib/acfs/middleware/json.rb +27 -0
- data/lib/acfs/middleware/logger.rb +0 -2
- data/lib/acfs/middleware/msgpack.rb +30 -0
- data/lib/acfs/middleware/print.rb +0 -2
- data/lib/acfs/middleware/serializer.rb +39 -0
- data/lib/acfs/operation.rb +5 -5
- data/lib/acfs/request.rb +4 -4
- data/lib/acfs/request/callbacks.rb +2 -3
- data/lib/acfs/resource.rb +2 -2
- data/lib/acfs/resource/attributes.rb +10 -37
- data/lib/acfs/resource/attributes/base.rb +10 -19
- data/lib/acfs/resource/attributes/boolean.rb +10 -8
- data/lib/acfs/resource/attributes/date_time.rb +6 -9
- data/lib/acfs/resource/attributes/dict.rb +37 -0
- data/lib/acfs/resource/attributes/float.rb +11 -5
- data/lib/acfs/resource/attributes/integer.rb +7 -5
- data/lib/acfs/resource/attributes/list.rb +13 -6
- data/lib/acfs/resource/attributes/string.rb +3 -5
- data/lib/acfs/resource/attributes/uuid.rb +8 -17
- data/lib/acfs/resource/loadable.rb +0 -1
- data/lib/acfs/resource/locatable.rb +0 -4
- data/lib/acfs/resource/operational.rb +0 -2
- data/lib/acfs/resource/persistence.rb +17 -17
- data/lib/acfs/resource/query_methods.rb +3 -5
- data/lib/acfs/resource/service.rb +0 -2
- data/lib/acfs/resource/validation.rb +0 -2
- 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 +21 -11
- data/lib/acfs/service.rb +4 -6
- data/lib/acfs/service/middleware.rb +20 -30
- data/lib/acfs/service/middleware/stack.rb +63 -0
- data/lib/acfs/singleton_resource.rb +0 -2
- data/lib/acfs/stub.rb +30 -21
- data/lib/acfs/util.rb +1 -1
- data/lib/acfs/version.rb +4 -2
- data/spec/acfs/adapter/typhoeus_spec.rb +12 -4
- data/spec/acfs/collection_spec.rb +45 -33
- data/spec/acfs/configuration_spec.rb +9 -1
- data/spec/acfs/global_spec.rb +21 -3
- data/spec/acfs/middleware/json_spec.rb +63 -0
- data/spec/acfs/middleware/msgpack_spec.rb +60 -0
- data/spec/acfs/operation_spec.rb +10 -0
- data/spec/acfs/request/callbacks_spec.rb +8 -8
- data/spec/acfs/request_spec.rb +5 -5
- data/spec/acfs/resource/attributes/boolean_spec.rb +40 -9
- data/spec/acfs/resource/attributes/date_time_spec.rb +29 -35
- data/spec/acfs/resource/attributes/dict_spec.rb +75 -0
- data/spec/acfs/resource/attributes/float_spec.rb +48 -9
- data/spec/acfs/resource/attributes/integer_spec.rb +34 -0
- data/spec/acfs/resource/attributes/list_spec.rb +43 -19
- data/spec/acfs/resource/attributes/uuid_spec.rb +31 -54
- data/spec/acfs/resource/attributes_spec.rb +17 -31
- data/spec/acfs/resource/locatable_spec.rb +2 -2
- data/spec/acfs/resource/persistance_spec.rb +65 -34
- data/spec/acfs/resource/query_methods_spec.rb +87 -87
- data/spec/acfs/resource/validation_spec.rb +4 -5
- data/spec/acfs/response/formats_spec.rb +1 -1
- data/spec/acfs/response/status_spec.rb +1 -1
- data/spec/acfs/runner_spec.rb +28 -3
- data/spec/acfs/service/middleware_spec.rb +4 -20
- data/spec/acfs/service_spec.rb +3 -5
- data/spec/acfs/singleton_resource_spec.rb +1 -2
- data/spec/acfs/stub_spec.rb +137 -22
- data/spec/acfs_spec.rb +22 -19
- data/spec/spec_helper.rb +2 -1
- data/spec/support/service.rb +10 -6
- data/spec/support/shared/find_callbacks.rb +7 -7
- metadata +37 -30
- data/lib/acfs/middleware/json_decoder.rb +0 -16
- data/lib/acfs/middleware/json_encoder.rb +0 -20
- data/lib/acfs/middleware/msgpack_decoder.rb +0 -26
- data/lib/acfs/middleware/msgpack_encoder.rb +0 -19
- data/spec/acfs/middleware/json_decoder_spec.rb +0 -45
- data/spec/acfs/middleware/msgpack_decoder_spec.rb +0 -36
data/lib/acfs/middleware/base.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
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
|
#
|
@@ -13,7 +12,7 @@ module Acfs
|
|
13
12
|
end
|
14
13
|
|
15
14
|
def call(request)
|
16
|
-
request.on_complete {
|
15
|
+
request.on_complete {|res, nxt| response(res, nxt) } if respond_to? :response
|
17
16
|
app.call(request)
|
18
17
|
end
|
19
18
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
|
3
|
+
module Acfs
|
4
|
+
module Middleware
|
5
|
+
# A middleware to encore request data using JSON.
|
6
|
+
#
|
7
|
+
class JSON < Serializer
|
8
|
+
def mime
|
9
|
+
::Mime::JSON
|
10
|
+
end
|
11
|
+
|
12
|
+
def encode(data)
|
13
|
+
::MultiJson.dump data
|
14
|
+
end
|
15
|
+
|
16
|
+
def decode(body)
|
17
|
+
::MultiJson.load body
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @deprecated
|
22
|
+
JsonDecoder = JSON
|
23
|
+
|
24
|
+
# @deprecated
|
25
|
+
JsonEncoder = JSON
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'msgpack'
|
2
|
+
require 'action_dispatch'
|
3
|
+
|
4
|
+
module Acfs
|
5
|
+
module Middleware
|
6
|
+
class MessagePack < Serializer
|
7
|
+
unless defined?(::Mime::MSGPACK)
|
8
|
+
::Mime::Type.register 'application/x-msgpack', :msgpack
|
9
|
+
end
|
10
|
+
|
11
|
+
def mime
|
12
|
+
::Mime::MSGPACK
|
13
|
+
end
|
14
|
+
|
15
|
+
def encode(data)
|
16
|
+
::MessagePack.pack data
|
17
|
+
end
|
18
|
+
|
19
|
+
def decode(body)
|
20
|
+
::MessagePack.unpack body
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @deprecated
|
25
|
+
MessagePackEncoder = MessagePack
|
26
|
+
|
27
|
+
# @deprecated
|
28
|
+
MessagePackDecoder = MessagePack
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Acfs
|
2
|
+
module Middleware
|
3
|
+
# A base middleware that does not modify request or response.
|
4
|
+
# Can be used as super class for custom middleware implementations.
|
5
|
+
#
|
6
|
+
class Serializer < Base
|
7
|
+
def encode(_data)
|
8
|
+
raise NotImplementedError
|
9
|
+
end
|
10
|
+
|
11
|
+
def decode(_data)
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def mime
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(request)
|
20
|
+
unless request.headers['Content-Type']
|
21
|
+
request.body = encode request.data
|
22
|
+
request.headers['Content-Type'] = mime
|
23
|
+
end
|
24
|
+
|
25
|
+
accept = request.headers['Accept'].to_s.split(',')
|
26
|
+
accept << "#{mime};q=#{options.fetch(:q, 1)}"
|
27
|
+
request.headers['Accept'] = accept.join(',')
|
28
|
+
|
29
|
+
request.on_complete do |response, nxt|
|
30
|
+
response.data = decode response.body if mime == response.content_type
|
31
|
+
|
32
|
+
nxt.call response
|
33
|
+
end
|
34
|
+
|
35
|
+
app.call(request)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
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,15 +50,16 @@ 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
|
58
|
-
request = ::Acfs::Request.new url, method: method, params: params,
|
57
|
+
request = ::Acfs::Request.new url, method: method, params: params,
|
58
|
+
data: data, operation: self
|
59
59
|
request.on_complete do |response|
|
60
60
|
::ActiveSupport::Notifications.instrument 'acfs.operation.complete',
|
61
|
-
|
62
|
-
|
61
|
+
operation: self,
|
62
|
+
response: response
|
63
63
|
|
64
64
|
handle_failure response unless response.success?
|
65
65
|
callback.call response.data, response
|
data/lib/acfs/request.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
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
|
#
|
8
7
|
class Request
|
9
8
|
attr_accessor :body, :format
|
10
|
-
attr_reader :url, :headers, :params, :data, :method
|
9
|
+
attr_reader :url, :headers, :params, :data, :method, :operation
|
11
10
|
|
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) || {}
|
19
18
|
@params = options.delete(:params) || {}
|
20
19
|
@method = options.delete(:method) || :get
|
21
20
|
end.to_s
|
22
|
-
|
21
|
+
@operation = options.delete(:operation) || nil
|
22
|
+
on_complete(&block) if block_given?
|
23
23
|
end
|
24
24
|
|
25
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
@@ -17,8 +17,8 @@ class Acfs::Resource
|
|
17
17
|
if ActiveModel::VERSION::MAJOR >= 4
|
18
18
|
include ActiveModel::Model
|
19
19
|
else
|
20
|
-
extend
|
21
|
-
extend
|
20
|
+
extend ActiveModel::Naming
|
21
|
+
extend ActiveModel::Translation
|
22
22
|
include ActiveModel::Conversion
|
23
23
|
include ActiveModel::Validations
|
24
24
|
end
|
@@ -178,7 +178,6 @@ class Acfs::Resource
|
|
178
178
|
|
179
179
|
#
|
180
180
|
module ClassMethods
|
181
|
-
|
182
181
|
ATTR_CLASS_BASE = '::Acfs::Resource::Attributes'.freeze
|
183
182
|
|
184
183
|
#
|
@@ -223,56 +222,30 @@ class Acfs::Resource
|
|
223
222
|
# Attributes with default values.
|
224
223
|
#
|
225
224
|
def attributes
|
226
|
-
|
227
|
-
|
228
|
-
attrs[key] = attr.default_value
|
229
|
-
end
|
225
|
+
defined_attributes.each_with_object({}) do |(key, attr), hash|
|
226
|
+
hash[key] = attr.default_value
|
230
227
|
end
|
231
228
|
end
|
232
229
|
|
233
230
|
def defined_attributes
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
end
|
239
|
-
|
240
|
-
attributes
|
231
|
+
if superclass.respond_to?(:defined_attributes)
|
232
|
+
superclass.defined_attributes.merge(local_attributes)
|
233
|
+
else
|
234
|
+
local_attributes
|
241
235
|
end
|
242
236
|
end
|
243
237
|
|
244
|
-
|
245
|
-
#
|
246
|
-
# Return hash of attributes and there types.
|
247
|
-
#
|
248
|
-
# @example
|
249
|
-
# class User < Acfs::Resource
|
250
|
-
# attribute :name, :string
|
251
|
-
# attribute :age, :integer, default: 25
|
252
|
-
# end
|
253
|
-
# User.attributes # => {"name": Acfs::Model::Attributes::String,
|
254
|
-
# # "age": Acfs::Model::Attributes::Integer}
|
255
|
-
#
|
256
|
-
# @return [Hash{Symbol => Class}] Attributes and their types.
|
257
|
-
#
|
258
|
-
def attribute_types
|
259
|
-
@attribute_types ||= begin
|
260
|
-
attribute_types = {}
|
261
|
-
if superclass.respond_to?(:attribute_types)
|
262
|
-
attribute_types.merge superclass.attribute_types
|
263
|
-
end
|
238
|
+
private
|
264
239
|
|
265
|
-
|
266
|
-
|
240
|
+
def local_attributes
|
241
|
+
@local_attributes ||= {}
|
267
242
|
end
|
268
243
|
|
269
|
-
private
|
270
|
-
|
271
244
|
def define_attribute(name, type, opts = {})
|
272
245
|
name = name.to_s
|
273
246
|
attribute = type.new opts
|
274
247
|
|
275
|
-
|
248
|
+
local_attributes[name] = attribute
|
276
249
|
define_attribute_method name
|
277
250
|
|
278
251
|
send :define_method, name do
|
@@ -1,36 +1,27 @@
|
|
1
1
|
module Acfs::Resource::Attributes
|
2
|
-
|
3
2
|
#
|
4
3
|
class Base
|
5
|
-
attr_reader :
|
6
|
-
|
7
|
-
def initialize(opts = {})
|
8
|
-
@options = opts
|
9
|
-
@options.reverse_merge! allow_nil: true
|
10
|
-
end
|
4
|
+
attr_reader :default
|
11
5
|
|
12
|
-
def
|
13
|
-
|
6
|
+
def initialize(default: nil)
|
7
|
+
@default = default
|
14
8
|
end
|
15
9
|
|
16
|
-
def
|
17
|
-
|
10
|
+
def cast(value)
|
11
|
+
cast_value(value) unless value.nil?
|
18
12
|
end
|
19
13
|
|
20
14
|
def default_value
|
21
|
-
if
|
22
|
-
|
15
|
+
if default.respond_to? :call
|
16
|
+
default
|
23
17
|
else
|
24
|
-
cast
|
18
|
+
cast default
|
25
19
|
end
|
26
20
|
end
|
27
21
|
|
28
|
-
|
29
|
-
return nil if obj.nil? && nil_allowed? || (obj == '' && blank_allowed?)
|
30
|
-
cast_type obj
|
31
|
-
end
|
22
|
+
private
|
32
23
|
|
33
|
-
def
|
24
|
+
def cast_value(_value)
|
34
25
|
raise NotImplementedError
|
35
26
|
end
|
36
27
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Acfs::Resource::Attributes
|
2
|
-
|
3
2
|
# @api public
|
4
3
|
#
|
5
4
|
# Boolean attribute type. Use it in your model as an attribute type:
|
@@ -15,21 +14,24 @@ module Acfs::Resource::Attributes
|
|
15
14
|
# true, on, yes
|
16
15
|
#
|
17
16
|
class Boolean < Base
|
18
|
-
|
19
|
-
TRUE_VALUES = %w(true on yes 1)
|
17
|
+
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF', 'no', 'NO'].to_set
|
20
18
|
|
21
19
|
# @api public
|
22
20
|
#
|
23
21
|
# Cast given object to boolean.
|
24
22
|
#
|
25
|
-
# @param [Object]
|
23
|
+
# @param [Object] value Object to cast.
|
26
24
|
# @return [TrueClass, FalseClass] Casted boolean.
|
27
25
|
#
|
28
|
-
def
|
29
|
-
return true if
|
30
|
-
return false if
|
26
|
+
def cast_value(value)
|
27
|
+
return true if value == true
|
28
|
+
return false if value == false
|
31
29
|
|
32
|
-
|
30
|
+
if value.blank?
|
31
|
+
nil
|
32
|
+
else
|
33
|
+
!FALSE_VALUES.include?(value)
|
34
|
+
end
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Acfs::Resource::Attributes
|
2
|
-
|
3
2
|
# @api public
|
4
3
|
#
|
5
4
|
# DateTime attribute type. Use it in your model as
|
@@ -16,18 +15,16 @@ module Acfs::Resource::Attributes
|
|
16
15
|
#
|
17
16
|
# Cast given object to DateTime.
|
18
17
|
#
|
19
|
-
# @param [Object]
|
18
|
+
# @param [Object] value Object to cast.
|
20
19
|
# @return [DateTime] Casted object as DateTime.
|
21
20
|
#
|
22
|
-
def
|
23
|
-
if
|
21
|
+
def cast_value(value)
|
22
|
+
if value.blank?
|
24
23
|
nil
|
25
|
-
elsif
|
26
|
-
|
27
|
-
elsif obj.is_a?(Time) || obj.is_a?(Date)
|
28
|
-
::DateTime.iso8601 obj.iso8601
|
24
|
+
elsif value.acts_like?(:time) || value.acts_like?(:date)
|
25
|
+
value.to_datetime
|
29
26
|
else
|
30
|
-
::DateTime.iso8601
|
27
|
+
::DateTime.iso8601 value
|
31
28
|
end
|
32
29
|
end
|
33
30
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Acfs::Resource::Attributes
|
2
|
+
# @api public
|
3
|
+
#
|
4
|
+
# Dict attribute type. Use it in your model as an attribute type:
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class User
|
8
|
+
# include Acfs::Model
|
9
|
+
# attribute :opts, :dict
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
class Dict < Base
|
13
|
+
# @api public
|
14
|
+
#
|
15
|
+
# Cast given object to a dict/hash.
|
16
|
+
#
|
17
|
+
# @param [Object] value Object to cast.
|
18
|
+
# @return [Hash] Casted object as hash.
|
19
|
+
# @raise [TypeError] If object cannot be casted to a hash.
|
20
|
+
#
|
21
|
+
def cast_value(value)
|
22
|
+
return {} if value.blank?
|
23
|
+
|
24
|
+
if value.is_a?(Hash)
|
25
|
+
value
|
26
|
+
elsif value.respond_to?(:serializable_hash)
|
27
|
+
value.serializable_hash
|
28
|
+
elsif value.respond_to?(:to_hash)
|
29
|
+
value.to_hash
|
30
|
+
elsif value.respond_to?(:to_h)
|
31
|
+
value.to_h
|
32
|
+
else
|
33
|
+
Hash(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|