acfs 1.3.3 → 1.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +339 -0
- data/LICENSE +22 -0
- data/README.md +335 -0
- data/acfs.gemspec +46 -0
- data/lib/acfs.rb +51 -0
- data/lib/acfs/adapter/base.rb +24 -0
- data/lib/acfs/adapter/typhoeus.rb +69 -0
- data/lib/acfs/collection.rb +28 -0
- data/lib/acfs/collections/paginatable.rb +76 -0
- data/lib/acfs/configuration.rb +120 -0
- data/lib/acfs/errors.rb +127 -0
- data/lib/acfs/global.rb +101 -0
- data/lib/acfs/location.rb +82 -0
- data/lib/acfs/middleware/base.rb +24 -0
- data/lib/acfs/middleware/json.rb +29 -0
- data/lib/acfs/middleware/logger.rb +25 -0
- data/lib/acfs/middleware/msgpack.rb +32 -0
- data/lib/acfs/middleware/print.rb +23 -0
- data/lib/acfs/middleware/serializer.rb +41 -0
- data/lib/acfs/operation.rb +83 -0
- data/lib/acfs/request.rb +39 -0
- data/lib/acfs/request/callbacks.rb +54 -0
- data/lib/acfs/resource.rb +39 -0
- data/lib/acfs/resource/attributes.rb +269 -0
- data/lib/acfs/resource/attributes/base.rb +29 -0
- data/lib/acfs/resource/attributes/boolean.rb +39 -0
- data/lib/acfs/resource/attributes/date_time.rb +32 -0
- data/lib/acfs/resource/attributes/dict.rb +39 -0
- data/lib/acfs/resource/attributes/float.rb +33 -0
- data/lib/acfs/resource/attributes/integer.rb +29 -0
- data/lib/acfs/resource/attributes/list.rb +36 -0
- data/lib/acfs/resource/attributes/string.rb +26 -0
- data/lib/acfs/resource/attributes/uuid.rb +48 -0
- data/lib/acfs/resource/dirty.rb +37 -0
- data/lib/acfs/resource/initialization.rb +31 -0
- data/lib/acfs/resource/loadable.rb +35 -0
- data/lib/acfs/resource/locatable.rb +132 -0
- data/lib/acfs/resource/operational.rb +23 -0
- data/lib/acfs/resource/persistence.rb +260 -0
- data/lib/acfs/resource/query_methods.rb +266 -0
- data/lib/acfs/resource/service.rb +44 -0
- data/lib/acfs/resource/validation.rb +39 -0
- data/lib/acfs/response.rb +30 -0
- data/lib/acfs/response/formats.rb +27 -0
- data/lib/acfs/response/status.rb +33 -0
- data/lib/acfs/rspec.rb +13 -0
- data/lib/acfs/runner.rb +102 -0
- data/lib/acfs/service.rb +97 -0
- data/lib/acfs/service/middleware.rb +58 -0
- data/lib/acfs/service/middleware/stack.rb +65 -0
- data/lib/acfs/singleton_resource.rb +85 -0
- data/lib/acfs/stub.rb +194 -0
- data/lib/acfs/util.rb +22 -0
- data/lib/acfs/version.rb +16 -0
- data/lib/acfs/yard.rb +6 -0
- data/spec/acfs/adapter/typhoeus_spec.rb +55 -0
- data/spec/acfs/collection_spec.rb +157 -0
- data/spec/acfs/configuration_spec.rb +53 -0
- data/spec/acfs/global_spec.rb +140 -0
- data/spec/acfs/location_spec.rb +25 -0
- data/spec/acfs/middleware/json_spec.rb +65 -0
- data/spec/acfs/middleware/msgpack_spec.rb +62 -0
- data/spec/acfs/operation_spec.rb +12 -0
- data/spec/acfs/request/callbacks_spec.rb +48 -0
- data/spec/acfs/request_spec.rb +79 -0
- data/spec/acfs/resource/attributes/boolean_spec.rb +58 -0
- data/spec/acfs/resource/attributes/date_time_spec.rb +51 -0
- data/spec/acfs/resource/attributes/dict_spec.rb +77 -0
- data/spec/acfs/resource/attributes/float_spec.rb +61 -0
- data/spec/acfs/resource/attributes/integer_spec.rb +36 -0
- data/spec/acfs/resource/attributes/list_spec.rb +60 -0
- data/spec/acfs/resource/attributes/uuid_spec.rb +42 -0
- data/spec/acfs/resource/attributes_spec.rb +181 -0
- data/spec/acfs/resource/dirty_spec.rb +49 -0
- data/spec/acfs/resource/initialization_spec.rb +36 -0
- data/spec/acfs/resource/loadable_spec.rb +22 -0
- data/spec/acfs/resource/locatable_spec.rb +118 -0
- data/spec/acfs/resource/persistance_spec.rb +322 -0
- data/spec/acfs/resource/query_methods_spec.rb +548 -0
- data/spec/acfs/resource/validation_spec.rb +129 -0
- data/spec/acfs/response/formats_spec.rb +52 -0
- data/spec/acfs/response/status_spec.rb +71 -0
- data/spec/acfs/runner_spec.rb +95 -0
- data/spec/acfs/service/middleware_spec.rb +35 -0
- data/spec/acfs/service_spec.rb +48 -0
- data/spec/acfs/singleton_resource_spec.rb +17 -0
- data/spec/acfs/stub_spec.rb +345 -0
- data/spec/acfs_spec.rb +205 -0
- data/spec/fixtures/config.yml +14 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/hash.rb +11 -0
- data/spec/support/response.rb +12 -0
- data/spec/support/service.rb +92 -0
- data/spec/support/shared/find_callbacks.rb +50 -0
- metadata +136 -3
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Acfs::Resource
|
4
|
+
# @api private
|
5
|
+
#
|
6
|
+
# Provide methods for creating and processing CRUD operations and
|
7
|
+
# handling responses. That includes error handling as well as
|
8
|
+
# handling stubbed resources.
|
9
|
+
#
|
10
|
+
# Should only be used internal.
|
11
|
+
#
|
12
|
+
module Operational
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
delegate :operation, to: :'self.class'
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Invoke CRUD operation.
|
18
|
+
def operation(action, opts = {}, &block)
|
19
|
+
Acfs.runner.process ::Acfs::Operation.new self, action, opts, &block
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Acfs::Resource
|
4
|
+
#
|
5
|
+
# Allow to track the persistence state of a model.
|
6
|
+
#
|
7
|
+
module Persistence
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
# @api public
|
11
|
+
#
|
12
|
+
# Check if the model is persisted. A model is persisted if
|
13
|
+
# it is saved after being created
|
14
|
+
#
|
15
|
+
# @example Newly created resource:
|
16
|
+
# user = User.new name: "John"
|
17
|
+
# user.persisted? # => false
|
18
|
+
# user.save
|
19
|
+
# user.persisted? # => true
|
20
|
+
#
|
21
|
+
# @example Modified resource:
|
22
|
+
# user2 = User.find 5
|
23
|
+
# user2.persisted? # => true
|
24
|
+
# user2.name = 'Amy'
|
25
|
+
# user2.persisted? # => true
|
26
|
+
# user2.save
|
27
|
+
# user2.persisted? # => true
|
28
|
+
#
|
29
|
+
# @return [Boolean] True if resource has been saved
|
30
|
+
#
|
31
|
+
def persisted?
|
32
|
+
!new?
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api public
|
36
|
+
#
|
37
|
+
# Return true if model is a new record and was not saved yet.
|
38
|
+
#
|
39
|
+
# @return [Boolean] True if resource is newly created,
|
40
|
+
# false otherwise.
|
41
|
+
#
|
42
|
+
def new?
|
43
|
+
!loaded?
|
44
|
+
end
|
45
|
+
alias new_record? new?
|
46
|
+
|
47
|
+
# @api public
|
48
|
+
#
|
49
|
+
# Saves the resource.
|
50
|
+
#
|
51
|
+
# It will PUT to the service to update the resource or send
|
52
|
+
# a POST to create a new one if the resource is new.
|
53
|
+
#
|
54
|
+
# Saving a resource is a synchronous operation.
|
55
|
+
#
|
56
|
+
# @return [Boolean] True if save operation was successful,
|
57
|
+
# false otherwise.
|
58
|
+
# @see #save! See {#save!} for available options.
|
59
|
+
#
|
60
|
+
def save(*args)
|
61
|
+
save!(*args)
|
62
|
+
true
|
63
|
+
rescue Acfs::Error
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api public
|
68
|
+
#
|
69
|
+
# Saves the resource. Raises an error if something happens.
|
70
|
+
#
|
71
|
+
# Saving a resource is a synchronous operation.
|
72
|
+
#
|
73
|
+
# @param opts [Hash] Hash with additional options.
|
74
|
+
# @option opts [Hash] :data Data to send to remote service.
|
75
|
+
# Default will be resource attributes.
|
76
|
+
#
|
77
|
+
# @raise [Acfs::InvalidResource]
|
78
|
+
# If remote services respond with 422 response. Will fill
|
79
|
+
# errors with data from response
|
80
|
+
# @raise [Acfs::ErroneousResponse]
|
81
|
+
# If remote service respond with not successful response.
|
82
|
+
#
|
83
|
+
# @see #save
|
84
|
+
#
|
85
|
+
def save!(opts = {})
|
86
|
+
opts[:data] = attributes unless opts[:data]
|
87
|
+
|
88
|
+
operation((new? ? :create : :update), opts) do |data|
|
89
|
+
update_with data
|
90
|
+
end
|
91
|
+
rescue ::Acfs::InvalidResource => e
|
92
|
+
self.remote_errors = e.errors
|
93
|
+
raise e
|
94
|
+
end
|
95
|
+
|
96
|
+
# @api public
|
97
|
+
#
|
98
|
+
# Update attributes with given data and save resource.
|
99
|
+
#
|
100
|
+
# Saving a resource is a synchronous operation.
|
101
|
+
#
|
102
|
+
# @param attrs [Hash] Hash with attributes to write.
|
103
|
+
# @param opts [Hash] Options passed to `save`.
|
104
|
+
#
|
105
|
+
# @return [Boolean]
|
106
|
+
# True if save operation was successful, false otherwise.
|
107
|
+
#
|
108
|
+
# @see #save
|
109
|
+
# @see #attributes=
|
110
|
+
# @see #update_attributes!
|
111
|
+
#
|
112
|
+
def update_attributes(attrs, opts = {})
|
113
|
+
check_loaded! opts
|
114
|
+
|
115
|
+
self.attributes = attrs
|
116
|
+
save opts
|
117
|
+
end
|
118
|
+
|
119
|
+
# @api public
|
120
|
+
#
|
121
|
+
# Update attributes with given data and save resource.
|
122
|
+
#
|
123
|
+
# Saving a resource is a synchronous operation.
|
124
|
+
#
|
125
|
+
# @param [Hash] attrs Hash with attributes to write.
|
126
|
+
# @param [Hash] opts Options passed to `save!`.
|
127
|
+
#
|
128
|
+
# @raise [Acfs::InvalidResource]
|
129
|
+
# If remote services respond with 422 response. Will fill
|
130
|
+
# errors with data from response
|
131
|
+
#
|
132
|
+
# @raise [Acfs::ErroneousResponse]
|
133
|
+
# If remote service respond with not successful response.
|
134
|
+
#
|
135
|
+
# @see #save!
|
136
|
+
# @see #attributes=
|
137
|
+
# @see #update_attributes
|
138
|
+
#
|
139
|
+
def update_attributes!(attrs, opts = {})
|
140
|
+
check_loaded! opts
|
141
|
+
|
142
|
+
self.attributes = attrs
|
143
|
+
save! opts
|
144
|
+
end
|
145
|
+
|
146
|
+
# @api public
|
147
|
+
#
|
148
|
+
# Destroy resource by sending a DELETE request.
|
149
|
+
#
|
150
|
+
# Deleting a resource is a synchronous operation.
|
151
|
+
#
|
152
|
+
# @return [Boolean]
|
153
|
+
# @see #delete!
|
154
|
+
#
|
155
|
+
def delete(opts = {})
|
156
|
+
delete! opts
|
157
|
+
true
|
158
|
+
rescue Acfs::Error
|
159
|
+
false
|
160
|
+
end
|
161
|
+
|
162
|
+
# @api public
|
163
|
+
#
|
164
|
+
# Destroy resource by sending a DELETE request.
|
165
|
+
# Will raise an error in case something goes wrong.
|
166
|
+
#
|
167
|
+
# Deleting a resource is a synchronous operation.
|
168
|
+
|
169
|
+
# @raise [Acfs::ErroneousResponse]
|
170
|
+
# If remote service respond with not successful response.
|
171
|
+
#
|
172
|
+
# @return [undefined]
|
173
|
+
# @see #delete
|
174
|
+
#
|
175
|
+
def delete!(opts = {})
|
176
|
+
opts[:params] ||= {}
|
177
|
+
opts[:params] = attributes_for_url(:delete).merge opts[:params]
|
178
|
+
|
179
|
+
operation :delete, opts do |data|
|
180
|
+
update_with data
|
181
|
+
freeze
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def attributes_for_url(action)
|
188
|
+
arguments_for_url = self.class.location(action: action).arguments
|
189
|
+
attributes.slice(*arguments_for_url)
|
190
|
+
end
|
191
|
+
|
192
|
+
module ClassMethods
|
193
|
+
# @api public
|
194
|
+
#
|
195
|
+
# Create a new resource sending given data. If resource cannot be
|
196
|
+
# created an error will be thrown.
|
197
|
+
#
|
198
|
+
# Saving a resource is a synchronous operation.
|
199
|
+
#
|
200
|
+
# @param data [Hash{Symbol, String => Object}]
|
201
|
+
# Data to send in create request.
|
202
|
+
#
|
203
|
+
# @return [self] Newly resource object.
|
204
|
+
#
|
205
|
+
# @raise [Acfs::InvalidResource]
|
206
|
+
# If remote services respond with 422 response. Will fill
|
207
|
+
# errors with data from response
|
208
|
+
#
|
209
|
+
# @raise [Acfs::ErroneousResponse]
|
210
|
+
# If remote service respond with not successful response.
|
211
|
+
#
|
212
|
+
# @see Acfs::Model::Persistence#save! Available options. `:data`
|
213
|
+
# will be overridden with provided data hash.
|
214
|
+
# @see #create
|
215
|
+
#
|
216
|
+
def create!(data, _opts = {})
|
217
|
+
new(data).tap(&:save!)
|
218
|
+
end
|
219
|
+
|
220
|
+
# @api public
|
221
|
+
#
|
222
|
+
# Create a new resource sending given data. If resource cannot be
|
223
|
+
# create model will be returned and error hash contains response
|
224
|
+
# errors if available.
|
225
|
+
#
|
226
|
+
# Saving a resource is a synchronous operation.
|
227
|
+
#
|
228
|
+
# @param data [Hash{Symbol, String => Object}]
|
229
|
+
# Data to send in create request.
|
230
|
+
#
|
231
|
+
# @return [self] Newly resource object.
|
232
|
+
#
|
233
|
+
# @raise [Acfs::ErroneousResponse]
|
234
|
+
# If remote service respond with not successful response.
|
235
|
+
#
|
236
|
+
# @see Acfs::Model::Persistence#save! Available options. `:data`
|
237
|
+
# will be overridden with provided data hash.
|
238
|
+
# @see #create!
|
239
|
+
#
|
240
|
+
def create(data, _opts = {})
|
241
|
+
model = new data
|
242
|
+
model.save
|
243
|
+
model
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
private
|
248
|
+
|
249
|
+
def update_with(data)
|
250
|
+
self.attributes = data
|
251
|
+
loaded!
|
252
|
+
end
|
253
|
+
|
254
|
+
def check_loaded!(opts = {})
|
255
|
+
return if loaded? || opts[:force]
|
256
|
+
|
257
|
+
raise ::Acfs::ResourceNotLoaded.new resource: self
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Acfs::Resource
|
4
|
+
# Methods providing the query interface for finding resouces.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class MyUser < Acfs::Resource
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# MyUser.find(5) # Find single resource
|
11
|
+
# MyUser.all # Full or partial collection of
|
12
|
+
# # resources
|
13
|
+
# Comment.where(user: user.id) # Collection with additional parameter
|
14
|
+
# # to filter resources
|
15
|
+
#
|
16
|
+
module QueryMethods
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
# @api public
|
21
|
+
#
|
22
|
+
# @overload find(id, opts = {})
|
23
|
+
# Find a single resource by given ID.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# user = User.find(5) # Will query `http://base.url/users/5`
|
27
|
+
#
|
28
|
+
# @param id [Fixnum] Resource IDs to fetch from remote service.
|
29
|
+
# @param params [Hash] Additional options.
|
30
|
+
# @option opts [Hash] :params Additional parameters added to
|
31
|
+
# request. `:id` will be overridden with given ID.
|
32
|
+
#
|
33
|
+
# @yield [resource] Callback block to be executed after resource
|
34
|
+
# was fetched successfully.
|
35
|
+
# @yieldparam resource [self] Fetched resources.
|
36
|
+
#
|
37
|
+
# @return [self] Resource object if only one ID was given.
|
38
|
+
#
|
39
|
+
# @overload find(ids, opts = {})
|
40
|
+
# Load collection of specified resources by given IDs.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# User.find([1, 2, 5]) # Will return collection and will request
|
44
|
+
# # `http://base.url/users/1`,
|
45
|
+
# # `http://base.url/users/2`
|
46
|
+
# # and `http://base.url/users/5` parallel
|
47
|
+
#
|
48
|
+
# @param ids [Array<Integer>] List of resource IDs.
|
49
|
+
# @param opts [Hash] Additional options.
|
50
|
+
# @option opts [Hash] :params Additional parameters added to
|
51
|
+
# request. `:id` will be overridden with individual resource ID.
|
52
|
+
#
|
53
|
+
# @yield [collection] Callback block to be executed after collection
|
54
|
+
# was fetched successfully.
|
55
|
+
# @yieldparam resource [Collection] Collection with fetched resources.
|
56
|
+
#
|
57
|
+
# @return [Collection] Collection of requested resources.
|
58
|
+
#
|
59
|
+
def find(id_or_ids, opts = {}, &block)
|
60
|
+
if id_or_ids.respond_to? :each
|
61
|
+
find_multiple id_or_ids, opts, &block
|
62
|
+
else
|
63
|
+
find_single id_or_ids, opts, &block
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api public
|
68
|
+
#
|
69
|
+
# Try to load all resources.
|
70
|
+
#
|
71
|
+
# @param params [Hash] Request parameters that will be send to
|
72
|
+
# remote service.
|
73
|
+
#
|
74
|
+
# @yield [collection] Callback block to be executed when resource
|
75
|
+
# collection was loaded successfully.
|
76
|
+
# @yieldparam collection [Collection] Collection of fetched resources.
|
77
|
+
#
|
78
|
+
# @return [Collection] Collection of requested resources.
|
79
|
+
#
|
80
|
+
def all(params = {}, opts = {}, &block)
|
81
|
+
collection = ::Acfs::Collection.new self
|
82
|
+
collection.__callbacks__ << block if block
|
83
|
+
|
84
|
+
operation :list, opts.merge(params: params) do |data, response|
|
85
|
+
data.each {|obj| collection << create_resource(obj) }
|
86
|
+
collection.process_response response
|
87
|
+
collection.loaded!
|
88
|
+
collection.__invoke__
|
89
|
+
end
|
90
|
+
|
91
|
+
collection
|
92
|
+
end
|
93
|
+
alias where all
|
94
|
+
|
95
|
+
# @api public
|
96
|
+
#
|
97
|
+
# Try to load first resource. Return nil if no object can be loaded.
|
98
|
+
#
|
99
|
+
# @param params [Hash] Request parameters that will be send
|
100
|
+
# to remote service.
|
101
|
+
#
|
102
|
+
# @yield [resource] Callback block to be executed after
|
103
|
+
# resource was fetched (even if nil).
|
104
|
+
# @yieldparam resource [self] Fetched resource, nil
|
105
|
+
# if empty list is returned
|
106
|
+
#
|
107
|
+
# @return [self] Resource object, nil if empty list is returned
|
108
|
+
#
|
109
|
+
def find_by(params, &block)
|
110
|
+
Acfs::Util::ResourceDelegator.new(new).tap do |m|
|
111
|
+
m.__callbacks__ << block unless block.nil?
|
112
|
+
operation :list, params: params do |data|
|
113
|
+
if data.empty?
|
114
|
+
m.__setobj__ nil
|
115
|
+
else
|
116
|
+
m.__setobj__ create_resource(data.first, origin: m.__getobj__)
|
117
|
+
end
|
118
|
+
m.__invoke__
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# @api public
|
124
|
+
#
|
125
|
+
# Try to load first resource. Raise Acfs::ResourceNotFound
|
126
|
+
# exception if no object can be loaded.
|
127
|
+
#
|
128
|
+
# @param params [Hash] Request parameters that will be send
|
129
|
+
# to remote service.
|
130
|
+
#
|
131
|
+
# @yield [resource] Callback block to be executed after
|
132
|
+
# resource was fetched successfully.
|
133
|
+
# @yieldparam resource [self] Fetched resource, nil
|
134
|
+
# if empty list is returned
|
135
|
+
#
|
136
|
+
# @return [self] Resource object, nil if empty list is returned
|
137
|
+
#
|
138
|
+
def find_by!(params, &block)
|
139
|
+
find_by params do |m|
|
140
|
+
if m.nil?
|
141
|
+
raise Acfs::ResourceNotFound.new message: 'Received erroneous ' \
|
142
|
+
"response: no `#{name}` with params #{params} found"
|
143
|
+
end
|
144
|
+
block&.call m
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# @api public
|
149
|
+
#
|
150
|
+
# Iterates over all pages returned by index action.
|
151
|
+
#
|
152
|
+
# Server must return a paginated resource.
|
153
|
+
#
|
154
|
+
# @example
|
155
|
+
# User.each_page do |page|
|
156
|
+
# p page.size
|
157
|
+
# end
|
158
|
+
# Acfs.run
|
159
|
+
# # => 50
|
160
|
+
# # => 50
|
161
|
+
# # => 42
|
162
|
+
#
|
163
|
+
# @param opts [Hash] Options passed to {#where}.
|
164
|
+
#
|
165
|
+
# @yield [collection] Callback that will be invoked for each page.
|
166
|
+
# @yieldparam collection [Collection] Paginated collection.
|
167
|
+
#
|
168
|
+
# @return [Collection] First page.
|
169
|
+
#
|
170
|
+
def each_page(opts = {})
|
171
|
+
cb = proc do |collection|
|
172
|
+
yield collection
|
173
|
+
collection.next_page(&cb)
|
174
|
+
end
|
175
|
+
where opts, &cb
|
176
|
+
end
|
177
|
+
|
178
|
+
# @api public
|
179
|
+
#
|
180
|
+
# Iterates over all items of all pages returned by index action.
|
181
|
+
#
|
182
|
+
# Server must return a paginated resource.
|
183
|
+
#
|
184
|
+
# @example
|
185
|
+
# index = 0
|
186
|
+
# User.each_item do |page|
|
187
|
+
# index += 1
|
188
|
+
# end
|
189
|
+
# Acfs.run
|
190
|
+
# print index
|
191
|
+
# # => 142
|
192
|
+
#
|
193
|
+
# @param opts [Hash] Options passed to {#each_page}.
|
194
|
+
#
|
195
|
+
# @yield [item] Callback that will be invoked for each item.
|
196
|
+
# @yieldparam item [self] Resource.
|
197
|
+
# @yieldparam collection [Acfs::Collection] Collection.
|
198
|
+
#
|
199
|
+
def each_item(opts = {})
|
200
|
+
each_page(opts) do |collection|
|
201
|
+
collection.each do |item|
|
202
|
+
yield item, collection
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
|
209
|
+
def find_single(id, opts, &block)
|
210
|
+
model = Acfs::Util::ResourceDelegator.new new
|
211
|
+
|
212
|
+
opts[:params] ||= {}
|
213
|
+
opts[:params].merge! id: id unless id.nil?
|
214
|
+
|
215
|
+
model.__callbacks__ << block unless block.nil?
|
216
|
+
|
217
|
+
operation :read, opts do |data|
|
218
|
+
model.__setobj__ create_resource data, origin: model.__getobj__
|
219
|
+
model.__invoke__
|
220
|
+
end
|
221
|
+
|
222
|
+
model
|
223
|
+
end
|
224
|
+
|
225
|
+
def find_multiple(ids, opts, &block)
|
226
|
+
::Acfs::Collection.new(self).tap do |collection|
|
227
|
+
collection.__callbacks__ << block unless block.nil?
|
228
|
+
|
229
|
+
counter = 0
|
230
|
+
ids.each_with_index do |id, index|
|
231
|
+
find_single id, opts do |resource|
|
232
|
+
collection[index] = resource
|
233
|
+
if (counter += 1) == ids.size
|
234
|
+
collection.loaded!
|
235
|
+
collection.__invoke__
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def create_resource(data, opts = {})
|
243
|
+
type = data.delete 'type'
|
244
|
+
klass = resource_class_lookup(type)
|
245
|
+
(opts[:origin].is_a?(klass) ? opts[:origin] : klass.new).tap do |m|
|
246
|
+
m.write_attributes data, opts
|
247
|
+
m.loaded!
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def resource_class_lookup(type)
|
252
|
+
return self if type.nil?
|
253
|
+
|
254
|
+
klass = type.camelize.constantize
|
255
|
+
|
256
|
+
unless klass <= self
|
257
|
+
raise Acfs::ResourceTypeError.new type_name: type, base_class: self
|
258
|
+
end
|
259
|
+
|
260
|
+
klass
|
261
|
+
rescue NameError, NoMethodError
|
262
|
+
raise Acfs::ResourceTypeError.new type_name: type, base_class: self
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|