smooth_operator 1.8.0 → 1.8.3

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MjU3NWQ2OTMyMjE4ODBjZGMzZWJmMmRlMzcxZDBmMWZjYmU5YjYwOQ==
4
+ N2JjYWE0YjEwY2U0MTk1NWIwZTYxMzlkZTQxNjcwM2M3NDNlZGI4Zg==
5
5
  data.tar.gz: !binary |-
6
- Y2E5MDEyYmYxODcwNmQ4MzY2MWFlMmViYTQ3Y2QxN2FlOWU2ZTJiOA==
6
+ ZGQxNjU4NDk4OGFhZmM5NjdmYzAwNWVjOTE3YmQzMDdjZjVhMTc4YQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NzlmOGZhNzVhYTVkOTE0YTI4OGZkMjhjNDlkYWE1NWEzZmE0YmIzY2RmMGVk
10
- NzcyYTlmY2ZhZmNmZmU4MzIyOWY4ZjU2MmFlYTU4ZjRmNzI2OTczYmM3MGNi
11
- ZDUyMGZkOGYwZDBkZThmNTE5ZTQxMTkxN2JjZWRiYTFlNzg4Nzk=
9
+ NjVhMWJmNzE3YTM2YzI0OTQ1YjIyNTBjYTFiODk2Y2NmZmM1YzIzY2E3M2E0
10
+ NzI1OGM4YWRhOTQyNzVkNmRjMzAwMDM3MzI0MjJlOGFlODYwODNkMjg2Y2Nm
11
+ OWNiNjE3NzZlYjc0OGRmY2Y4NTVhNGFlODI2N2JjYmNkNGRkZDI=
12
12
  data.tar.gz: !binary |-
13
- YWI0YjkzNDVmN2JhMmY0MzYxMmE4NGQ1ZDAxMDM1NzZkYThiZjZhMmYxZmE2
14
- NzIzYTQ5MzA0NDg4NzE5ZmM2ODgzOTFmYjkwNzMxYjZiMTdmZjRjZDUzYjM4
15
- YzQzZTc3NzJkM2I2OGM5MzFhYTQ0NDc5MWU1MGI0NmE0MzkzNGM=
13
+ NjM1ZDQ5NTI5YzI3MmE2Mjk2ZDQ3NmY0OGQ2OGU3ZjkzMWE5ZTVmZDNiMzQ3
14
+ ZjA5YWIyYWNhZWZhNTY4NDhiOTc4MWUzY2ZlYWYyMDQzM2M0MWU4ZjE0M2Vl
15
+ OWVhOTMzYzAzNTI4YmQzNTkzMDEwYjA5MGU1MTY3ODM5NTI1ZmM=
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ 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
+
6
8
  group :development, :test do
7
9
  gem "pry"
8
10
  gem "sinatra"
data/README.md CHANGED
@@ -7,8 +7,9 @@ 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
+ ---
10
11
 
11
- ## Installation
12
+ ## 1) Installation
12
13
 
13
14
  Add this line to your application's Gemfile:
14
15
 
@@ -22,15 +23,252 @@ Or install it yourself as:
22
23
 
23
24
  $ gem install smooth_operator
24
25
 
26
+ ---
25
27
 
26
- ## Usage
28
+ ## 2) Usage and Examples
27
29
 
28
- TODO: Write usage instructions here
30
+ ```ruby
31
+ class MyBlogResource < SmoothOperator::Base
32
+ self.endpoint = 'http://myblog.com/api/v0'
29
33
 
34
+ # HTTP BASIC AUTH
35
+ self.endpoint_user = 'admin'
36
+ self.endpoint_pass = 'admin'
37
+ end
30
38
 
31
- ## TODO
39
+ class Post < MyBlogResource
40
+ end
41
+ ```
32
42
 
