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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +8 -9
  4. data/acfs.gemspec +3 -3
  5. data/lib/acfs.rb +0 -2
  6. data/lib/acfs/adapter/base.rb +0 -2
  7. data/lib/acfs/adapter/typhoeus.rb +6 -9
  8. data/lib/acfs/collection.rb +3 -3
  9. data/lib/acfs/collections/paginatable.rb +16 -16
  10. data/lib/acfs/configuration.rb +3 -5
  11. data/lib/acfs/errors.rb +8 -7
  12. data/lib/acfs/global.rb +1 -1
  13. data/lib/acfs/location.rb +11 -11
  14. data/lib/acfs/middleware/base.rb +1 -2
  15. data/lib/acfs/middleware/json.rb +0 -1
  16. data/lib/acfs/middleware/logger.rb +0 -2
  17. data/lib/acfs/middleware/print.rb +0 -2
  18. data/lib/acfs/middleware/serializer.rb +3 -6
  19. data/lib/acfs/operation.rb +3 -4
  20. data/lib/acfs/request.rb +2 -3
  21. data/lib/acfs/request/callbacks.rb +2 -3
  22. data/lib/acfs/resource.rb +34 -5
  23. data/lib/acfs/{model → resource}/attributes.rb +70 -46
  24. data/lib/acfs/{model → resource}/attributes/base.rb +10 -6
  25. data/lib/acfs/resource/attributes/boolean.rb +33 -0
  26. data/lib/acfs/resource/attributes/date_time.rb +32 -0
  27. data/lib/acfs/{model → resource}/attributes/dict.rb +1 -3
  28. data/lib/acfs/{model → resource}/attributes/float.rb +3 -6
  29. data/lib/acfs/{model → resource}/attributes/integer.rb +3 -6
  30. data/lib/acfs/{model → resource}/attributes/list.rb +2 -5
  31. data/lib/acfs/{model → resource}/attributes/string.rb +4 -6
  32. data/lib/acfs/{model → resource}/attributes/uuid.rb +18 -8
  33. data/lib/acfs/resource/dirty.rb +47 -0
  34. data/lib/acfs/{model → resource}/initialization.rb +8 -10
  35. data/lib/acfs/{model → resource}/loadable.rb +3 -4
  36. data/lib/acfs/{model → resource}/locatable.rb +22 -23
  37. data/lib/acfs/{model → resource}/operational.rb +2 -3
  38. data/lib/acfs/resource/persistence.rb +257 -0
  39. data/lib/acfs/{model → resource}/query_methods.rb +81 -66
  40. data/lib/acfs/{model → resource}/service.rb +10 -9
  41. data/lib/acfs/resource/validation.rb +28 -0
  42. data/lib/acfs/response.rb +1 -2
  43. data/lib/acfs/response/formats.rb +1 -2
  44. data/lib/acfs/response/status.rb +3 -5
  45. data/lib/acfs/runner.rb +4 -5
  46. data/lib/acfs/service.rb +4 -6
  47. data/lib/acfs/service/middleware.rb +1 -3
  48. data/lib/acfs/singleton_resource.rb +11 -24
  49. data/lib/acfs/stub.rb +30 -22
  50. data/lib/acfs/util.rb +1 -1
  51. data/lib/acfs/version.rb +4 -2
  52. data/spec/acfs/adapter/typhoeus_spec.rb +4 -4
  53. data/spec/acfs/collection_spec.rb +33 -33
  54. data/spec/acfs/configuration_spec.rb +0 -1
  55. data/spec/acfs/global_spec.rb +3 -3
  56. data/spec/acfs/middleware/json_spec.rb +2 -2
  57. data/spec/acfs/middleware/msgpack_spec.rb +4 -4
  58. data/spec/acfs/request/callbacks_spec.rb +8 -8
  59. data/spec/acfs/request_spec.rb +5 -5
  60. data/spec/acfs/{model → resource}/attributes/boolean_spec.rb +2 -2
  61. data/spec/acfs/{model → resource}/attributes/date_time_spec.rb +7 -7
  62. data/spec/acfs/{model → resource}/attributes/dict_spec.rb +6 -6
  63. data/spec/acfs/{model → resource}/attributes/float_spec.rb +3 -3
  64. data/spec/acfs/{model → resource}/attributes/list_spec.rb +5 -5
  65. data/spec/acfs/{model → resource}/attributes/uuid_spec.rb +6 -6
  66. data/spec/acfs/{model → resource}/attributes_spec.rb +31 -17
  67. data/spec/acfs/{model → resource}/dirty_spec.rb +7 -5
  68. data/spec/acfs/{model → resource}/initialization_spec.rb +7 -7
  69. data/spec/acfs/{model → resource}/loadable_spec.rb +4 -3
  70. data/spec/acfs/{model → resource}/locatable_spec.rb +24 -14
  71. data/spec/acfs/{model → resource}/persistance_spec.rb +34 -34
  72. data/spec/acfs/{model → resource}/query_methods_spec.rb +171 -130
  73. data/spec/acfs/{model → resource}/validation_spec.rb +5 -6
  74. data/spec/acfs/response/formats_spec.rb +1 -1
  75. data/spec/acfs/response/status_spec.rb +1 -1
  76. data/spec/acfs/runner_spec.rb +2 -3
  77. data/spec/acfs/service/middleware_spec.rb +1 -1
  78. data/spec/acfs/service_spec.rb +3 -5
  79. data/spec/acfs/singleton_resource_spec.rb +3 -3
  80. data/spec/acfs/stub_spec.rb +52 -24
  81. data/spec/acfs_spec.rb +22 -19
  82. data/spec/spec_helper.rb +1 -1
  83. data/spec/support/hash.rb +9 -0
  84. data/spec/support/service.rb +4 -7
  85. data/spec/support/shared/find_callbacks.rb +7 -7
  86. metadata +52 -52
  87. data/lib/acfs/model.rb +0 -43
  88. data/lib/acfs/model/attributes/boolean.rb +0 -38
  89. data/lib/acfs/model/attributes/date_time.rb +0 -30
  90. data/lib/acfs/model/dirty.rb +0 -49
  91. data/lib/acfs/model/persistence.rb +0 -243
  92. data/lib/acfs/model/relations.rb +0 -10
  93. data/lib/acfs/model/validation.rb +0 -30
