acfs 1.0.0.dev.1.b305 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +5 -13
  2. data/CHANGELOG.md +64 -0
  3. data/README.md +2 -2
  4. data/acfs.gemspec +4 -4
  5. data/lib/acfs.rb +7 -5
  6. data/lib/acfs/adapter/base.rb +0 -2
  7. data/lib/acfs/adapter/typhoeus.rb +17 -13
  8. data/lib/acfs/collections/paginatable.rb +10 -10
  9. data/lib/acfs/configuration.rb +4 -5
  10. data/lib/acfs/errors.rb +10 -9
  11. data/lib/acfs/global.rb +16 -7
  12. data/lib/acfs/location.rb +11 -11
  13. data/lib/acfs/middleware/base.rb +1 -2
  14. data/lib/acfs/middleware/json.rb +27 -0
  15. data/lib/acfs/middleware/logger.rb +0 -2
  16. data/lib/acfs/middleware/msgpack.rb +30 -0
  17. data/lib/acfs/middleware/print.rb +0 -2
  18. data/lib/acfs/middleware/serializer.rb +39 -0
  19. data/lib/acfs/operation.rb +5 -5
  20. data/lib/acfs/request.rb +4 -4
  21. data/lib/acfs/request/callbacks.rb +2 -3
  22. data/lib/acfs/resource.rb +2 -2
  23. data/lib/acfs/resource/attributes.rb +10 -37
  24. data/lib/acfs/resource/attributes/base.rb +10 -19
  25. data/lib/acfs/resource/attributes/boolean.rb +10 -8
  26. data/lib/acfs/resource/attributes/date_time.rb +6 -9
  27. data/lib/acfs/resource/attributes/dict.rb +37 -0
  28. data/lib/acfs/resource/attributes/float.rb +11 -5
  29. data/lib/acfs/resource/attributes/integer.rb +7 -5
  30. data/lib/acfs/resource/attributes/list.rb +13 -6
  31. data/lib/acfs/resource/attributes/string.rb +3 -5
  32. data/lib/acfs/resource/attributes/uuid.rb +8 -17
  33. data/lib/acfs/resource/loadable.rb +0 -1
  34. data/lib/acfs/resource/locatable.rb +0 -4
  35. data/lib/acfs/resource/operational.rb +0 -2
  36. data/lib/acfs/resource/persistence.rb +17 -17
  37. data/lib/acfs/resource/query_methods.rb +3 -5
  38. data/lib/acfs/resource/service.rb +0 -2
  39. data/lib/acfs/resource/validation.rb +0 -2
  40. data/lib/acfs/response.rb +1 -2
  41. data/lib/acfs/response/formats.rb +1 -2
  42. data/lib/acfs/response/status.rb +3 -5
  43. data/lib/acfs/runner.rb +21 -11
  44. data/lib/acfs/service.rb +4 -6
  45. data/lib/acfs/service/middleware.rb +20 -30
  46. data/lib/acfs/service/middleware/stack.rb +63 -0
  47. data/lib/acfs/singleton_resource.rb +0 -2
  48. data/lib/acfs/stub.rb +30 -21
  49. data/lib/acfs/util.rb +1 -1
  50. data/lib/acfs/version.rb +4 -2
  51. data/spec/acfs/adapter/typhoeus_spec.rb +12 -4
  52. data/spec/acfs/collection_spec.rb +45 -33
  53. data/spec/acfs/configuration_spec.rb +9 -1
  54. data/spec/acfs/global_spec.rb +21 -3
  55. data/spec/acfs/middleware/json_spec.rb +63 -0
  56. data/spec/acfs/middleware/msgpack_spec.rb +60 -0
  57. data/spec/acfs/operation_spec.rb +10 -0
  58. data/spec/acfs/request/callbacks_spec.rb +8 -8
  59. data/spec/acfs/request_spec.rb +5 -5
  60. data/spec/acfs/resource/attributes/boolean_spec.rb +40 -9
  61. data/spec/acfs/resource/attributes/date_time_spec.rb +29 -35
  62. data/spec/acfs/resource/attributes/dict_spec.rb +75 -0
  63. data/spec/acfs/resource/attributes/float_spec.rb +48 -9
  64. data/spec/acfs/resource/attributes/integer_spec.rb +34 -0
  65. data/spec/acfs/resource/attributes/list_spec.rb +43 -19
  66. data/spec/acfs/resource/attributes/uuid_spec.rb +31 -54
  67. data/spec/acfs/resource/attributes_spec.rb +17 -31
  68. data/spec/acfs/resource/locatable_spec.rb +2 -2
  69. data/spec/acfs/resource/persistance_spec.rb +65 -34
  70. data/spec/acfs/resource/query_methods_spec.rb +87 -87
  71. data/spec/acfs/resource/validation_spec.rb +4 -5
  72. data/spec/acfs/response/formats_spec.rb +1 -1
  73. data/spec/acfs/response/status_spec.rb +1 -1
  74. data/spec/acfs/runner_spec.rb +28 -3
  75. data/spec/acfs/service/middleware_spec.rb +4 -20
  76. data/spec/acfs/service_spec.rb +3 -5
  77. data/spec/acfs/singleton_resource_spec.rb +1 -2
  78. data/spec/acfs/stub_spec.rb +137 -22
  79. data/spec/acfs_spec.rb +22 -19
  80. data/spec/spec_helper.rb +2 -1
  81. data/spec/support/service.rb +10 -6
  82. data/spec/support/shared/find_callbacks.rb +7 -7
  83. metadata +37 -30
  84. data/lib/acfs/middleware/json_decoder.rb +0 -16
  85. data/lib/acfs/middleware/json_encoder.rb +0 -20
  86. data/lib/acfs/middleware/msgpack_decoder.rb +0 -26
  87. data/lib/acfs/middleware/msgpack_encoder.rb +0 -19
  88. data/spec/acfs/middleware/json_decoder_spec.rb +0 -45
  89. data/spec/acfs/middleware/msgpack_decoder_spec.rb +0 -36