33
- 1. FinderMethods specs
34
- 2. serialization_specs to test the json options for nested classes
35
- 3. model_schema_specs
36
- 4. Cache
43
+ ---
44
+
45
+ ### 2.1) Creating a .new 'Post' and #save it
46
+
47
+ ```ruby
48
+ post = Post.new(body: 'my first post', author: 'John Doe')
49
+
50
+ post.new_record? # true
51
+ post.persisted? # false
52
+ post.body # 'my first post'
53
+ post.author # 'John Doe'
54
+ post.something_else # will raise NoMethodError
55
+
56
+ save_result = post.save # will make a http POST call to 'http://myblog.com/api/v0/posts'
57
+ # with `{ post: { body: 'my first post', author: 'John Doe' } }`
58
+
59
+ post.last_remote_call # will contain a SmoothOperator::RemoteCall instance containing relevant information about the save remote call.
60
+
61
+ # If the server response is positive (http code between 200 and 299):
62
+ save_result # true
63
+ post.new_record? # false
64
+ post.persisted? # true
65
+ # server response contains { id: 1 } on its body
66
+ post.id # 1
67
+
68
+ # If the server response is negative (http code between 400 and 499):
69
+ save_result # false
70
+ post.new_record? # true
71
+ post.persisted? # false
72
+ # server response contains { errors: { body: ['must be less then 10 letters'] } }
73
+ post.errors.body # Array
74
+
75
+ # If the server response is an error (http code between 500 and 599), or the connection was broke:
76
+ save_result # nil
77
+ post.new_record? # true
78
+ post.persisted? # false
79
+ # server response contains { errors: { body: ['must be less then 10 letters'] } }
80
+ post.errors # will raise NoMethodError
81
+
82
+ # In the positive and negative server response comes with a json,
83
+ # e.g. { id: 1 }, post will reflect that new data
84
+ post.id # 1
85
+
86
+ # In case of error and the server response contains a json,
87
+ # e.g. { id: 1 }, post will NOT reflect that data
88
+ post.id # raise NoMethodError
89
+
90
+ ```
91
+
92
+ ---
93
+
94
+ ### 2.2) Editing an existing record
95
+ ```ruby
96
+ post = Post.find(2)
97
+
98
+ post.body = 'editing my second page'
99
+
100
+ post.save
101
+ ```
102
+
103
+ ---
104
+
105
+ ### 2.3) Customize #save 'url', 'params' and 'options'
106
+ ```ruby
107
+ post = Post.new(id: 2, body: 'editing my second page')
108
+
109
+ post.new_record? # false
110
+ post.persisted? # true
111
+
112
+ post.save("#{post.id}/save_and_add_to_list", { admin: true, post: { author: 'Agent Smith', list_id: 1 } }, { timeout: 1 })
113
+ # Will make a PUT to 'http://myblog.com/api/v0/posts/2/save_and_add_to_list'
114
+ # with { admin: true, post: { body: 'editing my second page', list_id: 1 } }
115
+ # and will only wait 1sec for the server to respond.
116
+ ```
117
+
118
+ ---
119
+
120
+ ### 2.4) Saving using HTTP Patch verb
121
+ ```ruby
122
+ class Page < MyBlogResource
123
+ self.save_http_verb = :patch
124
+ end
125
+
126
+ page = Page.find(2)
127
+
128
+ page.body = 'editing my second page'
129
+
130
+ page.save # will make a http PATCH call to 'http://myblog.com/api/v0/pages/2'
131
+ # with `{ page: { body: 'editing my second page' } }`
132
+ ```
133
+
134
+ ---
135
+
136
+ ### 2.5) Retrieving remote objects - 'index' REST action
137
+
138
+ ```ruby
139
+ remote_call = Page.find(:all) # Will make a GET call to 'http://myblog.com/api/v0/pages'
140
+ # and will return a SmoothOperator::RemoteCall instance
141
+
142
+ pages = remote_call.objects # 'pages = remote_call.data' also works
143
+
144
+ # If the server response is positive (http code between 200 and 299):
145
+ remote_call.success? # true
146
+ remote_call.failure? # false
147
+ remote_call.error? # false
148
+ remote_call.status # true
149
+ pages = remote_call.data # array of Page instances
150
+ remote_call.http_status # server_response code
151
+
152
+ # If the server response is negative (http code between 400 and 499):
153
+ remote_call.success? # false
154
+ remote_call.failure? # true
155
+ remote_call.error? # false
156
+ remote_call.status # false
157
+ remote_call.http_status # server_response code
158
+
159
+ # If the server response is an error (http code between 500 and 599), or the connection broke:
160
+ remote_call.success? # false
161
+ remote_call.failure? # false
162
+ remote_call.error? # true
163
+ remote_call.status # nil
164
+ remote_call.http_status # server_response code or 0 if connection broke
165
+ ```
166
+
167
+ ---
168
+
169
+ ### 2.6) Retrieving remote objects - 'show' REST action
170
+
171
+ ```ruby
172
+ remote_call = Page.find(2) # Will make a GET call to 'http://myblog.com/api/v0/pages/2'
173
+ # and will return a SmoothOperator::RemoteCall instance
174
+
175
+ page = remote_call.object # 'page = remote_call.data' also works
176
+ ```
177
+
178
+ ---
179
+
180
+ ### 2.7) Retrieving remote objects - custom query
181
+ ```ruby
182
+ remote_call = Page.find('my_pages', { q: body_contains: 'link' }, { endpoint_user: 'admin', endpoint_pass: 'new_password' })
183
+ # will make a GET call to 'http://myblog.com/api/v0/pages/my_pages?q={body_contains="link"}'
184
+ # and will change the HTTP BASIC AUTH credentials to user: 'admin' and pass: 'new_password' for this connection only.
185
+
186
+ # If the server json response is an Array [{ id: 1 }, { id: 2 }]
187
+ pages = remote.data # will return an array with 2 Page's instances
188
+ pages[0].id # 1
189
+ pages[1].id # 2
190
+
191
+ # If the server json response is a Hash { id: 3 }
192
+ page = remote.data # will return a single Page instance
193
+ page.id # 3
194
+
195
+ # If the server json response is Hash with a key called 'pages' { page: 1, total: 3, pages: [{ id: 4 }, { id: 5 }] }
196
+ 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.
197
+ pages.page # 1
198
+ pages.total # 3
199
+
200
+ pages[0].id # 4
201
+ pages[1].id # 5
202
+ ```
203
+
204
+ ---
205
+
206
+ ## 3) Methods
207
+
208
+ ---
209
+
210
+ ### 3.1) Persistence methods
211
+
212
+ Methods | Behaviour | Arguments | Return
213
+ ------- | --------- | ------ | ---------
214
+ .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
215
+ #new_record? | Returns @new_record if defined, else populates it with true if #id is present or false if blank. | - | Boolean
216
+ #destroyed?| Returns @destroyed if defined, else populates it with false. | - | Boolean
217
+ #persisted?| Returns true if both #new_record? and #destroyed? return false, else returns false. | - | Boolean
218
+ #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
219
+ #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
220
+ #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
221
+
222
+ ---
223
+
224
+ ### 3.2) Finder methods
225
+
226
+ Methods | Behaviour | Arguments | Return
227
+ ------- | --------- | ------ | ---------
228
+ .all | calls .find(:all, data, options) | Hash data = {}, Hash options = {} | Class instance, Array of Class instances or an ArrayWithMetaData instance
229
+ .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
230
+
231
+ ---
232
+
233
+ ### 3.3) Operator methods
234
+ ...
235
+
236
+ ---
237
+
238
+ ### 3.3) Remote call methods
239
+ ...
240
+
241
+ ---
242
+
243
+ ## 4) Behaviours
244
+
245
+ ---
246
+
247
+ ### 4.1) Delegation behaviour
248
+ ...
249
+
250
+ ---
251
+
252
+ ### 4.2) Persistent operator behaviour
253
+ ...
254
+
255
+ ---
256
+
257
+ ### 4.3) Operator behaviour
258
+ ...
259
+
260
+ ---
261
+
262
+ ### 4.4) Remote call behaviour
263
+ ...
264
+
265
+ ---
266
+
267
+ ## 4) TODO
268
+
269
+ 1. Finish "Methods" and "Behaviours" documentation;
270
+ 2. Allow changing the HTTP verb for a specific connection;
271
+ 3. FinderMethods specs;
272
+ 4. serialization_specs to test the json options for nested classes;
273
+ 5. model_schema_specs;
274
+ 6. Cache.
@@ -8,7 +8,7 @@ module SmoothOperator
8
8
 
