smooth_operator 1.8.0 → 1.8.3

Sign up to get free protection for your applications and to get access to all the features.
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