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
@@ -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