acfs 0.45.0 → 0.50.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 -5
- data/CHANGELOG.md +34 -0
- data/README.md +0 -1
- data/acfs.gemspec +3 -3
- data/lib/acfs/middleware/json.rb +1 -1
- data/lib/acfs/middleware/msgpack.rb +1 -1
- data/lib/acfs/resource/attributes/base.rb +10 -18
- data/lib/acfs/resource/attributes/boolean.rb +10 -6
- data/lib/acfs/resource/attributes/date_time.rb +7 -8
- data/lib/acfs/resource/attributes/dict.rb +15 -5
- data/lib/acfs/resource/attributes/float.rb +11 -3
- data/lib/acfs/resource/attributes/integer.rb +7 -7
- data/lib/acfs/resource/attributes/list.rb +13 -4
- data/lib/acfs/resource/attributes/string.rb +3 -3
- data/lib/acfs/resource/attributes/uuid.rb +8 -15
- data/lib/acfs/resource/attributes.rb +11 -37
- data/lib/acfs/resource/dirty.rb +3 -15
- data/lib/acfs/resource/query_methods.rb +5 -2
- data/lib/acfs/resource/validation.rb +4 -2
- data/lib/acfs/response/formats.rb +1 -1
- data/lib/acfs/service/middleware/stack.rb +38 -9
- data/lib/acfs/version.rb +1 -1
- 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 +54 -29
- data/spec/acfs/resource/attributes/float_spec.rb +48 -9
- data/spec/acfs/resource/attributes/integer_spec.rb +23 -8
- 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 +10 -24
- data/spec/acfs/resource/query_methods_spec.rb +10 -3
- data/spec/acfs/response/formats_spec.rb +3 -3
- data/spec/spec_helper.rb +1 -1
- metadata +9 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5f6205aca10d63d37898eecce39e239605fc0a4165d17a9ad994ead94e0037dd
|
|
4
|
+
data.tar.gz: e1dac804253b61cabd8d5e9410784268c689771fedb9bdcad8c99a67e0b946ef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 150fd36e55507f600437fe65dc3d853379799b6f5afc30c0aaa9644e36d4e025fa3ced557569f6af9e8cbbb8e484ede41281cefac7ceaecda3d6957647e5b76b
|
|
7
|
+
data.tar.gz: 206228583c974b3ef735d1cfb524938595856bd8741e481c80b331da1779839c4ab31073f34d615561d68f53955ea5f58c501c2d5208039522e5296233d002aa
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
* Add Rails 5.2 compatibility
|
|
6
|
+
|
|
7
|
+
## 1.1.1
|
|
8
|
+
|
|
9
|
+
* `each_item`: Pass collection to provided block (#40)
|
|
10
|
+
|
|
11
|
+
## 1.1.0
|
|
12
|
+
|
|
13
|
+
* Add support for Rails 5.1
|
|
14
|
+
|
|
15
|
+
## 1.0.1
|
|
16
|
+
|
|
17
|
+
* Fix deprecation warnings when using ::Mime
|
|
18
|
+
|
|
19
|
+
## 1.0.0
|
|
20
|
+
|
|
21
|
+
* Switch to first non-development major as it's long time used in production.
|
|
22
|
+
* Fix NewRelic RPM inference with middleware stack inherited from `ActionDispatch::MiddlewareStack`.
|
|
23
|
+
|
|
24
|
+
## 0.48.0
|
|
25
|
+
|
|
26
|
+
* Remove #attribute_types broke since f7e4109 (Sep 2013, v0.23)
|
|
27
|
+
* Fix attribute inheritance on subclassing broken since commit 7cf1d11 (Apr 2014, v0.43)
|
|
28
|
+
|
|
29
|
+
## 0.47.0
|
|
30
|
+
|
|
31
|
+
* Change blank value handling of dict and list type (0a12ef1)
|
|
32
|
+
|
|
33
|
+
## 0.46.0
|
|
34
|
+
|
|
35
|
+
* Rework types system (#39)
|
|
36
|
+
|
|
3
37
|
## 0.45.0
|
|
4
38
|
|
|
5
39
|
* Fetching multiple records (`find(ary)`) is stable now, but untested (#38)
|
data/README.md
CHANGED
|
@@ -313,7 +313,6 @@ Read [official guide][2] to see to to subscribe.
|
|
|
313
313
|
* Reusing model definitions for generating responses?
|
|
314
314
|
* Rails responders providing REST operations with integrated ETag,
|
|
315
315
|
Modified Headers, conflict detection, ...
|
|
316
|
-
* Pagination? Filtering? (If service API provides such features.)
|
|
317
316
|
* Documentation
|
|
318
317
|
|
|
319
318
|
## Contributing
|
data/acfs.gemspec
CHANGED
|
@@ -18,9 +18,9 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
19
|
spec.require_paths = %w(lib)
|
|
20
20
|
|
|
21
|
-
spec.add_runtime_dependency 'activesupport', '>=
|
|
22
|
-
spec.add_runtime_dependency 'activemodel', '>=
|
|
23
|
-
spec.add_runtime_dependency 'actionpack', '>=
|
|
21
|
+
spec.add_runtime_dependency 'activesupport', '>= 4.2'
|
|
22
|
+
spec.add_runtime_dependency 'activemodel', '>= 4.2'
|
|
23
|
+
spec.add_runtime_dependency 'actionpack', '>= 4.2'
|
|
24
24
|
spec.add_runtime_dependency 'multi_json'
|
|
25
25
|
|
|
26
26
|
# Bundle update w/o version resolves to 0.3.3 ...
|
data/lib/acfs/middleware/json.rb
CHANGED
|
@@ -1,35 +1,27 @@
|
|
|
1
1
|
module Acfs::Resource::Attributes
|
|
2
2
|
#
|
|
3
3
|
class Base
|
|
4
|
-
attr_reader :
|
|
4
|
+
attr_reader :default
|
|
5
5
|
|
|
6
|
-
def initialize(
|
|
7
|
-
@
|
|
8
|
-
@options.reverse_merge! allow_nil: true
|
|
6
|
+
def initialize(default: nil)
|
|
7
|
+
@default = default
|
|
9
8
|
end
|
|
10
9
|
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def blank_allowed?
|
|
16
|
-
options[:allow_blank]
|
|
10
|
+
def cast(value)
|
|
11
|
+
cast_value(value) unless value.nil?
|
|
17
12
|
end
|
|
18
13
|
|
|
19
14
|
def default_value
|
|
20
|
-
if
|
|
21
|
-
|
|
15
|
+
if default.respond_to? :call
|
|
16
|
+
default
|
|
22
17
|
else
|
|
23
|
-
cast
|
|
18
|
+
cast default
|
|
24
19
|
end
|
|
25
20
|
end
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
return nil if obj.nil? && nil_allowed? || (obj == '' && blank_allowed?)
|
|
29
|
-
cast_type obj
|
|
30
|
-
end
|
|
22
|
+
private
|
|
31
23
|
|
|
32
|
-
def
|
|
24
|
+
def cast_value(_value)
|
|
33
25
|
raise NotImplementedError
|
|
34
26
|
end
|
|
35
27
|
end
|
|
@@ -14,20 +14,24 @@ module Acfs::Resource::Attributes
|
|
|
14
14
|
# true, on, yes
|
|
15
15
|
#
|
|
16
16
|
class Boolean < Base
|
|
17
|
-
|
|
17
|
+
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF', 'no', 'NO'].to_set
|
|
18
18
|
|
|
19
19
|
# @api public
|
|
20
20
|
#
|
|
21
21
|
# Cast given object to boolean.
|
|
22
22
|
#
|
|
23
|
-
# @param [Object]
|
|
23
|
+
# @param [Object] value Object to cast.
|
|
24
24
|
# @return [TrueClass, FalseClass] Casted boolean.
|
|
25
25
|
#
|
|
26
|
-
def
|
|
27
|
-
return true if
|
|
28
|
-
return false if
|
|
26
|
+
def cast_value(value)
|
|
27
|
+
return true if value == true
|
|
28
|
+
return false if value == false
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
if value.blank?
|
|
31
|
+
nil
|
|
32
|
+
else
|
|
33
|
+
!FALSE_VALUES.include?(value)
|
|
34
|
+
end
|
|
31
35
|
end
|
|
32
36
|
end
|
|
33
37
|
end
|
|
@@ -10,22 +10,21 @@ module Acfs::Resource::Attributes
|
|
|
10
10
|
# end
|
|
11
11
|
#
|
|
12
12
|
class DateTime < Base
|
|
13
|
+
|
|
13
14
|
# @api public
|
|
14
15
|
#
|
|
15
16
|
# Cast given object to DateTime.
|
|
16
17
|
#
|
|
17
|
-
# @param [Object]
|
|
18
|
+
# @param [Object] value Object to cast.
|
|
18
19
|
# @return [DateTime] Casted object as DateTime.
|
|
19
20
|
#
|
|
20
|
-
def
|
|
21
|
-
if
|
|
21
|
+
def cast_value(value)
|
|
22
|
+
if value.blank?
|
|
22
23
|
nil
|
|
23
|
-
elsif
|
|
24
|
-
|
|
25
|
-
elsif obj.is_a?(Time) || obj.is_a?(Date)
|
|
26
|
-
::DateTime.iso8601 obj.iso8601
|
|
24
|
+
elsif value.acts_like?(:time) || value.acts_like?(:date)
|
|
25
|
+
value.to_datetime
|
|
27
26
|
else
|
|
28
|
-
::DateTime.iso8601
|
|
27
|
+
::DateTime.iso8601 value
|
|
29
28
|
end
|
|
30
29
|
end
|
|
31
30
|
end
|
|
@@ -14,14 +14,24 @@ module Acfs::Resource::Attributes
|
|
|
14
14
|
#
|
|
15
15
|
# Cast given object to a dict/hash.
|
|
16
16
|
#
|
|
17
|
-
# @param [Object]
|
|
17
|
+
# @param [Object] value Object to cast.
|
|
18
18
|
# @return [Hash] Casted object as hash.
|
|
19
19
|
# @raise [TypeError] If object cannot be casted to a hash.
|
|
20
20
|
#
|
|
21
|
-
def
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
|
|
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
|
|
25
35
|
end
|
|
26
36
|
end
|
|
27
37
|
end
|
|
@@ -13,11 +13,19 @@ module Acfs::Resource::Attributes
|
|
|
13
13
|
#
|
|
14
14
|
# Cast given object to float.
|
|
15
15
|
#
|
|
16
|
-
# @param [Object]
|
|
16
|
+
# @param [Object] value Object to cast.
|
|
17
17
|
# @return [Float] Casted object as float.
|
|
18
18
|
#
|
|
19
|
-
def
|
|
20
|
-
|
|
19
|
+
def cast_value(value)
|
|
20
|
+
return 0.0 if value.blank?
|
|
21
|
+
|
|
22
|
+
case value
|
|
23
|
+
when ::Float then value
|
|
24
|
+
when "Infinity" then ::Float::INFINITY
|
|
25
|
+
when "-Infinity" then -::Float::INFINITY
|
|
26
|
+
when "NaN" then ::Float::NAN
|
|
27
|
+
else Float(value)
|
|
28
|
+
end
|
|
21
29
|
end
|
|
22
30
|
end
|
|
23
31
|
end
|
|
@@ -13,15 +13,15 @@ module Acfs::Resource::Attributes
|
|
|
13
13
|
#
|
|
14
14
|
# Cast given object to integer.
|
|
15
15
|
#
|
|
16
|
-
# @param [Object]
|
|
16
|
+
# @param [Object] value Object to cast.
|
|
17
17
|
# @return [Fixnum] Casted object as fixnum.
|
|
18
18
|
#
|
|
19
|
-
def
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
def cast_value(value)
|
|
20
|
+
if value.blank?
|
|
21
|
+
0
|
|
22
|
+
else
|
|
23
|
+
Integer(value)
|
|
24
|
+
end
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
end
|
|
@@ -13,13 +13,22 @@ module Acfs::Resource::Attributes
|
|
|
13
13
|
#
|
|
14
14
|
# Cast given object to a list.
|
|
15
15
|
#
|
|
16
|
-
# @param [Object]
|
|
16
|
+
# @param [Object] value Object to cast.
|
|
17
17
|
# @return [Fixnum] Casted object as list.
|
|
18
18
|
# @raise [TypeError] If object cannot be casted to a list.
|
|
19
19
|
#
|
|
20
|
-
def
|
|
21
|
-
return
|
|
22
|
-
|
|
20
|
+
def cast_value(value)
|
|
21
|
+
return [] if value.blank?
|
|
22
|
+
|
|
23
|
+
if value.is_a?(::Array)
|
|
24
|
+
value
|
|
25
|
+
elsif value.respond_to?(:to_ary)
|
|
26
|
+
value.to_ary
|
|
27
|
+
elsif value.respond_to?(:to_a)
|
|
28
|
+
value.to_a
|
|
29
|
+
else
|
|
30
|
+
Array(value)
|
|
31
|
+
end
|
|
23
32
|
end
|
|
24
33
|
end
|
|
25
34
|
end
|
|
@@ -14,11 +14,11 @@ module Acfs::Resource::Attributes
|
|
|
14
14
|
#
|
|
15
15
|
# Cast given object to string.
|
|
16
16
|
#
|
|
17
|
-
# @param [Object]
|
|
17
|
+
# @param [Object] value Object to cast.
|
|
18
18
|
# @return [String] Casted string.
|
|
19
19
|
#
|
|
20
|
-
def
|
|
21
|
-
|
|
20
|
+
def cast_value(value)
|
|
21
|
+
value.to_s
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
end
|
|
@@ -10,7 +10,7 @@ module Acfs::Resource::Attributes
|
|
|
10
10
|
#
|
|
11
11
|
class UUID < Base
|
|
12
12
|
#
|
|
13
|
-
|
|
13
|
+
UUID_REGEXP = /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/i
|
|
14
14
|
|
|
15
15
|
# @api public
|
|
16
16
|
#
|
|
@@ -28,23 +28,16 @@ module Acfs::Resource::Attributes
|
|
|
28
28
|
# | 4 | 4 |
|
|
29
29
|
# | 5 | 12 |
|
|
30
30
|
#
|
|
31
|
-
# @param [Object]
|
|
31
|
+
# @param [Object] value Object to cast.
|
|
32
32
|
# @return [String] Casted object as UUID.
|
|
33
33
|
#
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def cast_string(str)
|
|
41
|
-
if nil_allowed? && str.blank?
|
|
42
|
-
return nil
|
|
43
|
-
elsif str =~ REGEXP
|
|
44
|
-
str
|
|
34
|
+
def cast_value(value)
|
|
35
|
+
if value.blank?
|
|
36
|
+
nil
|
|
37
|
+
elsif value.to_s =~ UUID_REGEXP
|
|
38
|
+
value
|
|
45
39
|
else
|
|
46
|
-
raise
|
|
47
|
-
'does not look like a UUID'
|
|
40
|
+
raise TypeError.new "Invalid UUID: `#{value.to_s}'"
|
|
48
41
|
end
|
|
49
42
|
end
|
|
50
43
|
end
|
|
@@ -47,7 +47,7 @@ class Acfs::Resource
|
|
|
47
47
|
# Attributes and their values.
|
|
48
48
|
#
|
|
49
49
|
def attributes
|
|
50
|
-
@
|
|
50
|
+
@_attrs ||= HashWithIndifferentAccess.new
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# @api public
|
|
@@ -222,56 +222,30 @@ class Acfs::Resource
|
|
|
222
222
|
# Attributes with default values.
|
|
223
223
|
#
|
|
224
224
|
def attributes
|
|
225
|
-
{}
|
|
226
|
-
|
|
227
|
-
attrs[key] = attr.default_value
|
|
228
|
-
end
|
|
225
|
+
defined_attributes.each_with_object({}) do |(key, attr), hash|
|
|
226
|
+
hash[key] = attr.default_value
|
|
229
227
|
end
|
|
230
228
|
end
|
|
231
229
|
|
|
232
230
|
def defined_attributes
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
attributes
|
|
231
|
+
if superclass.respond_to?(:defined_attributes)
|
|
232
|
+
superclass.defined_attributes.merge(local_attributes)
|
|
233
|
+
else
|
|
234
|
+
local_attributes
|
|
240
235
|
end
|
|
241
236
|
end
|
|
242
237
|
|
|
243
|
-
|
|
244
|
-
#
|
|
245
|
-
# Return hash of attributes and there types.
|
|
246
|
-
#
|
|
247
|
-
# @example
|
|
248
|
-
# class User < Acfs::Resource
|
|
249
|
-
# attribute :name, :string
|
|
250
|
-
# attribute :age, :integer, default: 25
|
|
251
|
-
# end
|
|
252
|
-
# User.attributes # => {"name": Acfs::Model::Attributes::String,
|
|
253
|
-
# # "age": Acfs::Model::Attributes::Integer}
|
|
254
|
-
#
|
|
255
|
-
# @return [Hash{Symbol => Class}] Attributes and their types.
|
|
256
|
-
#
|
|
257
|
-
def 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
|
|
238
|
+
private
|
|
263
239
|
|
|
264
|
-
|
|
265
|
-
|
|
240
|
+
def local_attributes
|
|
241
|
+
@local_attributes ||= {}
|
|
266
242
|
end
|
|
267
243
|
|
|
268
|
-
private
|
|
269
|
-
|
|
270
244
|
def define_attribute(name, type, opts = {})
|
|
271
245
|
name = name.to_s
|
|
272
246
|
attribute = type.new opts
|
|
273
247
|
|
|
274
|
-
|
|
248
|
+
local_attributes[name] = attribute
|
|
275
249
|
define_attribute_method name
|
|
276
250
|
|
|
277
251
|
send :define_method, name do
|
data/lib/acfs/resource/dirty.rb
CHANGED
|
@@ -8,26 +8,14 @@ class Acfs::Resource
|
|
|
8
8
|
|
|
9
9
|
# @api private
|
|
10
10
|
#
|
|
11
|
-
# Resets all changes. Does not touch previous changes.
|
|
12
|
-
#
|
|
13
11
|
def reset_changes
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# @api private
|
|
18
|
-
#
|
|
19
|
-
# Save current changes as previous changes and reset
|
|
20
|
-
# current one.
|
|
21
|
-
#
|
|
22
|
-
def swap_changes
|
|
23
|
-
@previously_changed = changes
|
|
24
|
-
reset_changes
|
|
12
|
+
clear_changes_information
|
|
25
13
|
end
|
|
26
14
|
|
|
27
15
|
# @api private
|
|
28
16
|
#
|
|
29
17
|
def save!(*)
|
|
30
|
-
super.tap {|_|
|
|
18
|
+
super.tap {|_| changes_applied }
|
|
31
19
|
end
|
|
32
20
|
|
|
33
21
|
# @api private
|
|
@@ -40,7 +28,7 @@ class Acfs::Resource
|
|
|
40
28
|
# @api private
|
|
41
29
|
#
|
|
42
30
|
def write_raw_attribute(name, value, opts = {})
|
|
43
|
-
attribute_will_change!
|
|
31
|
+
attribute_will_change!(name) if opts[:change].nil? || opts[:change]
|
|
44
32
|
super
|
|
45
33
|
end
|
|
46
34
|
end
|
|
@@ -193,10 +193,13 @@ class Acfs::Resource
|
|
|
193
193
|
#
|
|
194
194
|
# @yield [item] Callback that will be invoked for each item.
|
|
195
195
|
# @yieldparam item [self] Resource.
|
|
196
|
+
# @yieldparam collection [Acfs::Collection] Collection.
|
|
196
197
|
#
|
|
197
|
-
def each_item(opts = {}
|
|
198
|
+
def each_item(opts = {})
|
|
198
199
|
each_page(opts) do |collection|
|
|
199
|
-
collection.each
|
|
200
|
+
collection.each do |item|
|
|
201
|
+
yield item, collection
|
|
202
|
+
end
|
|
200
203
|
end
|
|
201
204
|
end
|
|
202
205
|
|
|
@@ -13,8 +13,10 @@ class Acfs::Resource
|
|
|
13
13
|
|
|
14
14
|
def remote_errors=(errors)
|
|
15
15
|
(errors || []).each do |field, errs|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
errs.each do |err|
|
|
17
|
+
self.errors.add field.to_sym, err
|
|
18
|
+
remote_errors.add field.to_sym, err
|
|
19
|
+
end
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
|
|
@@ -1,28 +1,57 @@
|
|
|
1
|
-
require 'action_dispatch/middleware/stack'
|
|
2
|
-
|
|
3
1
|
module Acfs
|
|
4
2
|
class Service
|
|
5
3
|
module Middleware
|
|
6
|
-
class Stack
|
|
4
|
+
class Stack
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
7
|
MUTEX = Mutex.new
|
|
8
8
|
IDENTITY = -> (i) { i }
|
|
9
9
|
|
|
10
|
+
attr_reader :middlewares
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@middlewares = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def call(request)
|
|
17
|
+
build! unless @app
|
|
18
|
+
|
|
19
|
+
@app.call request
|
|
20
|
+
end
|
|
21
|
+
|
|
10
22
|
def build!
|
|
23
|
+
return if @app
|
|
24
|
+
|
|
11
25
|
MUTEX.synchronize do
|
|
12
|
-
return if @
|
|
26
|
+
return if @app
|
|
13
27
|
|
|
14
|
-
@
|
|
28
|
+
@app = build
|
|
15
29
|
end
|
|
16
30
|
end
|
|
17
31
|
|
|
18
32
|
def build(app = IDENTITY)
|
|
19
|
-
|
|
33
|
+
middlewares.reverse.inject(app) do |next_middleware, current_middleware|
|
|
34
|
+
klass, args, block = current_middleware
|
|
35
|
+
args ||= []
|
|
36
|
+
|
|
37
|
+
if klass.is_a?(Class)
|
|
38
|
+
klass.new(next_middleware, *args, &block)
|
|
39
|
+
elsif klass.respond_to?(:call)
|
|
40
|
+
lambda do |env|
|
|
41
|
+
next_middleware.call(klass.call(env, *args))
|
|
42
|
+
end
|
|
43
|
+
else
|
|
44
|
+
fail "Invalid middleware, doesn't respond to `call`: #{klass.inspect}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
20
47
|
end
|
|
21
48
|
|
|
22
|
-
def
|
|
23
|
-
|
|
49
|
+
def insert(index, klass, *args, &block)
|
|
50
|
+
middlewares.insert(index, [klass, args, block])
|
|
51
|
+
end
|
|
24
52
|
|
|
25
|
-
|
|
53
|
+
def each
|
|
54
|
+
middlewares.each { |x| yield x.first }
|
|
26
55
|
end
|
|
27
56
|
|
|
28
57
|
def clear
|
data/lib/acfs/version.rb
CHANGED
|
@@ -3,23 +3,54 @@ require 'spec_helper'
|
|
|
3
3
|
describe Acfs::Resource::Attributes::Boolean do
|
|
4
4
|
subject { Acfs::Resource::Attributes::Boolean.new }
|
|
5
5
|
|
|
6
|
-
describe 'cast' do
|
|
7
|
-
it '
|
|
6
|
+
describe '#cast' do
|
|
7
|
+
it 'casts nil' do
|
|
8
|
+
expect(subject.cast(nil)).to eq nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'casts empty string to false' do
|
|
12
|
+
expect(subject.cast('')).to eq nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'casts blank string to false' do
|
|
16
|
+
expect(subject.cast(" \t")).to eq nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'preserves boolean values' do
|
|
8
20
|
expect(subject.cast(false)).to eq false
|
|
9
21
|
expect(subject.cast(true)).to eq true
|
|
10
22
|
end
|
|
11
23
|
|
|
12
|
-
it '
|
|
24
|
+
it 'casts falsy values to false' do
|
|
25
|
+
expect(subject.cast(false)).to eq false
|
|
26
|
+
expect(subject.cast(0)).to eq false
|
|
27
|
+
expect(subject.cast('0')).to eq false
|
|
28
|
+
expect(subject.cast('no')).to eq false
|
|
29
|
+
expect(subject.cast('NO')).to eq false
|
|
30
|
+
expect(subject.cast('off')).to eq false
|
|
31
|
+
expect(subject.cast('OFF')).to eq false
|
|
32
|
+
expect(subject.cast('false')).to eq false
|
|
33
|
+
expect(subject.cast('FALSE')).to eq false
|
|
34
|
+
expect(subject.cast('f')).to eq false
|
|
35
|
+
expect(subject.cast('F')).to eq false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'casts any other value to true' do
|
|
39
|
+
expect(subject.cast(true)).to eq true
|
|
40
|
+
expect(subject.cast(1)).to eq true
|
|
41
|
+
expect(subject.cast('1')).to eq true
|
|
13
42
|
expect(subject.cast('yes')).to eq true
|
|
43
|
+
expect(subject.cast('YES')).to eq true
|
|
14
44
|
expect(subject.cast('on')).to eq true
|
|
45
|
+
expect(subject.cast('ON')).to eq true
|
|
15
46
|
expect(subject.cast('true')).to eq true
|
|
16
|
-
expect(subject.cast('
|
|
17
|
-
|
|
47
|
+
expect(subject.cast('TRUE')).to eq true
|
|
48
|
+
expect(subject.cast('t')).to eq true
|
|
49
|
+
expect(subject.cast('T')).to eq true
|
|
18
50
|
|
|
19
|
-
|
|
20
|
-
expect(subject.cast('')).to eq
|
|
21
|
-
expect(subject.cast('
|
|
22
|
-
expect(subject.cast('random')).to eq false
|
|
51
|
+
expect(subject.cast(2)).to eq true
|
|
52
|
+
expect(subject.cast('wrong')).to eq true
|
|
53
|
+
expect(subject.cast('random')).to eq true
|
|
23
54
|
end
|
|
24
55
|
end
|
|
25
56
|
end
|