@@ -1,5 +1,4 @@
1
1
  module Acfs::Resource::Attributes
2
-
3
2
  # @api public
4
3
  #
5
4
  # Float attribute type. Use it in your model as an attribute type:
@@ -10,16 +9,23 @@ module Acfs::Resource::Attributes
10
9
  # end
11
10
  #
12
11
  class Float < Base
13
-
14
12
  # @api public
15
13
  #
16
14
  # Cast given object to float.
17
15
  #
18
- # @param [Object] obj Object to cast.
16
+ # @param [Object] value Object to cast.
19
17
  # @return [Float] Casted object as float.
20
18
  #
21
- def cast_type(obj)
22
- Float obj
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
23
29
  end
24
30
  end
25
31
  end
@@ -1,5 +1,4 @@
1
1
  module Acfs::Resource::Attributes
2
-
3
2
  # @api public
4
3
  #
5
4
  # Integer attribute type. Use it in your model as an attribute type:
@@ -10,16 +9,19 @@ module Acfs::Resource::Attributes
10
9
  # end
11
10
  #
12
11
  class Integer < Base
13
-
14
12
  # @api public
15
13
  #
16
14
  # Cast given object to integer.
17
15
  #
18
- # @param [Object] obj Object to cast.
16
+ # @param [Object] value Object to cast.
19
17
  # @return [Fixnum] Casted object as fixnum.
20
18
  #
21
- def cast_type(obj)
22
- Integer obj
19
+ def cast_value(value)
20
+ if value.blank?
21
+ 0
22
+ else
23
+ Integer(value)
24
+ end
23
25
  end
24
26
  end
25
27
  end
@@ -1,5 +1,4 @@
1
1
  module Acfs::Resource::Attributes
2
-
3
2
  # @api public
4
3
  #
5
4
  # List attribute type. Use it in your model as an attribute type:
@@ -10,18 +9,26 @@ module Acfs::Resource::Attributes
10
9
  # end
11
10
  #
12
11
  class List < Base
13
-
14
12
  # @api public
15
13
  #
16
14
  # Cast given object to a list.
17
15
  #
18
- # @param [Object] obj Object to cast.
16
+ # @param [Object] value Object to cast.
19
17
  # @return [Fixnum] Casted object as list.
20
18
  # @raise [TypeError] If object cannot be casted to a list.
21
19
  #
22
- def cast_type(obj)
23
- return obj.to_a if obj.respond_to? :to_a
24
- raise TypeError.new "Cannot cast #{obj.inspect} to array."
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
25
32
  end
26
33
  end
27
34
  end
@@ -1,5 +1,4 @@
1
1
  module Acfs::Resource::Attributes
2
-
3
2
  # @api public
4
3
  #
5
4
  # String attribute type. Use it in your model as