9
9
  attr_reader :meta_data, :internal_array, :table_name, :object_class
10
10
 
11
- def_delegators :internal_array, :length, :<<
11
+ def_delegators :internal_array, :length, :<<, :[]
12
12
 
13
13
  def initialize(attributes, table_name, object_class)
14
14
  _attributes = attributes.dup
@@ -12,7 +12,7 @@ module SmoothOperator
12
12
  relative_path = '' if relative_path == :all
13
13
 
14
14
  get(relative_path, data, options).tap do |remote_call|
15
- remote_call.object = build_object(remote_call.parsed_response, options)
15
+ remote_call.object = build_object(remote_call.parsed_response, options) if remote_call.success?
16
16
  end
17
17
  end
18
18
 
@@ -39,8 +39,6 @@ module SmoothOperator
39
39
  case object
40
40
  when String
41
41
  object.to_s == ''
42
- when Array
43
- object.empty?
44
42
  else
45
43
  object.nil?
46
44
  end
@@ -28,7 +28,7 @@ module SmoothOperator
28
28
  attr_writer :table_name
29
29
 
30
30
  def table_name
31
- @table_name ||= self.model_name.to_s.downcase.pluralize
31
+ @table_name ||= self.model_name.to_s.underscore.pluralize
32
32
  end
