smooth_operator 1.3.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/Gemfile +0 -5
- data/README.md +11 -308
- data/console.rb +3 -28
- data/lib/smooth_operator.rb +7 -75
- data/lib/smooth_operator/array_with_meta_data.rb +21 -20
- data/lib/smooth_operator/attribute_assignment.rb +53 -57
- data/lib/smooth_operator/delegation.rb +34 -15
- data/lib/smooth_operator/finder_methods.rb +17 -33
- data/lib/smooth_operator/helpers.rb +7 -37
- data/lib/smooth_operator/internal_attribute.rb +49 -0
- data/lib/smooth_operator/model_schema.rb +72 -0
- data/lib/smooth_operator/open_struct.rb +4 -7
- data/lib/smooth_operator/operator.rb +64 -102
- data/lib/smooth_operator/persistence.rb +64 -94
- data/lib/smooth_operator/remote_call.rb +70 -0
- data/lib/smooth_operator/serialization.rb +33 -89
- data/lib/smooth_operator/translation.rb +13 -26
- data/lib/smooth_operator/type_converter.rb +69 -0
- data/lib/smooth_operator/validations.rb +3 -25
- data/lib/smooth_operator/version.rb +1 -1
- data/smooth_operator.gemspec +5 -9
- data/spec/factories/user_factory.rb +4 -5
- data/spec/smooth_operator/attribute_assignment_spec.rb +11 -145
- data/spec/smooth_operator/delegation_spec.rb +54 -57
- data/spec/smooth_operator/finder_methods_spec.rb +2 -91
- data/spec/smooth_operator/{resource_name_spec.rb → model_schema_spec.rb} +2 -2
- data/spec/smooth_operator/operator_spec.rb +1 -1
- data/spec/smooth_operator/persistence_spec.rb +20 -140
- data/spec/smooth_operator/serialization_spec.rb +4 -28
- data/spec/spec_helper.rb +9 -7
- data/spec/support/models/address.rb +0 -9
- data/spec/support/models/post.rb +3 -9
- data/spec/support/models/user.rb +7 -30
- data/spec/support/models/user_with_address_and_posts.rb +12 -20
- data/spec/support/test_server.rb +7 -63
- metadata +18 -55
- data/lib/smooth_operator/associations.rb +0 -110
- data/lib/smooth_operator/associations/association_reflection.rb +0 -79
- data/lib/smooth_operator/associations/has_many_relation.rb +0 -45
- data/lib/smooth_operator/associations/reflection.rb +0 -41
- data/lib/smooth_operator/cookie_jar.rb +0 -21
- data/lib/smooth_operator/http_methods.rb +0 -17
- data/lib/smooth_operator/internal_data.rb +0 -45
- data/lib/smooth_operator/operators/connection_wrapper.rb +0 -15
- data/lib/smooth_operator/operators/faraday.rb +0 -75
- data/lib/smooth_operator/operators/typhoeus.rb +0 -87
- data/lib/smooth_operator/options.rb +0 -30
- data/lib/smooth_operator/remote_call/base.rb +0 -76
- data/lib/smooth_operator/remote_call/errors/connection_failed.rb +0 -20
- data/lib/smooth_operator/remote_call/errors/timeout.rb +0 -20
- data/lib/smooth_operator/remote_call/faraday.rb +0 -19
- data/lib/smooth_operator/remote_call/typhoeus.rb +0 -19
- data/lib/smooth_operator/resource_name.rb +0 -46
- data/lib/smooth_operator/schema.rb +0 -21
- data/lib/smooth_operator/type_casting.rb +0 -127
- data/spec/require_helper.rb +0 -11
- data/spec/smooth_operator/remote_call_spec.rb +0 -340
- data/spec/smooth_operator/validations_spec.rb +0 -42
- data/spec/support/models/comment.rb +0 -5
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MjU3NWQ2OTMyMjE4ODBjZGMzZWJmMmRlMzcxZDBmMWZjYmU5YjYwOQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Y2E5MDEyYmYxODcwNmQ4MzY2MWFlMmViYTQ3Y2QxN2FlOWU2ZTJiOA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NzlmOGZhNzVhYTVkOTE0YTI4OGZkMjhjNDlkYWE1NWEzZmE0YmIzY2RmMGVk
|
10
|
+
NzcyYTlmY2ZhZmNmZmU4MzIyOWY4ZjU2MmFlYTU4ZjRmNzI2OTczYmM3MGNi
|
11
|
+
ZDUyMGZkOGYwZDBkZThmNTE5ZTQxMTkxN2JjZWRiYTFlNzg4Nzk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YWI0YjkzNDVmN2JhMmY0MzYxMmE4NGQ1ZDAxMDM1NzZkYThiZjZhMmYxZmE2
|
14
|
+
NzIzYTQ5MzA0NDg4NzE5ZmM2ODgzOTFmYjkwNzMxYjZiMTdmZjRjZDUzYjM4
|
15
|
+
YzQzZTc3NzJkM2I2OGM5MzFhYTQ0NDc5MWU1MGI0NmE0MzkzNGM=
|
data/Gemfile
CHANGED
@@ -3,15 +3,10 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in smooth_operator.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem 'simplecov', :require => false, :group => :test
|
7
|
-
|
8
6
|
group :development, :test do
|
9
7
|
gem "pry"
|
10
8
|
gem "sinatra"
|
11
|
-
gem "typhoeus"
|
12
|
-
gem "activesupport"
|
13
9
|
gem "sinatra-contrib"
|
14
10
|
gem "rspec", "~> 3.0.0.beta1"
|
15
11
|
gem "factory_girl", "~> 4.0"
|
16
|
-
gem "ethon", :git => 'https://github.com/goncalvesjoao/ethon'
|
17
12
|
end
|
data/README.md
CHANGED
@@ -1,23 +1,14 @@
|
|
1
|
-
# SmoothOperator
|
1
|
+
# SmoothOperator
|
2
2
|
|
3
3
|
Ruby gem, that mimics the ActiveRecord behaviour but through external API's.
|
4
4
|
It's a lightweight and flexible alternative to ActiveResource, that responds to a REST API like you expect it too.
|
5
5
|
|
6
|
-
|
6
|
+
Depends only on Faraday gem, no need for ActiveSupport or any other Active* gem.
|
7
7
|
|
8
|
-
|
8
|
+
Although if I18n is present it will respond to .human_attribute_name method and if ActiveModel is present it will make use of 'ActiveModel::Name' to improve .model_name method.
|
9
9
|
|
10
|
-
This micro-services example will also feature other cool stuff like:
|
11
|
-
- parallel requests;
|
12
|
-
- using HTTP PATCH verb for saving instead of PUT;
|
13
|
-
- form errors with simple_form gem;
|
14
|
-
- nested objects using cocoon gem;
|
15
|
-
- endless-pagination with kaminari gem
|
16
|
-
- and others...
|
17
10
|
|
18
|
-
|
19
|
-
|
20
|
-
## 1) Installation
|
11
|
+
## Installation
|
21
12
|
|
22
13
|
Add this line to your application's Gemfile:
|
23
14
|
|
@@ -31,303 +22,15 @@ Or install it yourself as:
|
|
31
22
|
|
32
23
|
$ gem install smooth_operator
|
33
24
|
|
34
|
-
---
|
35
|
-
|
36
|
-
## 2) Usage and Examples
|
37
|
-
|
38
|
-
```ruby
|
39
|
-
class MyBlogResource < SmoothOperator::Base
|
40
|
-
|
41
|
-
# HTTP BASIC AUTH
|
42
|
-
options endpoint_user: 'admin',
|
43
|
-
endpoint_pass: 'admin',
|
44
|
-
endpoint: 'http://myblog.com/api/v0'
|
45
|
-
|
46
|
-
# OR
|
47
|
-
# smooth_operator_options
|
48
|
-
end
|
49
|
-
|
50
|
-
class Post < MyBlogResource
|
51
|
-
end
|
52
|
-
```
|
53
|
-
|
54
|
-
---
|
55
|
-
|
56
|
-
### 2.1) Creating a .new 'Post' and #save it
|
57
|
-
|
58
|
-
```ruby
|
59
|
-
post = Post.new(body: 'my first post', author: 'John Doe')
|
60
|
-
|
61
|
-
post.new_record? # true
|
62
|
-
post.persisted? # false
|
63
|
-
post.body # 'my first post'
|
64
|
-
post.author # 'John Doe'
|
65
|
-
post.something_else # will raise NoMethodError
|
66
|
-
|
67
|
-
save_result = post.save # will make a http POST call to 'http://myblog.com/api/v0/posts'
|
68
|
-
# with `{ post: { body: 'my first post', author: 'John Doe' } }`
|
69
|
-
|
70
|
-
post.last_remote_call # will contain a SmoothOperator::RemoteCall instance containing relevant information about the save remote call.
|
71
|
-
|
72
|
-
# If the server response is positive (http code between 200 and 299):
|
73
|
-
save_result # true
|
74
|
-
post.new_record? # false
|
75
|
-
post.persisted? # true
|
76
|
-
# server response contains { id: 1 } on its body
|
77
|
-
post.id # 1
|
78
|
-
|
79
|
-
# If the server response is negative (http code between 400 and 499):
|
80
|
-
save_result # false
|
81
|
-
post.new_record? # true
|
82
|
-
post.persisted? # false
|
83
|
-
# server response contains { errors: { body: ['must be less then 10 letters'] } }
|
84
|
-
post.errors.body # Array
|
85
|
-
|
86
|
-
# If the server response is an error (http code between 500 and 599), or the connection was broke:
|
87
|
-
save_result # nil
|
88
|
-
post.new_record? # true
|
89
|
-
post.persisted? # false
|
90
|
-
# server response contains { errors: { body: ['must be less then 10 letters'] } }
|
91
|
-
post.errors # will raise NoMethodError
|
92
|
-
|
93
|
-
# In the positive and negative server response comes with a json,
|
94
|
-
# e.g. { id: 1 }, post will reflect that new data
|
95
|
-
post.id # 1
|
96
|
-
|
97
|
-
# In case of error and the server response contains a json,
|
98
|
-
# e.g. { id: 1 }, post will NOT reflect that data
|
99
|
-
post.id # raise NoMethodError
|
100
|
-
|
101
|
-
```
|
102
|
-
|
103
|
-
---
|
104
|
-
|
105
|
-
### 2.2) Editing an existing record
|
106
|
-
```ruby
|
107
|
-
post = Post.find(2)
|
108
|
-
|
109
|
-
post.body = 'editing my second page'
|
110
|
-
|
111
|
-
post.save
|
112
|
-
```
|
113
|
-
|
114
|
-
---
|
115
|
-
|
116
|
-
### 2.3) Customize #save 'url', 'params' and 'options'
|
117
|
-
```ruby
|
118
|
-
post = Post.new(id: 2, body: 'editing my second page')
|
119
|
-
|
120
|
-
post.new_record? # false
|
121
|
-
post.persisted? # true
|
122
|
-
|
123
|
-
post.save("save_and_add_to_list", { admin: true, post: { author: 'Agent Smith', list_id: 1 } }, { timeout: 1 })
|
124
|
-
# Will make a PUT to 'http://myblog.com/api/v0/posts/2/save_and_add_to_list'
|
125
|
-
# with { admin: true, post: { body: 'editing my second page', list_id: 1 } }
|
126
|
-
# and will only wait 1sec for the server to respond.
|
127
|
-
|
128
|
-
post.save('/#{post.id}/save_and_add_to_list')
|
129
|
-
# Will make a PUT to 'http://myblog.com/api/v0/posts/2/save_and_add_to_list'
|
130
|
-
|
131
|
-
post.save('/save_and_add_to_list')
|
132
|
-
# Will make a PUT to 'http://myblog.com/api/v0/posts/save_and_add_to_list'
|
133
|
-
```
|
134
|
-
|
135
|
-
---
|
136
|
-
|
137
|
-
### 2.4) Saving using HTTP Patch verb
|
138
|
-
```ruby
|
139
|
-
class Page < MyBlogResource
|
140
|
-
options update_http_verb: 'patch'
|
141
|
-
# OR
|
142
|
-
#smooth_operator_options update_http_verb: 'patch'
|
143
|
-
end
|
144
|
-
|
145
|
-
page = Page.find(2)
|
146
|
-
|
147
|
-
page.body = 'editing my second page'
|
148
|
-
|
149
|
-
page.save # will make a http PATCH call to 'http://myblog.com/api/v0/pages/2'
|
150
|
-
# with `{ page: { body: 'editing my second page' } }`
|
151
|
-
```
|
152
|
-
|
153
|
-
---
|
154
|
-
|
155
|
-
### 2.5) Retrieving remote objects - 'index' REST action
|
156
|
-
|
157
|
-
```ruby
|
158
|
-
remote_call = Page.find(:all) # Will make a GET call to 'http://myblog.com/api/v0/pages'
|
159
|
-
# and will return a SmoothOperator::RemoteCall instance
|
160
|
-
|
161
|
-
pages = remote_call.data
|
162
|
-
|
163
|
-
# If the server response is positive (http code between 200 and 299, or 304):
|
164
|
-
remote_call.ok? # true
|
165
|
-
remote_call.not_processed? # false
|
166
|
-
remote_call.error? # false
|
167
|
-
remote_call.status # true
|
168
|
-
pages = remote_call.data # array of Page instances
|
169
|
-
remote_call.http_status # server_response code
|
170
|
-
|
171
|
-
# If the server response is unprocessed entity (http code 422):
|
172
|
-
remote_call.ok? # false
|
173
|
-
remote_call.not_processed? # true
|
174
|
-
remote_call.error? # false
|
175
|
-
remote_call.status # false
|
176
|
-
remote_call.http_status # server_response code
|
177
|
-
|
178
|
-
# If the server response is client error (http code between 400..499, except 422):
|
179
|
-
remote_call.ok? # false
|
180
|
-
remote_call.not_processed? # false
|
181
|
-
remote_call.error? # true
|
182
|
-
remote_call.status # nil
|
183
|
-
remote_call.http_status # server_response code
|
184
|
-
|
185
|
-
# If the server response is server error (http code between 500 and 599), or the connection broke:
|
186
|
-
remote_call.ok? # false
|
187
|
-
remote_call.not_processed? # false
|
188
|
-
remote_call.error? # true
|
189
|
-
remote_call.status # nil
|
190
|
-
remote_call.http_status # server_response code or 0 if connection broke
|
191
|
-
```
|
192
|
-
|
193
|
-
---
|
194
|
-
|
195
|
-
### 2.6) Retrieving remote objects - 'show' REST action
|
196
|
-
|
197
|
-
```ruby
|
198
|
-
remote_call = Page.find(2) # Will make a GET call to 'http://myblog.com/api/v0/pages/2'
|
199
|
-
# and will return a SmoothOperator::RemoteCall instance
|
200
|
-
|
201
|
-
service_down = remote_call.error?
|
202
|
-
|
203
|
-
page = remote_call.data
|
204
|
-
```
|
205
|
-
|
206
|
-
---
|
207
|
-
|
208
|
-
### 2.7) Retrieving remote objects - custom query
|
209
|
-
```ruby
|
210
|
-
remote_call = Page.find('my_pages', { q: body_contains: 'link' }, { endpoint_user: 'admin', endpoint_pass: 'new_password' })
|
211
|
-
# will make a GET call to 'http://myblog.com/api/v0/pages/my_pages?q={body_contains="link"}'
|
212
|
-
# and will change the HTTP BASIC AUTH credentials to user: 'admin' and pass: 'new_password' for this connection only.
|
213
|
-
|
214
|
-
@service_down = remote_call.error?
|
215
|
-
|
216
|
-
# If the server json response is an Array [{ id: 1 }, { id: 2 }]
|
217
|
-
@pages = remote.data # will return an array with 2 Page's instances
|
218
|
-
@pages[0].id # 1
|
219
|
-
@pages[1].id # 2
|
220
|
-
|
221
|
-
# If the server json response is a Hash { id: 3 }
|
222
|
-
@page = remote.data # will return a single Page instance
|
223
|
-
@page.id # 3
|
224
|
-
|
225
|
-
# If the server json response is Hash with a key called 'pages' { current_page: 1, total_pages: 3, limit_value: 10, pages: [{ id: 4 }, { id: 5 }] }
|
226
|
-
@pages = remote.data # will return a single ArrayWithMetaData instance, that will allow you to access to both the Page's instances array and the metadata.
|
227
|
-
|
228
|
-
# @pages is now a valid object to work with kaminari
|
229
|
-
@pages.total_pages # 3
|
230
|
-
@pages.current_page # 1
|
231
|
-
@pages.limit_value # 10
|
232
|
-
|
233
|
-
@pages[0].id # 4
|
234
|
-
@pages[1].id # 5
|
235
|
-
```
|
236
|
-
|
237
|
-
### 2.8) Keeping your session alive - custom HTTP Headers
|
238
|
-
|
239
|
-
Controllers
|
240
|
-
ApplicationController
|
241
|
-
```ruby
|
242
|
-
```
|
243
|
-
|
244
|
-
Models
|
245
|
-
SmoothResource
|
246
|
-
```ruby
|
247
|
-
class SmoothResource < SmoothOperator::Rails
|
248
|
-
|
249
|
-
options headers: :custom_headers
|
250
|
-
|
251
|
-
def self.custom_headers
|
252
|
-
{
|
253
|
-
cookie: current_user.blog_cookie,
|
254
|
-
"X_CSRF_TOKEN" => current_user.blog_auth_token
|
255
|
-
}
|
256
|
-
end
|
257
|
-
|
258
|
-
protected ############## PROTECTED #################
|
259
|
-
|
260
|
-
def self.current_user
|
261
|
-
User.current_user
|
262
|
-
end
|
263
|
-
|
264
|
-
end
|
265
|
-
```
|
266
|
-
|
267
|
-
---
|
268
|
-
|
269
|
-
## 3) Methods
|
270
|
-
|
271
|
-
---
|
272
|
-
|
273
|
-
### 3.1) Persistence methods
|
274
|
-
|
275
|
-
Methods | Behaviour | Arguments | Return
|
276
|
-
------- | --------- | ------ | ---------
|
277
|
-
.create | Generates a new instance of the class with *attributes and calls #save with the rest of its arguments| Hash attributes = nil, String relative_path = nil, Hash data = {}, Hash options = {} | Class instance
|
278
|
-
#new_record? | Returns @new_record if defined, else populates it with true if #id is present or false if blank. | - | Boolean
|
279
|
-
#destroyed?| Returns @destroyed if defined, else populates it with false. | - | Boolean
|
280
|
-
#persisted?| Returns true if both #new_record? and #destroyed? return false, else returns false. | - | Boolean
|
281
|
-
#save | if #new_record? makes a HTTP POST, else a PUT call. If !#new_record? and relative_path is blank, sets relative_path = id.to_s. If the server POST response is positive, sets @new_record = false. See 4.2) for more behaviour info. | String relative_path = nil, Hash data = {}, Hash options = {} | Boolean or Nil
|
282
|
-
#save! | Executes the same behaviour as #save, but will raise RecordNotSaved if the returning value is not true | String relative_path = nil, Hash data = {}, Hash options = {} | Boolean or Nil
|
283
|
-
#destroy | Does nothing if !persisted? else makes a HTTP DELETE call. If server response it positive, sets @destroyed = true. If relative_path is blank, sets relative_path = id.to_s. See 4.2) for more behaviour info. | String relative_path = nil, Hash data = {}, Hash options = {} | Boolean or Nil
|
284
|
-
|
285
|
-
---
|
286
|
-
|
287
|
-
### 3.2) Finder methods
|
288
|
-
|
289
|
-
Methods | Behaviour | Arguments | Return
|
290
|
-
------- | --------- | ------ | ---------
|
291
|
-
.find | If relative_path == :all, sets relative_path = ''. Makes a Get call and initiates Class objects with the server's response data. See 4.3) and 4.4) for more behaviour info. | String relative_path, Hash data = {}, Hash options = {} | Class instance, Array of Class instances or an ArrayWithMetaData instance
|
292
|
-
|
293
|
-
---
|
294
|
-
|
295
|
-
### 3.3) Operator methods
|
296
|
-
...
|
297
|
-
|
298
|
-
---
|
299
|
-
|
300
|
-
### 3.3) Remote call methods
|
301
|
-
...
|
302
|
-
|
303
|
-
---
|
304
|
-
|
305
|
-
## 4) Behaviours
|
306
|
-
|
307
|
-
---
|
308
|
-
|
309
|
-
### 4.1) Delegation behaviour
|
310
|
-
...
|
311
|
-
|
312
|
-
---
|
313
|
-
|
314
|
-
### 4.2) Persistent operator behaviour
|
315
|
-
...
|
316
|
-
|
317
|
-
---
|
318
|
-
|
319
|
-
### 4.3) Operator behaviour
|
320
|
-
...
|
321
25
|
|
322
|
-
|
26
|
+
## Usage
|
323
27
|
|
324
|
-
|
325
|
-
...
|
28
|
+
TODO: Write usage instructions here
|
326
29
|
|
327
|
-
---
|
328
30
|
|
329
|
-
##
|
31
|
+
## TODO
|
330
32
|
|
331
|
-
1.
|
332
|
-
2.
|
333
|
-
3.
|
33
|
+
1. FinderMethods specs
|
34
|
+
2. serialization_specs to test the json options for nested classes
|
35
|
+
3. model_schema_specs
|
36
|
+
4. Cache
|
data/console.rb
CHANGED
@@ -3,34 +3,9 @@
|
|
3
3
|
$LOAD_PATH << './'
|
4
4
|
$LOAD_PATH << './lib'
|
5
5
|
|
6
|
-
require
|
6
|
+
require "spec/spec_helper"
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
LocalhostServer.new(TestServer.new, 4567)
|
11
|
-
|
12
|
-
# user = nil
|
13
|
-
|
14
|
-
# hydra = Typhoeus::Hydra::hydra
|
15
|
-
|
16
|
-
# user = User::Base.new(id: 1)
|
17
|
-
# user.reload(nil, nil, { hydra: hydra })
|
18
|
-
|
19
|
-
# User::Base.find(1, nil, { hydra: hydra }) do |remote_call|
|
20
|
-
# user = remote_call.data
|
21
|
-
# end
|
22
|
-
|
23
|
-
#User::Base.post('', { user: { age: 1, posts: [{ body: 'post1' }, 2] } })
|
24
|
-
|
25
|
-
#user = UserWithAddressAndPosts::Son.new(FactoryGirl.attributes_for(:user_with_address_and_posts))
|
26
|
-
#user.save('', { status: 200 })
|
27
|
-
|
28
|
-
# "[{\"patient_id\"=>33, \"messages\"=>[{\"id\"=>\"53722c20cb38247c36000003\", \"title\"=>\"Joao Goncalves\", \"created_at\"=>\"2014-05-13T14:28:48Z\"}, {\"id\"=>\"53722bfccb382485d5000002\", \"title\"=>\"Joao Goncalves\", \"created_at\"=>\"2014-05-13T14:28:12Z\"}, {\"id\"=>\"53722b91cb3824e913000001\", \"title\"=>\"Joao Goncalves\", \"created_at\"=>\"2014-05-13T14:26:25Z\"}]}]"
|
29
|
-
|
30
|
-
post = Post.new(comments: [{ id: 1, name: '1' }, { id: 2, name: '2' }], address: { id: 1, name: 'address' })
|
31
|
-
|
32
|
-
comments_attributes = { "0" => { id: 1, name: '3' }, "1" => { name: '4' } }
|
33
|
-
|
34
|
-
comments_with_errors = { "0" => { id: 1, name: '3', errors: { body: ["can't be blank"] } }, "1" => { name: '4', errors: { body: ["can't be blank"] } } }
|
8
|
+
#User.post('', { user: { age: 1, posts: [{ body: 'post1' }, 2] } })
|
35
9
|
|
36
10
|
binding.pry
|
11
|
+
|
data/lib/smooth_operator.rb
CHANGED
@@ -1,94 +1,26 @@
|
|
1
|
-
require
|
1
|
+
# require 'active_model'
|
2
|
+
|
2
3
|
require "smooth_operator/version"
|
3
4
|
require "smooth_operator/helpers"
|
4
5
|
require "smooth_operator/operator"
|
6
|
+
require "smooth_operator/remote_call"
|
5
7
|
require "smooth_operator/persistence"
|
6
8
|
require "smooth_operator/translation"
|
7
9
|
require "smooth_operator/open_struct"
|
8
|
-
require "smooth_operator/http_methods"
|
9
|
-
require "smooth_operator/associations"
|
10
10
|
require "smooth_operator/finder_methods"
|
11
11
|
|
12
12
|
module SmoothOperator
|
13
|
+
|
13
14
|
class Base < OpenStruct
|
14
15
|
|
15
|
-
extend
|
16
|
-
extend HttpMethods
|
17
|
-
extend Associations
|
16
|
+
extend Operator
|
18
17
|
extend FinderMethods
|
19
18
|
extend Translation if defined? I18n
|
20
19
|
|
21
|
-
include Operator
|
22
|
-
include HttpMethods
|
23
20
|
include Persistence
|
24
|
-
include FinderMethods
|
25
|
-
|
26
|
-
options strict_behaviour: true
|
27
|
-
|
28
|
-
def self.smooth_operator?
|
29
|
-
true
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
if defined?(ActiveModel)
|
35
|
-
class Rails < Base
|
36
|
-
|
37
|
-
include ActiveModel::Validations
|
38
|
-
include ActiveModel::Validations::Callbacks
|
39
|
-
include ActiveModel::Conversion
|
40
|
-
|
41
|
-
options unknown_hash_class: SmoothOperator::OpenStruct
|
42
|
-
|
43
|
-
validate :validate_induced_errors, :validate_nested_objects
|
44
|
-
|
45
|
-
def column_for_attribute(attribute_name)
|
46
|
-
type = self.class.attribute_type(attribute_name)
|
47
|
-
|
48
|
-
ActiveRecord::ConnectionAdapters::Column.new(attribute_name.to_sym, type, type)
|
49
|
-
end
|
50
|
-
|
51
|
-
def save(relative_path = nil, data = {}, options = {})
|
52
|
-
return false unless before_save
|
53
|
-
|
54
|
-
clear_induced_errors
|
55
|
-
|
56
|
-
save_result = valid? ? super : false
|
57
|
-
|
58
|
-
after_save if valid? && save_result
|
59
|
-
|
60
|
-
save_result
|
61
|
-
end
|
62
|
-
|
63
|
-
def before_save
|
64
|
-
true
|
65
|
-
end
|
66
|
-
|
67
|
-
def after_save; end
|
68
|
-
|
69
|
-
def self.model_name
|
70
|
-
smooth_model_name
|
71
|
-
end
|
72
|
-
|
73
|
-
protected ################# PROTECTED ###################
|
74
|
-
|
75
|
-
def validate_induced_errors
|
76
|
-
induced_errors.each do |key, value|
|
77
|
-
[*value].each do |_value|
|
78
|
-
self.errors.add(key, _value) unless self.errors.added?(key, _value)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
Helpers.blank?(induced_errors)
|
83
|
-
end
|
84
|
-
|
85
|
-
def validate_nested_objects
|
86
|
-
all_nested_objects = self.class.reflections.keys
|
87
|
-
.map { |association| send(association) }.flatten.compact
|
88
21
|
|
89
|
-
|
90
|
-
end
|
22
|
+
attr_reader :last_remote_call
|
91
23
|
|
92
|
-
end
|
93
24
|
end
|
25
|
+
|
94
26
|
end
|