@@ -11,16 +10,15 @@ module Acfs::Resource::Attributes
11
10
  # end
12
11
  #
13
12
  class String < Base
14
-
15
13
  # @api public
16
14
  #
17
15
  # Cast given object to string.
18
16
  #
19
- # @param [Object] obj Object to cast.
17
+ # @param [Object] value Object to cast.
20
18
  # @return [String] Casted string.
21
19
  #
22
- def cast_type(obj)
23
- obj.to_s
20
+ def cast_value(value)
21
+ value.to_s
24
22
  end
25
23
  end
26
24
  end
@@ -1,5 +1,4 @@
1
1
  module Acfs::Resource::Attributes
2
-
3
2
  # @api public
4
3
  #
5
4
  # UUID attribute type. Use it in your model as an attribute type:
@@ -10,9 +9,8 @@ module Acfs::Resource::Attributes
10
9
  # end
11
10
  #
12
11
  class UUID < Base
13
-
14
12
  #
15
- REGEXP = /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/i
13
+ UUID_REGEXP = /[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/i
16
14
 
17
15
  # @api public
18
16
  #
@@ -30,23 +28,16 @@ module Acfs::Resource::Attributes
30
28
  # | 4 | 4 |
31
29
  # | 5 | 12 |
32
30
  #
33
- # @param [Object] obj Object to cast.
31
+ # @param [Object] value Object to cast.
34
32
  # @return [String] Casted object as UUID.
35
33
  #
36
- def cast_type(obj)
37
- cast_string obj.to_s
38
- end
39
-
40
- private
41
-
42
- def cast_string(str)
43
- if nil_allowed? && str.blank?
44
- return nil
45
- elsif str =~ REGEXP
46
- str
34
+ def cast_value(value)
35
+ if value.blank?
36
+ nil
37
+ elsif value.to_s =~ UUID_REGEXP
38
+ value
47
39
  else
48
- raise ArgumentError.new "given String `#{str}` " \
49
- "does not look like a UUID"
40
+ raise TypeError.new "Invalid UUID: `#{value.to_s}'"
50
41
  end
51
42
  end
52
43
  end
@@ -1,5 +1,4 @@
1
1
  class Acfs::Resource
2
-
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}.
@@ -1,5 +1,4 @@
1
1
  class Acfs::Resource
2
-
3
2
  # Provide methods for generation URLs for resources.
4
3
  #
5
4
  # @example
@@ -14,7 +13,6 @@ class Acfs::Resource
14
13
 
15
14
  #
16
15
  module ClassMethods
17
-
18
16
  # @overload url(suffix)
19
17
  # @deprecated
20
18
  # Return URL for this class of resource. Given suffix
@@ -90,8 +88,6 @@ class Acfs::Resource
90
88
  return path
91
89
  when :read, :update, :delete
92
90
  return "#{path}/:id"
93
- else
94
- nil
95
91
  end
96
92
  end
97
93
  end
@@ -1,5 +1,4 @@
1
1
  class Acfs::Resource
2
-
3
2
  # @api private
4
3
  #
5
4
  # Provide methods for creating and processing CRUD operations and
@@ -14,7 +13,6 @@ class Acfs::Resource
14
13
 
15
14
  #
16
15
  module ClassMethods
17
-
18
16
  # Invoke CRUD operation.
19
17
  def operation(action, opts = {}, &block)
20
18
  Acfs.runner.process ::Acfs::Operation.new self, action, opts, &block
@@ -8,8 +8,7 @@ class Acfs::Resource
8
8
  # @api public
9
9
  #
10
10
  # Check if the model is persisted. A model is persisted if
11
- # it is saved after being created or when it was not changed
12
- # since it was loaded.
11
+ # it is saved after being created
13
12
  #
14
13
  # @example Newly created resource:
15
14
  # user = User.new name: "John"
@@ -21,15 +20,14 @@ class Acfs::Resource
21
20
  # user2 = User.find 5
22
21
  # user2.persisted? # => true
23
22
  # user2.name = 'Amy'
24
- # user2.persisted? # => false
23
+ # user2.persisted? # => true
25
24
  # user2.save
26
25
  # user2.persisted? # => true
27
26
  #
28
- # @return [Boolean] True if resource has no changes and
29
- # is not newly created, false otherwise.
27
+ # @return [Boolean] True if resource has been saved
30
28
  #
31
29
  def persisted?
32
- !new? && !changed?
30
+ !new?
33
31
  end