33
33
 
34
34
  def schema(structure)
@@ -49,19 +49,23 @@ module SmoothOperator
49
49
  if defined? ActiveModel
50
50
  rails_model_name_method
51
51
  else
52
- name.split('::').last.underscore.capitalize
52
+ @_model_name_namespace ||= name.split('::').last.underscore.capitalize
53
53
  end
54
54
  end
55
55
 
56
+ def model_name=(name)
57
+ @_model_name_namespace = name
58
+ end
56
59
 
60
+
57
61
  protected ############## PROTECTED #############
58
62
 
59
63
  def rails_model_name_method
60
64
  @_model_name ||= begin
61
- namespace = self.parents.detect do |n|
65
+ @_model_name_namespace ||= self.parents.detect do |n|
62
66
  n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
63
67
  end
64
- ActiveModel::Name.new(self, namespace)
68
+ ActiveModel::Name.new(self, @_model_name_namespace)
65
69
  end
66
70
  end
67
71
 
@@ -29,7 +29,7 @@ module SmoothOperator
29
29
  url, timeout = (options[:endpoint] || self.endpoint), (options[:timeout] || self.timeout)
30
30
 
31
31
  Faraday.new(url: url) do |builder|
32
- builder.options.params_encoder = Faraday::NestedParamsEncoder # to properly encode arrays
32
+ # builder.options.params_encoder = Faraday::NestedParamsEncoder # to properly encode arrays
33
33
  builder.options.timeout = timeout unless Helpers.blank?(timeout)
34
34
  builder.request :url_encoded
35
35
  builder.adapter adapter
@@ -38,7 +38,7 @@ module SmoothOperator
38
38
 
39
39
 
40
40
  protected ################ PROTECTED ################
41
-
41
+ #COMPLEX
42
42
  def make_the_call(http_verb, relative_path = '', data = {}, options = {})
43
43
  params, body = strip_params(http_verb, data)
44
44
 
@@ -58,7 +58,8 @@ module SmoothOperator
58
58
  end
59
59
 
60
60
  RemoteCall::Base.new(response)
61
- rescue Faraday::ConnectionFailed
61
+ # rescue Faraday::ConnectionFailed
62
+ rescue Faraday::Error::ConnectionFailed
62
63
  RemoteCall::ConnectionFailed.new
63
64
  end
64
65
  end
@@ -1,5 +1,5 @@
1
1
  module SmoothOperator
2
-
2
+
3
3
  module Persistence
4
4
 
5
5
  def self.included(base)
@@ -15,13 +15,13 @@ module SmoothOperator
15
15
  [:create, :save, :destroy].each do |method|
16
16
  define_method("#{method}_http_verb=") { |http_verb| methods_http_verbs[method] = http_verb }
17
17
  end
18
-
18
+
19
19
  def create(attributes = nil, relative_path = nil, data = {}, options = {})
20
- if attributes.is_a?(Array)
21
- attributes.map { |array_entry| create(array_entry, relative_path, data, options) }
22
- else
20
+ # if attributes.is_a?(Array)
21
+ # attributes.map { |array_entry| create(array_entry, relative_path, data, options) }
22
+ # else
23
23
  new(attributes).tap { |object| object.save(relative_path, data, options) }
24
- end
24
+ # end
25
25
  end
26
26
 
27
27
  end
@@ -29,16 +29,14 @@ module SmoothOperator
29
29
 