@@ -0,0 +1,33 @@
1
+ module Acfs::Resource::Attributes
2
+ # @api public
3
+ #
4
+ # Boolean attribute type. Use it in your model as an attribute type:
5
+ #
6
+ # @example
7
+ # class User < Acfs::Resource
8
+ # attribute :name, :boolean
9
+ # end
10
+ #
11
+ # Given objects will be converted to string. The following strings
12
+ # are considered true, everything else false:
13
+ #
14
+ # true, on, yes
15
+ #
16
+ class Boolean < Base
17
+ TRUE_VALUES = %w(true on yes 1)
18
+
19
+ # @api public
20
+ #
21
+ # Cast given object to boolean.
22
+ #
23
+ # @param [Object] obj Object to cast.
24
+ # @return [TrueClass, FalseClass] Casted boolean.
25
+ #
26
+ def cast_type(obj)
27
+ return true if obj.is_a? TrueClass
28
+ return false if obj.is_a? FalseClass
29
+
30
+ TRUE_VALUES.include? obj.to_s
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ module Acfs::Resource::Attributes
2
+ # @api public
3
+ #
4
+ # DateTime attribute type. Use it in your model as
5
+ # an attribute type:
6
+ #
7
+ # @example
8
+ # class User < Acfs::Resource
9
+ # attribute :name, :date_time
10
+ # end
11
+ #
12
+ class DateTime < Base
13
+ # @api public
14
+ #
15
+ # Cast given object to DateTime.
16
+ #
17
+ # @param [Object] obj Object to cast.
18
+ # @return [DateTime] Casted object as DateTime.
19
+ #
20
+ def cast_type(obj)
21
+ if nil_allowed? && obj.blank?
22
+ nil
23
+ elsif obj.is_a? ::DateTime
24
+ obj
25
+ elsif obj.is_a?(Time) || obj.is_a?(Date)
26
+ ::DateTime.iso8601 obj.iso8601
27
+ else
28
+ ::DateTime.iso8601 obj
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,4 @@
1
- module Acfs::Model::Attributes
2
-
1
+ module Acfs::Resource::Attributes
3
2
  # @api public
4
3
  #
5
4
  # Dict attribute type. Use it in your model as an attribute type:
