api-resource 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23cbaeb15eab2892df46438827daafa4fab93168
4
- data.tar.gz: 2a6bc12c082d02bd7938d7b57091a08afc97e05b
3
+ metadata.gz: 7fb25fa5e1a25eec2eca37948e5c8638d2ac17b2
4
+ data.tar.gz: 112ad65c7f8b3d611ac2e8e1a5781adc82736efa
5
5
  SHA512:
6
- metadata.gz: 005bb30e8ab91f0aaead583e085e4468e29a7b481705ca99de2de49a19b78402ecf722cf005b91169fe0c5b665cae9ae60447a7d8b22ae111b02b668620d9c51
7
- data.tar.gz: 3a8d3545b5d6ac2c4bc70ac1741d8359446686fafb762074880a27538dc7ee7ea34a30cd44ea7f14a9cf9d178bfd7247dde939a5d7e2dbd2f8605d0b22d736e0
6
+ metadata.gz: f4b7f563692b808b8120f3e88d5ca01b100601b354a869b9265fcdd84cf2b7661d8f2292b9950fb21bff0f06b9b16d804978e54e7966e80886ec629ae42f7edb
7
+ data.tar.gz: 7ebc0f1b6768180cac7fa13465e56d7acbfa20f70dc1a1d7bbc0ec6d94ea26403ba5063fd7c1e7de261f28da1a1f4b9cba1917cdb654b2cf9489151965672652
@@ -6,6 +6,7 @@ require 'active_model/model'
6
6
  require 'active_model/serializers/json'
7
7
  require 'active_support/core_ext/hash/indifferent_access'
8
8
  require 'active_support/core_ext/object/to_param'
9
+ require 'active_support/core_ext/module/remove_method'
9
10
 
10
11
  module ApiResource
11
12
 
@@ -40,7 +41,7 @@ module ApiResource
40
41
  end
41
42
 
42
43
  def self.resource_path
43
- @resource_path || name.to_s.tableize
44
+ @resource_path || name.to_s.tableize.split('/').last
44
45
  end
45
46
 
46
47
  def self.resource_path=(path)
@@ -148,20 +149,21 @@ module ApiResource
148
149
  # define method for associated embedded resource(s)
149
150
  if value.is_a?(Hash)
150
151
  meta, data = value['meta'], value['data'] || value
151
- elsif value.is_a?(Array)
152
- meta, data = nil, value
153
152
  else
154
- next
153
+ meta, data = nil, value
155
154
  end
155
+
156
156
  child_class = self.class.load_class((meta && meta['type']) || key)
157
- next unless child_class
158
- if data.is_a?(Hash)
159
- child_value = child_class.new(data)
160
- define_singleton_method(key) { child_value }
161
- elsif data.is_a?(Array)
162
- child_values = ResourceCollection.new(data, meta, child_class)
163
- define_singleton_method(key) { child_values }
164
- end
157
+ child_value = if child_class && data.is_a?(Hash)
158
+ child_class.new(data)
159
+ elsif child_class && data.is_a?(Array)
160
+ ResourceCollection.new(data, meta, child_class)
161
+ else
162
+ data
163
+ end
164
+
165
+ self.class.remove_possible_method(key)
166
+ define_singleton_method(key) { child_value }
165
167
  end
166
168
  end
167
169
  end
@@ -177,7 +179,7 @@ module ApiResource
177
179
 
178
180
  def self.with_parent_resource(parent_resource_id, parent_resource_name)
179
181
  parent_resource_name = parent_resource_name.pluralize
180
- child_resource_path = resource_path
182
+ child_resource_path = resource_path
181
183
  Class.new(self) do
182
184
  self.resource_path = build_url(parent_resource_name, parent_resource_id, child_resource_path)
183
185
  end
@@ -189,6 +191,7 @@ module ApiResource
189
191
  end
190
192
 
191
193
  def self.load_class(tableized_class)
194
+ tableized_class = name.to_s.tableize.split('/')[0...-1].push(tableized_class).join('/')
192
195
  klass = tableized_class && tableized_class.to_s.singularize.classify.constantize rescue nil
193
196
  klass if klass && klass < ApiResource::Resource
194
197
  end
@@ -1,3 +1,3 @@
1
1
  module ApiResource
2
- VERSION = '0.5.0'
2
+ VERSION = '0.5.1'
3
3
  end