30
30
  def new_record?
31
31
  return @new_record if defined?(@new_record)
32
-
32
+
33
33
  @new_record = Helpers.blank?(get_internal_data("id"))
34
34
  end
35
-
35
+
36
36
  def destroyed?
37
- @destroyed || false
38
- end
37
+ return @destroyed if defined?(@destroyed)
39
38
 
40
- def last_remote_call
41
- @last_remote_call
39
+ @destroyed = false
42
40
  end
43
41
 
44
42
  def persisted?
@@ -56,8 +54,8 @@ module SmoothOperator
56
54
  def destroy(relative_path = nil, data = {}, options = {})
57
55
  return false unless persisted?
58
56
 
59
- relative_path = "#{id}" if Helpers.blank?(relative_path)
60
-
57
+ relative_path = id.to_s if Helpers.blank?(relative_path)
58
+
61
59
  success = make_remote_call(self.class.methods_http_verbs[:destroy], relative_path, data, options)
62
60
 
63
61
  @destroyed = true if success
@@ -81,7 +79,7 @@ module SmoothOperator
81
79
  end
82
80
 
83
81
  def update(relative_path, data, options)
84
- relative_path = "#{id}" if Helpers.blank?(relative_path)
82
+ relative_path = id.to_s if Helpers.blank?(relative_path)
85
83
 
86
84
  make_remote_call(self.class.methods_http_verbs[:save], relative_path, data, options)
87
85
  end
@@ -95,7 +93,7 @@ module SmoothOperator
95
93
  @last_remote_call = self.class.send(http_verb, relative_path, data, options)
96
94
 
97
95
  returning_data = @last_remote_call.parsed_response
98
-
96
+
99
97
  if !@last_remote_call.error? && returning_data.is_a?(Hash)
100
98
  assign_attributes returning_data.include?(model_name) ? returning_data[model_name] : returning_data
101
99
  end
@@ -105,7 +103,7 @@ module SmoothOperator
105
103
 
106
104
  def build_remote_call_args(http_verb, data, options)
107
105
  return [data, options] if http_verb == :delete
108
-
106
+
109
107
  hash = serializable_hash(options[:serializable_options]).dup
110
108
  hash.delete('id')
111
109
 
@@ -113,5 +111,5 @@ module SmoothOperator
113
111
  end
114
112
 
115
113
  end
116
-
114
+
117
115
  end
@@ -14,6 +14,8 @@ module SmoothOperator
14
14
 
15
15
  def_delegators :response, :success?, :headers, :body
16
16
 
17
+ alias :ok? :success?
18
+
17
19
  def initialize(response, object_class = nil)
18
20
  @response, @object_class = response, object_class
19
21
  end
@@ -53,7 +55,7 @@ module SmoothOperator
53
55
 
54
56
  class ConnectionFailed
55
57
 
56
- attr_reader :data, :object, :objects, :status, :headers, :body
58
+ attr_reader :data, :object, :objects, :parsed_response, :status, :headers, :body
57
59
 
58
60
  def http_status; 0; end
59
61
 
@@ -67,4 +69,4 @@ module SmoothOperator
67
69
 
68
70
  end
69
71
 
70
- end
72
+ end
@@ -6,7 +6,8 @@ module SmoothOperator
6
6
  Helpers.symbolyze_keys serializable_hash(options)
7
7
  end
8
8
 
9
- alias :attributes :to_hash
9
+ # alias :attributes :to_hash
10
+ def attributes; to_hash; end
10
11
 
11
12
  def to_json(options = nil)
12
13
  require 'json' unless defined? JSON
@@ -18,9 +19,25 @@ module SmoothOperator
18
19
  send(attribute)
19
20
  end
20
21
 
21
- def serializable_hash(options = nil) # Code inspired in ActiveSupport#serializable_hash
22
+ def serializable_hash(options = nil)
23
+ hash = {}
22
24
  options ||= {}
23
25
 
26
+ attribute_names(options).each do |attribute_name|
27
+ hash[attribute_name] = read_attribute_for_hashing(attribute_name, options)
28
+ end
29
+
30
+ method_names(options).each do |method_name|
31
+ hash[method_name.to_s] = send(method_name)
32
+ end
33
+
34
+ hash
35
+ end
36
+
37
+
38
+ protected ##################### PROTECTED ###################
39
+ #COMPLEX
40
+ def attribute_names(options)
24
41
  attribute_names = internal_data.keys.sort