@@ -11,7 +10,6 @@ module Acfs::Model::Attributes
11
10
  # end
12
11
  #
13
12
  class Dict < Base
14
-
15
13
  # @api public
16
14
  #
17
15
  # Cast given object to a dict/hash.
@@ -1,17 +1,14 @@
1
- module Acfs::Model::Attributes
2
-
1
+ module Acfs::Resource::Attributes
3
2
  # @api public
4
3
  #
5
4
  # Float attribute type. Use it in your model as an attribute type:
6
5
  #
7
6
  # @example
8
- # class User
9
- # include Acfs::Model
7
+ # class User < Acfs::Resource
10
8
  # attribute :name, :float
11
9
  # end
12
10
  #
13
11
  class Float < Base
14
-
15
12
  # @api public
16
13
  #
17
14
  # Cast given object to float.
@@ -20,7 +17,7 @@ module Acfs::Model::Attributes
20
17
  # @return [Float] Casted object as float.
21
18
  #
22
19
  def cast_type(obj)
23
- obj.to_f
20
+ Float obj
24
21
  end
25
22
  end
26
23
  end
@@ -1,17 +1,14 @@
1
- module Acfs::Model::Attributes
2
-
1
+ module Acfs::Resource::Attributes
3
2
  # @api public
4
3
  #
5
4
  # Integer attribute type. Use it in your model as an attribute type:
6
5
  #
7
6
  # @example
8
- # class User
9
- # include Acfs::Model
7
+ # class User < Acfs::Resource
10
8
  # attribute :name, :integer
11
9
  # end
12
10
  #
13
11
  class Integer < Base
14
-
15
12
  # @api public
16
13
  #
17
14
  # Cast given object to integer.
@@ -20,7 +17,7 @@ module Acfs::Model::Attributes
20
17
  # @return [Fixnum] Casted object as fixnum.
21
18
  #
22
19
  def cast_type(obj)
23
- obj.to_i
20
+ Integer obj
24
21
  end
25
22
  end
26
23
  end
@@ -1,17 +1,14 @@
1
- module Acfs::Model::Attributes
2
-
1
+ module Acfs::Resource::Attributes
3
2
  # @api public
4
3
  #
5
4
  # List attribute type. Use it in your model as an attribute type:
6
5
  #
7
6
  # @example
8
- # class User
9
- # include Acfs::Model
7
+ # class User < Acfs::Resource
10
8
  # attribute :name, :list
11
9
  # end
12
10
  #
13
11
  class List < Base
14
-
15
12
  # @api public
16
13
  #
17
14
  # Cast given object to a list.
@@ -1,17 +1,15 @@
1
- module Acfs::Model::Attributes
2
-
1
+ module Acfs::Resource::Attributes
3
2
  # @api public
4
3
  #
5
- # String attribute type. Use it in your model as an attribute type:
4
+ # String attribute type. Use it in your model as
5
+ # an attribute type:
6
6
  #
7
7
  # @example
8
- # class User
9
- # include Acfs::Model
8
+ # class User < Acfs::Resource
10
9
  # attribute :name, :string
11
10
  # end
12
11
  #
13
12
  class String < Base
14
-
15
13
  # @api public
16
14
  #
17
15
  # Cast given object to string.
@@ -1,16 +1,16 @@
1
- module Acfs::Model::Attributes
2
-
1
+ module Acfs::Resource::Attributes
3
2
  # @api public
4
3
  #
5
4
  # UUID attribute type. Use it in your model as an attribute type:
6
5
  #
7
6
  # @example
8
- # class User
9
- # include Acfs::Model
7
+ # class User < Acfs::Resource
10
8
  # attribute :id, :uuid
11
9
  # end
12
10
  #
13
11
  class UUID < Base
12
+ #
13
+ REGEXP = /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/i
14
14
 
15
15
  # @api public
16
16
  #
@@ -32,10 +32,20 @@ module Acfs::Model::Attributes
32
32
  # @return [String] Casted object as UUID.
33
33
  #
34
34
  def cast_type(obj)