@@ -1,19 +1,22 @@
1
1
  RSpec.describe ApiResource::Resource do
2
+ module BlogApi
3
+ class Resource < ApiResource::Resource
4
+ self.base_url = 'http://api.example.com'
5
+ end
2
6
 
3
- class BlogResource < ApiResource::Resource
4
- self.base_url = 'http://api.example.com'
5
- end
6
-
7
- class Category < BlogResource
8
- attr_accessor :id, :name
9
- end
7
+ class Category < Resource
8
+ attr_accessor :id, :name
9
+ end
10
10
 
11
- class Blog < BlogResource
12
- attr_accessor :id, :title
13
- end
11
+ class Blog < Resource
12
+ attr_accessor :id, :title
13
+ def do_stuff_method
14
+ end
15
+ end
14
16
 
15
- class Tag < BlogResource
16
- attr_accessor :id, :name
17
+ class Tag < Resource
18
+ attr_accessor :id, :name
19
+ end
17
20
  end
18
21
 
19
22
  def check_returned_array(type, expected, actual)
@@ -24,11 +27,11 @@ RSpec.describe ApiResource::Resource do
24
27
 
25
28
  def check_returned_object(type, expected, actual, *except)
26
29
  expect(actual).to be_a(type)
27
- expect(actual.attributes).to match((expected[:data] || expected).except(*except))
30
+ expect(actual.try(:attributes) || actual).to match((expected[:data] || expected).except(*except))
28
31
  end
29
32
 
30
33
  def req(verb, path, resource, status=200, params=nil)
31
- stub_request(verb, "#{BlogResource.base_url}#{path}").
34
+ stub_request(verb, "#{BlogApi::Resource.base_url}#{path}").
32
35
  with(headers: { 'Accept' => 'application/json' }, body: params).
33
36
  to_return(status: status, body: resource.is_a?(String) || resource.blank? ? resource : resource.to_json)
34
37
  end
@@ -40,18 +43,18 @@ RSpec.describe ApiResource::Resource do
40
43
  end
41
44
 
42
45
  context '::all_pages' do
43
- it 'retreive all pages' do
46
+ it 'retrieves all pages' do
44
47
  expected_values = (1..223).map { |i| { id: i, title: "Hello #{i}" } }.each_slice(100).to_a
45
48
  expected_values.each_with_index do |objs, i|
46
49
  req(:get, "/blogs?page=#{i+1}&per_page=100", { data: objs, meta: { total_count: 223 } })
47
50
  end
48
51
 
49
52
  i = 1
50
- Blog.all_pages(per_page: 100) do |elts, page, per_page, total_count|
53
+ BlogApi::Blog.all_pages(per_page: 100) do |elts, page, per_page, total_count|
51
54
  expect(total_count).to eq(223)
52
55
  expect(page).to eq(i)
53
56
  expect(per_page).to eq(100)
54
- check_returned_array(Blog, expected_values[i-1], elts)
57
+ check_returned_array(BlogApi::Blog, expected_values[i-1], elts)
55
58
  i += 1
56
59
  false
57
60
  end
@@ -63,8 +66,8 @@ RSpec.describe ApiResource::Resource do
63
66
  def check_found_resource(expected_value)
64
67
  resource_id = 3
65
68
  req(:get, "/blogs/#{resource_id}", expected_value)
66
- result = Blog.find(resource_id)
67
- check_returned_object(Blog, expected_value, result)
69
+ result = BlogApi::Blog.find(resource_id)
70
+ check_returned_object(BlogApi::Blog, expected_value, result)
68
71
  end
69
72
 
70
73
  it 'creates resource with data rooted json' do
@@ -79,8 +82,8 @@ RSpec.describe ApiResource::Resource do
79
82
 
80
83
  it 'fetches all resources' do
81
84
  req(:get, '/blogs', @expected_resources)
82
- result = Blog.all
83
- check_returned_array(Blog, @expected_resources, result)
85
+ result = BlogApi::Blog.all
86
+ check_returned_array(BlogApi::Blog, @expected_resources, result)
84
87
  end
85
88
  end
86
89
 
@@ -88,24 +91,24 @@ RSpec.describe ApiResource::Resource do
88
91
 
89
92
  it 'fetches resourced filtered by query string with GET' do
