api-resource 0.5.0 → 0.5.1

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,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