35
- obj = obj.to_s
36
- return nil if nil_allowed? and obj == ''
37
- raise ArgumentError.new "given String `#{obj}` does not look like a UUID" unless obj =~ /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/i
38
- obj
35
+ cast_string obj.to_s
36
+ end
37
+
38
+ private
39
+
40
+ def cast_string(str)
41
+ if nil_allowed? && str.blank?
42
+ return nil
43
+ elsif str =~ REGEXP
44
+ str
45
+ else
46
+ raise ArgumentError.new "given String `#{str}` " \
47
+ 'does not look like a UUID'
48
+ end
39
49
  end
40
50
  end
41
51
 
@@ -0,0 +1,47 @@
1
+ class Acfs::Resource
2
+ #
3
+ # Thin wrapper around ActiveModel::Dirty
4
+ #
5
+ module Dirty
6
+ extend ActiveSupport::Concern
7
+ include ActiveModel::Dirty
8
+
9
+ # @api private
10
+ #
11
+ # Resets all changes. Does not touch previous changes.
12
+ #
13
+ def reset_changes
14
+ changed_attributes.clear
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
25
+ end
26
+
27
+ # @api private
28
+ #
29
+ def save!(*)
30
+ super.tap {|_| swap_changes }
31
+ end
32
+
33
+ # @api private
34
+ #
35
+ def loaded!
36
+ reset_changes
37
+ super
38
+ end
39
+
40
+ # @api private
41
+ #
42
+ def write_raw_attribute(name, value, opts = {})
43
+ attribute_will_change! name if opts[:change].nil? || opts[:change]
44
+ super
45
+ end
46
+ end
47
+ end
@@ -1,18 +1,17 @@
1
- module Acfs::Model
2
-
1
+ class Acfs::Resource
2
+ #
3
3
  # Initialization drop-in for pre-4.0 ActiveModel.
4
4
  #
5
5
  module Initialization
6
-
6
+ #
7
7
  # @api public
8
8
  #
9
- # Initializes a new model with the given `params`.
9
+ # Initializes a new model with the given `params`. fff
10
10
  #
11
11
  # @example
12
- # class User
13
- # include Acfs::Model
12
+ # class User < Acfs::Resource
14
13
  # attribute :name
15
- # attribute :email, default: -> { "#{name}@dom.tld" }
14
+ # attribute :email, default: ->{ "#{name}@dom.tld" }
16
15
  # attribute :age, :integer, default: 18
17
16
  # end
18
17
  #
@@ -21,11 +20,10 @@ module Acfs::Model
21
20
  # user.email # => "bob@dom.tld"
22
21
  # user.age # => 18
23
22
  #
24
- # @param [ Hash{ Symbol => Object } ] params Attributes to set on resource.
23
+ # @param params [Hash{Symbol => Object}] Attributes to set on resource.
25
24
  #
26
25
  def initialize(params = {})
27
- self.write_attributes params if params
26
+ write_attributes params if params
28
27
  end
29
-
30
28
  end
31
29
  end
@@ -1,5 +1,4 @@
1
- module Acfs::Model
2
-
1
+ class Acfs::Resource
3
2
  # Provides method to check for loading state of resources.
4
3
  # A resource that is created but not yet fetched will be loaded
5
4
  # after running {Acfs::Global#run Acfs.run}.
@@ -17,10 +16,10 @@ module Acfs::Model
17
16
  #
18
17
  # Check if model is loaded or if request is still queued.
19
18
  #
20
- # @return [ Boolean ] True if resource is loaded, false otherwise.
19
+ # @return [Boolean] True if resource is loaded, false otherwise.
21
20
  #
22
21
  def loaded?
23
- !!@loaded
22
+ @loaded.nil? ? false : @loaded
24
23
  end
25
24
 
26
25
  # @api private
@@ -1,5 +1,4 @@
1
- module Acfs::Model
2
-
1
+ class Acfs::Resource
3
2
  # Provide methods for generation URLs for resources.
4
3
  #
5
4
  # @example
@@ -12,36 +11,36 @@ module Acfs::Model
12
11
  module Locatable
13
12
  extend ActiveSupport::Concern
14
13
 
14
+ #
15
15
  module ClassMethods
16
-
17
16
  # @overload url(suffix)
18
17
  # @deprecated
19
- # Return URL for this class of resource. Given suffix will be appended.
18
+ # Return URL for this class of resource. Given suffix
19
+ # will be appended.
20
20
  #
21
21
  # @example