25
42
 
26
43
  if only = options[:only]
@@ -29,18 +46,12 @@ module SmoothOperator
29
46
  attribute_names -= [*except].map(&:to_s)
30
47
  end
31
48
 
32
- method_names = [*options[:methods]].select { |n| respond_to?(n) }
33
-
34
- hash = {}
35
-
36
- attribute_names.each { |attribute_name| hash[attribute_name] = read_attribute_for_hashing(attribute_name, options) }
37
- method_names.each { |method_name| hash[method_name.to_s] = send(method_name) }
38
-
39
- hash
49
+ attribute_names
40
50
  end
41
51
 
42
-
43
- protected ##################### PROTECTED ###################
52
+ def method_names(options)
53
+ [*options[:methods]].select { |n| respond_to?(n) }
54
+ end
44
55
 
45
56
  def read_attribute_for_hashing(attribute_name, options)
46
57
  object = read_attribute_for_serialization(attribute_name)
@@ -11,22 +11,22 @@ module SmoothOperator
11
11
  value.to_s
12
12
 
13
13
  when :int, :integer, Integer, Fixnum
14
- TypeConverter.to_int(value)
14
+ to_int(value)
15
15
 
16
16
  when :date, Date
17
- TypeConverter.to_date(value)
17
+ to_date(value)
18
18
 
19
19
  when :float, Float
20
- TypeConverter.to_float(value)
20
+ to_float(value)
21
21
 
22
22
  when :bool, :boolean
23
- TypeConverter.to_boolean(value)
23
+ to_boolean(value)
24
24
 
25
25
  when :datetime, :date_time, DateTime
26
- TypeConverter.to_datetime(value)
26
+ to_datetime(value)
27
27
 
28
28
  else
29
- value
29
+ Helpers.duplicate(value)
30
30
  end
31
31
  end
32
32
 
@@ -1,3 +1,3 @@
1
1
  module SmoothOperator
2
- VERSION = "1.8.0"
2
+ VERSION = "1.8.3"
3
3
  end
@@ -24,5 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
 
26
26
  spec.add_dependency "json"
27
- spec.add_dependency 'faraday', '> 0.9.0.rc5'
27
+ # spec.add_dependency 'faraday', '> 0.9.0.rc5'
28
+ spec.add_dependency 'faraday', '~> 0.8.1'
28
29
  end
@@ -1,11 +1,56 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe SmoothOperator::FinderMethods do
4
- subject { User }
4
+ subject { UserWithAddressAndPosts::Son }
5
5
 
6
+ describe ".all" do
7
+ xit "should can .find(:all) with the same arguments that it as received" do
8
+
9
+ end
10
+ end
6
11
 
7
12
  describe ".find" do
8
-
13
+ context "when the server returns a single hash" do
14
+ it "it should return a RemoteCall instance with a subject's class instance populated with the returned hash" do
15
+ remote_call = subject.find(5)
16
+ user = remote_call.object
17
+
18
+ expect(user).to be_instance_of(subject)
19
+ expect(user.attributes).to eq(attributes_for(:user_with_address_and_posts))
20
+ end
21
+ end
22
+
23
+ context "when the server returns an array" do
24
+ it "it should return a RemoteCall instance an array that contains a subject's class instance, one for every array's entry" do
25
+ remote_call = subject.find(:all)
26
+ users = remote_call.objects
27
+
28
+ expect(users).to be_instance_of(Array)
29
+ expect(users[0]).to be_instance_of(subject)
30
+ expect(users[1]).to be_instance_of(subject)
31
+ end
32
+
33
+ it "if any of the array entries is not a hash, it shall not be converted or alteread" do
34
+ remote_call = subject.find('misc_array')
35
+ users = remote_call.objects
36
+
37
+ expect(users).to be_instance_of(Array)
38
+ expect(users[0]).to be_instance_of(subject)
39
+ expect(users[1]).to be(2)
40
+ end
41
+ end
42
+
43
+ context "when the server returns a hash with a key (equal to subject's call.table_name) containing an array" do
44
+ it "it should return a RemoteCall instance an instance of ArrayWithMetaData" do
45
+ remote_call = subject.find('with_metadata')
46
+ users = remote_call.data
47
+
48
+ expect(users).to be_instance_of(SmoothOperator::ArrayWithMetaData)
49
+ expect(users.page).to be(1)
50
+ expect(users.total).to be(6)
51
+ users.each { |user| expect(user).to be_instance_of(subject) }
52
+ end
53
+ end
9
54
  end