34
32
 
35
33
  # @api public
@@ -174,7 +172,7 @@ class Acfs::Resource
174
172
  #
175
173
  def delete!(opts = {})
176
174
  opts[:params] ||= {}
177
- opts[:params].merge! id: id
175
+ opts[:params] = attributes_for_url(:delete).merge opts[:params]
178
176
 
179
177
  operation :delete, opts do |data|
180
178
  update_with data
@@ -182,9 +180,14 @@ class Acfs::Resource
182
180
  end
183
181
  end
184
182
 
185
- #
186
- module ClassMethods
183
+ private
187
184
 
185
+ def attributes_for_url(action)
186
+ arguments_for_url = self.class.location(action: action).arguments
187
+ attributes.slice(*arguments_for_url)
188
+ end
189
+
190
+ module ClassMethods
188
191
  # @api public
189
192
  #
190
193
  # Create a new resource sending given data. If resource cannot be
@@ -208,10 +211,8 @@ class Acfs::Resource
208
211
  # will be overridden with provided data hash.
209
212
  # @see #create
210
213
  #
211
- def create!(data, opts = {})
212
- new(data).tap do |model|
213
- model.save!
214
- end
214
+ def create!(data, _opts = {})
215
+ new(data).tap(&:save!)
215
216
  end
216
217
 
217
218
  # @api public
@@ -234,7 +235,7 @@ class Acfs::Resource
234
235
  # will be overridden with provided data hash.
235
236
  # @see #create!
236
237
  #
237
- def create(data, opts = {})
238
+ def create(data, _opts = {})
238
239
  model = new data
239
240
  model.save
240
241
  model
@@ -249,9 +250,8 @@ class Acfs::Resource
249
250
  end
250
251
 
251
252
  def check_loaded!(opts = {})
252
- unless loaded? || opts[:force]
253
- raise ::Acfs::ResourceNotLoaded.new resource: self
254
- end
253
+ return if loaded? || opts[:force]
254
+ raise ::Acfs::ResourceNotLoaded.new resource: self
255
255
  end
256
256
  end
257
257
  end
@@ -1,5 +1,4 @@
1
1
  class Acfs::Resource
2
-
3
2
  # Methods providing the query interface for finding resouces.
4
3
  #
5
4
  # @example
@@ -17,7 +16,6 @@ class Acfs::Resource
17
16
 
18
17
  #
19
18
  module ClassMethods
20
-
21
19
  # @api public
22
20
  #
23
21
  # @overload find(id, opts = {})
@@ -139,7 +137,7 @@ class Acfs::Resource
139
137
  def find_by!(params, &block)
140
138
  find_by params do |m|
141
139
  if m.nil?
142
- raise Acfs::ResourceNotFound.new message: "Recieved erronious " \
140
+ raise Acfs::ResourceNotFound.new message: 'Received erroneous ' \
143
141
  "response: no `#{name}` with params #{params} found"
144
142
  end
145
143
  block.call m unless block.nil?
@@ -225,9 +223,9 @@ class Acfs::Resource
225
223
  collection.__callbacks__ << block unless block.nil?
226
224
 
227
225
  counter = 0
228
- ids.each do |id|
226
+ ids.each_with_index do |id, index|
229
227
  find_single id, opts do |resource|
230
- collection << resource
228
+ collection[index] = resource
231
229
  if (counter += 1) == ids.size
232
230
  collection.loaded!
233
231
  collection.__invoke__
@@ -1,5 +1,4 @@
1
1
  class Acfs::Resource
2
-
3
2
  # Included by Acfs::Model. Allows to configure the service
4
3
  # a resource belongs to.
5
4
  #
@@ -8,7 +7,6 @@ class Acfs::Resource
8
7
 
9
8
  #
10
9
  module ClassMethods
11
-
12
10
  # @api public
13
11
  #
14
12
  # @overload service()
@@ -1,8 +1,6 @@
1
1
  class Acfs::Resource
2
-
3
2
  #
4
3
  module Validation
5
-
6
4
  def valid?(*args)
7
5
  super
8
6
  remote_errors.each {|f, e| errors.add f, e }
@@ -3,7 +3,6 @@ require 'acfs/response/status'
3
3
  require 'active_support/core_ext/module/delegation'
4
4
 
5
5
  module Acfs
6
-
7
6
  # This represents a response. In addition to an standard HTTP
8
7
  # it has a field `data` for storing the encoded body.
9
8
  #