22
22
  # User.url # => "http://users.srv.org/users"
23
23
  # User.url(5) # => "http://users.srv.org/users/5"
24
24
  #
25
- # @param [ String ] suffix Suffix to append to URL.
26
- # @return [ String ] Generated URL.
25
+ # @param suffix [String] Suffix to append to URL.
26
+ # @return [String] Generated URL.
27
27
  #
28
28
  # @overload url(opts = {})
29
- # Return URL for this class of resources. Given options will be used to replace
30
- # URL path arguments and to determine the operation action.
29
+ # Return URL for this class of resources. Given options
30
+ # will be used to replace URL path arguments and to
31
+ # determine the operation action.
31
32
  #
32
33
  # @example
33
34
  # User.url(id: 5, action: :read) # => "http://users.srv.org/users/5"
34
35
  # User.url(action: :list) # => "http://users.srv.org/users"
35
36
  #
36
37
  # @param opts [Hash] Options.
37
- # @option opts [Symbol] :action Operation action, usually `:list`, `:create`, `:read`,
38
- # `:update` or`:delete`.
39
- # @return [ String ] Generated URL.
38
+ # @option opts [Symbol] :action Operation action,
39
+ # usually `:list`, `:create`, `:read`, `:update` or`:delete`.
40
+ # @return [String] Generated URL.
40
41
  #
41
42
  def url(suffix = nil, opts = {})
42
- if Hash === suffix
43
- opts, suffix = suffix, nil
44
- end
43
+ opts, suffix = suffix, nil if suffix.is_a? Hash
45
44
 
46
45
  opts[:action] = :list if suffix
47
46
 
@@ -50,8 +49,8 @@ module Acfs::Model
50
49
  url
51
50
  end
52
51
 
53
- # Return a location object able to build the URL for this resource and
54
- # given action.
52
+ # Return a location object able to build the URL for this
53
+ # resource and given action.
55
54
  #
56
55
  # @example
57
56
  # class Identity < ::Acfs::Resource
@@ -73,8 +72,8 @@ module Acfs::Model
73
72
  # => 'http://service/users/42/identities'
74
73
  #
75
74
  # @param opts [Hash] Options.
76
- # @option opts [Symbol] :action Operation action, usually `:list`, `:create`, `:read`,
77
- # `:update` or`:delete`.
75
+ # @option opts [Symbol] :action Operation action,
76
+ # usually `:list`, `:create`, `:read`, `:update` or`:delete`.
78
77
  #
79
78
  # @return [Location] Location object.
80
79
  #
@@ -89,8 +88,6 @@ module Acfs::Model
89
88
  return path
90
89
  when :read, :update, :delete
91
90
  return "#{path}/:id"
92
- else
93
- nil
94
91
  end
95
92
  end
96
93
  end
@@ -109,9 +106,11 @@ module Acfs::Model
109
106
  # @see ClassMethods#url
110
107
  #
111
108
  def url(opts = {})
112
- return nil if need_primary_key? && !has_primary_key?
109
+ return nil if need_primary_key? && !primary_key?
113
110
 
114
- self.class.service.location(self.class, opts.reverse_merge(action: :read)).build(attributes).str
111
+ self.class.service
112
+ .location(self.class, opts.reverse_merge(action: :read))
113
+ .build(attributes).str
115
114
  end
116
115
 
117
116
  # @api private
@@ -122,7 +121,7 @@ module Acfs::Model
122
121
 
123
122
  # @api private
124
123
  # Return true if resource has a primary key (id) set.
125
- def has_primary_key?
124
+ def primary_key?
126
125
  respond_to?(:id) && !id.nil?
127
126
  end
128
127
  end
@@ -1,5 +1,4 @@
1
- module Acfs::Model
2
-
1
+ class Acfs::Resource
3
2
  # @api private
4
3
  #
5
4
  # Provide methods for creating and processing CRUD operations and
@@ -12,8 +11,8 @@ module Acfs::Model
12
11
  extend ActiveSupport::Concern
13
12
  delegate :operation, to: :'self.class'
14
13
 
14
+ #
15
15
  module ClassMethods
16
-
17
16
  # Invoke CRUD operation.
18
17
  def operation(action, opts = {}, &block)
19
18
  Acfs.runner.process ::Acfs::Operation.new self, action, opts, &block