10
55
 
11
56
  end
@@ -24,6 +24,7 @@ shared_examples_for "persistent remote call" do
24
24
 
25
25
  it "it should return true" do
26
26
  execute_method
27
+ expect(subject.last_remote_call.success?).to be true
27
28
  expect(subject.last_remote_call.status).to be true
28
29
  end
29
30
 
@@ -40,6 +41,7 @@ shared_examples_for "persistent remote call" do
40
41
 
41
42
  it "it should return false" do
42
43
  execute_method
44
+ expect(subject.last_remote_call.failure?).to be true
43
45
  expect(subject.last_remote_call.status).to be false
44
46
  end
45
47
 
@@ -56,6 +58,7 @@ shared_examples_for "persistent remote call" do
56
58
 
57
59
  it "it should return nil" do
58
60
  execute_method
61
+ expect(subject.last_remote_call.error?).to be true
59
62
  expect(subject.last_remote_call.status).to be_nil
60
63
  end
61
64
 
@@ -89,10 +92,10 @@ describe SmoothOperator::Persistence, helpers: :persistence do
89
92
 
90
93
  describe ".create" do
91
94
 
95
+ subject { created_subject }
92
96
  let(:method_arguments) { [] }
93
97
 
94
98
  context "when attributes DON'T contain an ID" do
95
- subject { created_subject }
96
99
  let(:method_to_execute) { :create_without_id }
97
100
  let(:persistence_state) { { 200 => true, 422 => false, 500 => false } }
98
101
 
@@ -107,7 +110,6 @@ describe SmoothOperator::Persistence, helpers: :persistence do
107
110
  end
108
111
 
109
112
  context "when attributes contain an ID" do
110
- subject { created_subject }
111
113
  let(:method_to_execute) { :create_with_id }
112
114
  let(:persistence_state) { { 200 => true, 422 => true, 500 => true } }
113
115
 
@@ -0,0 +1,98 @@
1
+ require "spec_helper"
2
+
3
+ describe SmoothOperator::RemoteCall do
4
+ subject { User }
5
+
6
+ describe "#success?" do
7
+ context "when the server response has a http code in the 200 range" do
8
+ it "should return true" do
9
+ end
10
+ end
11
+
12
+ context "when the server response has a http code NOT in the 200 range" do
13
+ it "should return false" do
14
+ end
15
+ end
16
+
17
+ context "when the server response connection fails" do
18
+ it "should return false" do
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "#failure?" do
24
+ context "when the server response has a http code in the 400 range" do
25
+ it "should return true" do
26
+ end
27
+ end
28
+
29
+ context "when the server response has a http code NOT in the 400 range" do
30
+ it "should return false" do
31
+ end
32
+ end
33
+
34
+ context "when the server response connection fails" do
35
+ it "should return false" do
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#error?" do
41
+ context "when the server response has a http code in the 500 range" do
42
+ it "should return true" do
43
+ end
44
+ end
45
+
46
+ context "when the server response has a http code NOT in the 500 range" do
47
+ it "should return false" do
48
+ end
49
+ end
50
+
51
+ context "when the server response connection fails" do
52
+ it "should return true" do
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#parsed_response" do
58
+ context "when the server response's body contains valid json data" do
59
+ it "should return the parsed result of that data" do
60
+ end
61
+ end
62
+
63
+ context "when the server response's body does not contains valid json data" do
64
+ it "should return nil" do
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#status" do
70
+ context "when the #error? returns true" do
71
+ it "should return nil" do
72
+ end
73
+ end
74
+
75
+ context "when the #error? returns false and #success? returns true" do
76
+ it "should return true" do
77
+ end
78
+ end
79
+
80
+ context "when the #error? returns false and #success? returns false" do
81
+ it "should return false" do
82
+ end
83
+ end
84
+ end
85
+
86
+ describe "#http_status" do
87
+ context "when a server connection is established" do
88
+ it "should return the server's http response code" do
89
+ end
90
+ end
91
+
92
+ context "when a server connection fails" do
93
+ it "should return 0" do
94
+ end
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,42 @@
1
+ require "spec_helper"
2
+
3
+ describe SmoothOperator::Validations do
4
+ subject { User.new(attributes_for(:user)) }
5
+
6
+ describe "#valid?" do
7
+ context "when executing a persistence method, and the server response has a hash with the key 'errors'" do
8
+ before { subject.save('send_error') }
9
+
10
+ it "it should return false" do
11
+ expect(subject.valid?).to be false
12
+ end
13
+ end
14
+
15
+ context "when executing a persistence method, and the server response does NOT have a hash with the key 'errors'" do
16
+ before { subject.save }
17
+
18
+ it "it should return true" do
19
+ expect(subject.valid?).to be true
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#invalid?" do
25
+ context "when executing a persistence method, and the server response has a hash with the key 'errors'" do
26
+ before { subject.save('send_error') }
27
+
28
+ it "it should return true" do
29
+ expect(subject.invalid?).to be true
30
+ end
31
+ end
32
+
33
+ context "when executing a persistence method, and the server response does NOT have a hash with the key 'errors'" do
34
+ before { subject.save }
35
+
36
+ it "it should return false" do
37
+ expect(subject.invalid?).to be false
38
+ end
39
+ end
40
+ end
41
+
42
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,11 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.start do
4
+ root('lib/')
5
+ project_name('SmoothOperator')
6
+ coverage_dir('../tmp/coverage/')
7
+ end
8
+
1
9
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
10
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
11
 
