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
@@ -1,10 +1,8 @@
1
1
  module Acfs
2
2
  module Middleware
3
-
4
3
  # Print resquests and response on terminal
5
4
  #
6
5
  class Print < Base
7
-
8
6
  def call(req)
9
7
  puts '-' * 80
10
8
  puts req.inspect
@@ -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(data)
7
+ def encode(_data)
9
8
  raise NotImplementedError
10
9
  end
11
10
 
12
- def decode(data)
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
@@ -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
- { read: :get, list: :get, update: :put, create: :post, delete: :delete }[action]
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
- operation: self,
63
- response: response
61
+ operation: self,
62
+ response: response
64
63
 
65
64
  handle_failure response unless response.success?
66
65
  callback.call response.data, response
@@ -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 |url|
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 &block if block_given?
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 { |res| call_callback res, index + 1 } if index < callbacks.size
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
@@ -1,8 +1,37 @@
1
- module Acfs
1
+ require 'active_model'
2
2
 
3
- # Transition stub for `Model`.
4
- #
5
- class Resource
6
- include Acfs::Model
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
- module Acfs::Model
2
-
1
+ class Acfs::Resource
2
+ #
3
3
  # = Acfs Attributes
4
4
  #
5
- # Allows to specify attributes of a class with default values and type safety.
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
- self.write_attributes self.class.attributes
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 [ HashWithIndifferentAccess{ Symbol => Object } ] Attributes and their values.
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 [ Hash{ String, Symbol => Object }, #each{|key, value|} ] attributes to set in resource.
63
- # @see #write_attributes Delegates attributes hash to `#write_attributes`.
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 [ Symbol, String ] name Attribute name.
74
- # @return [ Object ] Attribute value.
74
+ # @param [Symbol, String] name Attribute name.
75
+ # @return [Object] Attribute value.
75
76
  #
76
77
  def read_attribute(name)
77
- self.attributes[name.to_s]
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 { :name => 'john', :email => lambda{ "#{name}@example.org" } }
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 [ Hash{ String, Symbol => Object, Proc }, #each{|key, value|} ] attributes to write.
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,:ignore) == :raise
107
+ if opts.fetch(:unknown, :ignore) == :raise
105
108
  if (attributes.keys.map(&:to_s) - self.class.attributes.keys).any?
106
- raise ArgumentError.new "Unknown attributes: #{(attributes.keys - self.class.attributes.keys).map(&:inspect).join(', ')}"
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 [ String, Symbol ] name Attribute name.
149
- # @param [ Object ] value Value to write.
150
- # @raise [ ArgumentError ] If no attribute with given name is defined.
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 [ String, Symbol ] name Attribute name.
168
- # @param [ Object ] value Attribute value.
172
+ # @param [String, Symbol] name Attribute name.
173
+ # @param [Object] value Attribute value.
169
174
  #
170
175
  def write_raw_attribute(name, value, _ = {})
171
- self.attributes[name.to_s] = value
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 [ #to_sym ] name Attribute name.
191
- # @param [ Symbol, String, Class ] type Attribute type identifier or type class.
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? Symbol or type.is_a? String
195
- type = "::Acfs::Model::Attributes::#{type.to_s.classify}".constantize
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 values for this model class.
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 [ Hash{ String => Object, Proc } ] Attributes with default values.
221
+ # @return [Hash{String => Object, Proc}]
222
+ # Attributes with default values.
214
223
  #
215
224
  def attributes
216
- Hash.new.tap do |attrs|
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 ||= {}.merge superclass.respond_to?(:defined_attributes) ? superclass.defined_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 # => { "name": Acfs::Model::Attributes::String, "age": Acfs::Model::Attributes::Integer }
252
+ # User.attributes # => {"name": Acfs::Model::Attributes::String,
253
+ # # "age": Acfs::Model::Attributes::Integer}
238
254
  #
239
- # @return [ Hash{ Symbol => Class } ] Attributes and their types.
255
+ # @return [Hash{Symbol => Class}] Attributes and their types.
240
256
  #
241
257
  def attribute_types
242
- @attribute_types ||= {}.merge superclass.respond_to?(:attribute_types) ? superclass.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 = name.to_s
248
- attribute = type.new opts
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
- self.send :define_method, name do
277
+ send :define_method, name do
254
278
  read_attribute name
255
279
  end
256
280
 
257
- self.send :define_method, :"#{name}=" do |value|
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/model/attributes/#{filename}"
293
+ require "acfs/resource/attributes/#{filename}"
270
294
  end
@@ -1,5 +1,5 @@
1
- module Acfs::Model::Attributes
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
- !!options[:allow_nil]
12
+ options[:allow_nil]
13
13
  end
14
14
 
15
15
  def blank_allowed?
16
- !!options[:allow_blank]
16
+ options[:allow_blank]
17
17
  end
18
18
 
19
19
  def default_value
20
- options[:default].is_a?(Proc) ? options[:default] : cast(options[:default])
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(obj)
32
+ def cast_type(_obj)
29
33
  raise NotImplementedError
30
34
  end
31
35
  end