@@ -14,7 +13,7 @@ module Acfs
14
13
  include Response::Formats
15
14
  include Response::Status
16
15
 
17
- #delegate :status, :status_message, :success?, :modified?, :timed_out?,
16
+ # delegate :status, :status_message, :success?, :modified?, :timed_out?,
18
17
  # :response_body, :response_headers, :response_code, :headers,
19
18
  # to: :response
20
19
 
@@ -2,10 +2,8 @@ require 'action_dispatch'
2
2
 
3
3
  module Acfs
4
4
  class Response
5
-
6
5
  # Quick accessors for format handling.
7
6
  module Formats
8
-
9
7
  def content_type
10
8
  @content_type ||= read_content_type
11
9
  end
@@ -15,6 +13,7 @@ module Acfs
15
13
  end
16
14
 
17
15
  private
16
+
18
17
  def read_content_type
19
18
  return 'text/plain' unless headers && headers['Content-Type']
20
19
 
@@ -1,19 +1,17 @@
1
1
  module Acfs
2
2
  class Response
3
-
4
3
  # Method to fetch information about response status.
5
4
  #
6
5
  module Status
7
-
8
6
  # Return response status code. Will return zero if
9
7
  # request was not executed or failed on client side.
10
8
  #
11
9
  def status_code
12
10
  return @status.to_i if defined? :@status
13
- #return response.response_code unless response.nil?
14
- #0
11
+ # return response.response_code unless response.nil?
12
+ # 0
15
13
  end
16
- alias :code :status_code
14
+ alias_method :code, :status_code
17
15
 
18
16
  # Return true if response was successful indicated by
19
17
  # response status code.
@@ -1,7 +1,6 @@
1
1
  require 'acfs/service/middleware'
2
2
 
3
3
  module Acfs
4
-
5
4
  # @api private
6
5
  #
7
6
  class Runner
@@ -17,6 +16,7 @@ module Acfs
17
16
  # and parallel operations will be queued.
18
17
  #
19
18
  def process(op)
19
+ ::ActiveSupport::Notifications.instrument 'acfs.operation.before_process', operation: op
20
20
  op.synchronous? ? run(op) : enqueue(op)
21
21
  end
22
22
 
@@ -24,7 +24,7 @@ module Acfs
24
24
  #
25
25
  def run(op)
26
26
  ::ActiveSupport::Notifications.instrument 'acfs.runner.sync_run', operation: op do
27
- op_request(op) { |req| adapter.run req }
27
+ op_request(op) {|req| adapter.run req }
28
28
  end
29
29
  end
30
30
 
@@ -39,7 +39,7 @@ module Acfs
39
39
  def enqueue(op)
40
40
  ::ActiveSupport::Notifications.instrument 'acfs.runner.enqueue', operation: op do
41
41
  if running?
42
- op_request(op) { |req| adapter.queue req }
42
+ op_request(op) {|req| adapter.queue req }
43
43
  else
44
44
  queue << op
45
45
  end
@@ -55,15 +55,13 @@ module Acfs
55
55
  # Start processing queued operations.
56
56
  #
57
57
  def start
58
- enqueue_operations
58
+ return if running?
59
59
 
60
- @running = true
61
- adapter.start
60
+ enqueue_operations
61
+ start_all
62
62
  rescue
63
63
  queue.clear
64
64
  raise
65
- ensure
66
- @running = false
67
65
  end
68
66
 
69
67
  def clear
@@ -73,15 +71,27 @@ module Acfs
73
71
  end
74
72
 
75
73
  private
74
+
75
+ def start_all
76
+ @running = true
77
+ adapter.start
78
+ ensure
79
+ @running = false
80
+ end
81
+
76
82
  def enqueue_operations
77
83
  while (op = queue.shift)
78
- op_request(op) { |req| adapter.queue req }
84
+ op_request(op) {|req| adapter.queue req }
79
85
  end
80
86
  end
81
87
 
82
88
  def op_request(op)
83
- return if Acfs::Stub.enabled? and Acfs::Stub.stubbed(op)
84
- yield prepare op.service.prepare op.request
89
+ return if Acfs::Stub.enabled? && Acfs::Stub.stubbed(op)
90
+ req = op.service.prepare op.request
91
+ return unless req.is_a? Acfs::Request
92
+ req = prepare req
93
+ return unless req.is_a? Acfs::Request
94
+ yield req
85
95
  end
86
96
  end
87
97
  end