acfs 0.42.0 → 0.43.0

Sign up to get free protection for your applications and to get access to all the features.
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