@@ -25,7 +25,16 @@ class TestServer < Sinatra::Base
25
25
 
26
26
 
27
27
  get '/users' do
28
- json [{ id: 1 }, { id: 2 }]
28
+ users = [FactoryGirl.attributes_for(:user_with_address_and_posts), FactoryGirl.attributes_for(:user_with_address_and_posts)]
29
+
30
+ users[0][:id] = 1
31
+ users[1][:id] = 2
32
+
33
+ json users
34
+ end
35
+
36
+ get '/users/misc_array' do
37
+ json [FactoryGirl.attributes_for(:user_with_address_and_posts), 2]
29
38
  end
30
39
 
31
40
  get '/users/with_metadata' do
@@ -37,6 +46,11 @@ class TestServer < Sinatra::Base
37
46
  json FactoryGirl.attributes_for(:user_with_address_and_posts)
38
47
  end
39
48
 
49
+ put '/users/send_error' do
50
+ data_with_error = { id: 1, errors: { first_name: ["can't be blank"] } }
51
+ json data_with_error
52
+ end
53
+
40
54
 
41
55
  post '/users' do
42
56
  common_response
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smooth_operator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - João Gonçalves
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-25 00:00:00.000000000 Z
11
+ date: 2014-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: faraday
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>'
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: 0.9.0.rc5
47
+ version: 0.8.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ! '>'
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: 0.9.0.rc5
54
+ version: 0.8.1
55
55
  description: ActiveResource alternative
56
56
  email:
57
57
  - goncalves.joao@gmail.com
@@ -91,7 +91,9 @@ files:
91
91
  - spec/smooth_operator/model_schema_spec.rb
92
92
  - spec/smooth_operator/operator_spec.rb
93
93
  - spec/smooth_operator/persistence_spec.rb
94
+ - spec/smooth_operator/remote_call_spec.rb
94
95
  - spec/smooth_operator/serialization_spec.rb
96
+ - spec/smooth_operator/validations_spec.rb
95
97
  - spec/spec_helper.rb
96
98
  - spec/support/helpers/persistence_helper.rb
97
99
  - spec/support/localhost_server.rb
@@ -133,7 +135,9 @@ test_files:
133
135
  - spec/smooth_operator/model_schema_spec.rb
134
136
  - spec/smooth_operator/operator_spec.rb
135
137
  - spec/smooth_operator/persistence_spec.rb
138
+ - spec/smooth_operator/remote_call_spec.rb
136
139
  - spec/smooth_operator/serialization_spec.rb
140
+ - spec/smooth_operator/validations_spec.rb
137
141
  - spec/spec_helper.rb
138
142
  - spec/support/helpers/persistence_helper.rb
139
143
  - spec/support/localhost_server.rb