90
93
  req(:get, '/blogs?title=hello+world&tags%5B%5D=hello&tags%5B%5D=first&tags%5B%5D=greeting', @expected_resources)
91
- result = Blog.where(title: 'hello world', tags: ['hello', 'first', 'greeting'])
92
- check_returned_array(Blog, @expected_resources, result)
94
+ result = BlogApi::Blog.where(title: 'hello world', tags: ['hello', 'first', 'greeting'])
95
+ check_returned_array(BlogApi::Blog, @expected_resources, result)
93
96
  end
94
97
 
95
98
  it 'fetches resources filtered by query string with POST' do
96
- stub_request(:post, "#{Blog.base_url}/blogs").
99
+ stub_request(:post, "#{BlogApi::Blog.base_url}/blogs").
97
100
  with(headers: { 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded' },
98
101
  body: 'title=hello%20world&tags[]=hello&tags[]=first&tags[]=greeting').
99
102
  to_return(status: 200, body: @expected_resources.to_json)
100
103
 
101
- result = Blog.where({ title: 'hello world', tags: ['hello', 'first', 'greeting'] }, :post)
102
- check_returned_array(Blog, @expected_resources, result)
104
+ result = BlogApi::Blog.where({ title: 'hello world', tags: ['hello', 'first', 'greeting'] }, :post)
105
+ check_returned_array(BlogApi::Blog, @expected_resources, result)
103
106
  end
104
107
 
105
108
  it 'not add query string for empty array parameter values on GET' do
106
109
  req(:get, '/blogs', @expected_resources)
107
- result = Blog.where({ tags: [] })
108
- check_returned_array(Blog, @expected_resources, result)
110
+ result = BlogApi::Blog.where({ tags: [] })
111
+ check_returned_array(BlogApi::Blog, @expected_resources, result)
109
112
  end
110
113
  end
111
114
 
@@ -114,8 +117,8 @@ RSpec.describe ApiResource::Resource do
114
117
  it 'fetches resource nested with parent resource' do
115
118
  resource_id = 3
116
119
  req(:get, "/tags/#{resource_id}/blogs", @expected_resources)
117
- result = Blog.by_tag(resource_id).all
118
- check_returned_array(Blog, @expected_resources, result)
120
+ result = BlogApi::Blog.by_tag(resource_id).all
121
+ check_returned_array(BlogApi::Blog, @expected_resources, result)
119
122
  end
120
123
  end
121
124
 
@@ -130,10 +133,10 @@ RSpec.describe ApiResource::Resource do
130
133
  resource_values = @blog.merge(data: { relation_name => relation_values })
131
134
  resource_id = 3
132
135
  req(:get, "/blogs/#{resource_id}", resource_values)
133
- blog = Blog.find(resource_id)
134
- check_returned_object(Blog, resource_values, blog, relation_name)
136
+ blog = BlogApi::Blog.find(resource_id)
137
+ check_returned_object(BlogApi::Blog, resource_values, blog, relation_name)
135
138
  expect(blog).to respond_to(relation_name)
136
- check_returned_array(Tag, relation_values, blog.send(relation_name))
139
+ check_returned_array(BlogApi::Tag, relation_values, blog.send(relation_name))
137
140
  yield blog if block_given?
138
141
  end
139
142
 
@@ -155,25 +158,38 @@ RSpec.describe ApiResource::Resource do
155
158
  end
156
159
  end
157
160
  context 'has_one' do
158
- def check_has_one(relation_name, relation_values)
159
- resource_values = @blog.merge(data: { relation_name => relation_values })
160
- resource_id = 3
161
- req(:get, "/blogs/#{resource_id}", resource_values)
162
- blog = Blog.find(resource_id)
163
- check_returned_object(Blog, resource_values, blog, relation_name)
161
+ let(:raw_data) { { 'foo' => 'bar', 'baz' => 3 } }
162
+
163
+ def check_has_one(relation_name, relation_values, relation_type=BlogApi::Category)
164
+ @blog[:data].merge!(relation_name => relation_values)
165
+ resource_id = 3
166
+ stub = req(:get, "/blogs/#{resource_id}", @blog)
167
+ blog = BlogApi::Blog.find(resource_id)
168
+ check_returned_object(BlogApi::Blog, @blog, blog, relation_name)
164
169
  expect(blog).to respond_to(relation_name)
165
- check_returned_object(Category, relation_values, blog.send(relation_name))
170
+ check_returned_object(relation_type, relation_values, blog.send(relation_name))
171
+ expect(stub).to have_been_requested
166
172
  end
167
173
 
168
174
  it 'gets data rooted inlined json' do
169
175
  check_has_one(:category, data: @category_data)
170
176
  end
177
+
171
178
  it 'gets un-rooted inlined json' do
172
179
  check_has_one(:category, @category_data)
173
180
  end
181
+
174
182
  it 'override type from meta' do
175
183
  check_has_one(:main_category, data: { id: 33, name: 'Hobbies' }, meta: { type: :category })
176
184
  end
185
+
186
+ it 'creates method for raw types' do
187
+ check_has_one(:raw_attr, raw_data, Hash)
188
+ end
189
+
190
+ it 'replaces method with raw types' do
191
+ check_has_one(:do_stuff_method, raw_data, Hash)
192
+ end
177
193
  end
178
194
  end
179
195
 
@@ -187,19 +203,19 @@ RSpec.describe ApiResource::Resource do
187
203
 
188
204
  context '#save!' do
189
205
  it 'POSTs data when id is nil' do
190
- blog = Blog.new(title: 'hello')
206
+ blog = BlogApi::Blog.new(title: 'hello')
191
207
  expect(blog.id).to be_nil
192
208
  expected_value = { data: { id: 32, title: 'hello' } }
193
209
 
194
210
  stub = req(:post, '/blogs', expected_value, 201, { title: 'hello' })
195
211
  returned = blog.save!
196
212
  expect(returned).to eq(blog)
197
- check_returned_object(Blog, expected_value, blog)
213
+ check_returned_object(BlogApi::Blog, expected_value, blog)
198
214
  expect(stub).to have_been_requested
199
215
  end
200
216
  it 'PUTs data when id is not nil' do
201
217
  blog_id = 525
202
- blog = Blog.new(id: blog_id, title: 'hello')
218
+ blog = BlogApi::Blog.new(id: blog_id, title: 'hello')
203
219
 
204
220
  stub = req(:put, '/blogs', nil, 204, id: blog_id.to_s, title: 'hello')
205
221
  returned = blog.save!
@@ -211,14 +227,14 @@ RSpec.describe ApiResource::Resource do
211
227
 
212
228
  context '#destroy!' do
213
229
  it 'DELETEs data when id is not nil' do
214
- blog = Blog.new(id: 323, title: 'hello')
230
+ blog = BlogApi::Blog.new(id: 323, title: 'hello')
215
231
  stub = req(:delete, '/blogs', '', 204)
216
232
  returned = blog.destroy!
217
233
  expect(returned).to eq(blog)
218
234
  expect(stub).to have_been_requested
219
235
  end
220
236
  it 'not DELETE data when id is nil' do
221
- blog = Blog.new(id: nil, title: 'hello')
237
+ blog = BlogApi::Blog.new(id: nil, title: 'hello')
222
238
  stub = req(:delete, '/blogs', '', 204)
223
239
  returned = blog.destroy!
224
240
  expect(returned).to eq(blog)
@@ -228,13 +244,13 @@ RSpec.describe ApiResource::Resource do
228
244
 
229
245
  context '#submit!' do
230
246
 
231
- class SignUp < BlogResource
247
+ class SignUp < BlogApi::Resource
232
248
  self.resource_path = 'sign_up'
233
249
  attr_accessor :email, :password, :password_confirmation, :name
234
250
  validates :name, presence: true
235
251
  end
236
252
 
237
- class User < BlogResource
253
+ class User < BlogApi::Resource
238
254
  attr_accessor :id, :email, :name
239
255
  end
240
256
 
@@ -268,8 +284,9 @@ RSpec.describe ApiResource::Resource do
268
284
  expect(stub).to_not have_been_requested
269
285
  end
270
286
  end
287
+
271
288
  context '::filter_submit_params' do
272
- class Purchase < BlogResource
289
+ class Purchase < BlogApi::Resource
273
290
  filter_submitted_attributes do |attrs|
274
291
  address_attrs = [:name, :street, :zip_code]
275
292
  attrs.except(*address_attrs).merge(address: attrs.slice(*address_attrs))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chaker Nakhli