api-resource 0.2.0 → 0.3.0
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 +4 -4
- data/lib/api-resource/resource.rb +38 -21
- data/lib/api-resource/version.rb +1 -1
- data/spec/resource_spec.rb +101 -64
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f52282f574b5922a5f27ee524075ea79307b3cf
|
4
|
+
data.tar.gz: e713e470bb8e7a4f267c25ca94caf113adcf3ffb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a23bdd034f812966a75a8c36ef5fbd5b6496c52c7f3e95971c3a9b01e16742b77acf2d8054ed262f04d3b1b8b8f3db90d12279f80538714c3f3e88e5fe9d8da
|
7
|
+
data.tar.gz: 22ca88e67fb933867c2fc09076b0ef31cf24e2ecab4f1595b6169518952f34b3519ff8908d6912e10445b2629ba7c9acdbaebeec883dc138885a39e3c46cb265
|
@@ -7,7 +7,6 @@ require 'active_support/core_ext/object/to_param'
|
|
7
7
|
|
8
8
|
module ApiResource
|
9
9
|
class Resource
|
10
|
-
|
11
10
|
include ActiveModel::Model
|
12
11
|
include ActiveModel::Serializers::JSON
|
13
12
|
|
@@ -34,19 +33,21 @@ module ApiResource
|
|
34
33
|
|
35
34
|
def self.find(id)
|
36
35
|
result = client(:get, {}, resource_name, id)
|
37
|
-
|
36
|
+
json = JSON.parse(result)
|
37
|
+
self.new(json['data'])
|
38
38
|
end
|
39
39
|
|
40
40
|
def self.all
|
41
41
|
result = client(:get, {}, resource_name)
|
42
|
-
|
43
|
-
|
42
|
+
json = JSON.parse(result)
|
43
|
+
ResourceCollection.new(json['data'], json['meta'], self)
|
44
44
|
end
|
45
45
|
|
46
|
+
|
46
47
|
def self.where(options, verb=:get)
|
47
48
|
result = client(verb, *(verb==:get ? [{}, "#{resource_name}?#{options.to_param}"] : [options, resource_name]))
|
48
|
-
|
49
|
-
|
49
|
+
json = JSON.parse(result)
|
50
|
+
ResourceCollection.new(json['data'], json['meta'], self)
|
50
51
|
end
|
51
52
|
|
52
53
|
def attributes
|
@@ -60,15 +61,17 @@ module ApiResource
|
|
60
61
|
if respond_to? "#{key}="
|
61
62
|
send("#{key}=", value)
|
62
63
|
else
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
64
|
+
# check for embedded resource
|
65
|
+
next unless value.is_a?(Hash) && value['data']
|
66
|
+
child_class = self.class.load_class((value['meta'] && value['meta']['type']) || key)
|
67
|
+
next unless child_class
|
68
|
+
data = value['data']
|
69
|
+
if data.is_a?(Hash)
|
70
|
+
child_value = child_class.new(data)
|
71
|
+
define_singleton_method(key) { child_value }
|
72
|
+
elsif data.is_a?(Array)
|
73
|
+
child_values = ResourceCollection.new(data, value['meta'], child_class)
|
74
|
+
define_singleton_method(key) { child_values }
|
72
75
|
end
|
73
76
|
end
|
74
77
|
end
|
@@ -84,14 +87,15 @@ module ApiResource
|
|
84
87
|
end
|
85
88
|
end
|
86
89
|
|
87
|
-
def self.load_class(plural_resource_name)
|
88
|
-
plural_resource_name.to_s.singularize.classify.constantize rescue nil
|
89
|
-
end
|
90
|
-
|
91
90
|
def self.with_parent_resource(parent_resource_id, parent_resource_name)
|
92
91
|
result = client(:get, {}, parent_resource_name.pluralize, parent_resource_id, self.resource_name)
|
93
|
-
|
94
|
-
|
92
|
+
json = JSON.parse(result)
|
93
|
+
ResourceCollection.new(json['data'], json['meta'], self)
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.load_class(tableized_class)
|
97
|
+
klass = tableized_class && tableized_class.to_s.singularize.classify.constantize rescue nil
|
98
|
+
klass if klass < ApiResource::Resource
|
95
99
|
end
|
96
100
|
|
97
101
|
def self.client(verb, params, *paths)
|
@@ -111,5 +115,18 @@ module ApiResource
|
|
111
115
|
end
|
112
116
|
req.execute
|
113
117
|
end
|
118
|
+
|
119
|
+
class ResourceCollection
|
120
|
+
include Enumerable
|
121
|
+
|
122
|
+
def initialize(data, meta, klass)
|
123
|
+
meta.each { |k, v| self.class.class_eval { define_method(k) { v } } } if meta
|
124
|
+
@resources = data.map { |e| klass.new(e) }
|
125
|
+
end
|
126
|
+
|
127
|
+
def each(&block)
|
128
|
+
@resources.each(&block)
|
129
|
+
end
|
130
|
+
end
|
114
131
|
end
|
115
132
|
end
|
data/lib/api-resource/version.rb
CHANGED
data/spec/resource_spec.rb
CHANGED
@@ -16,94 +16,133 @@ RSpec.describe ApiResource::Resource do
|
|
16
16
|
attr_accessor :id, :name
|
17
17
|
end
|
18
18
|
|
19
|
+
def check_returned_array(type, expected, actual)
|
20
|
+
expect(actual).to be_a Enumerable
|
21
|
+
actual.each { |e| expect(e).to be_a type }
|
22
|
+
expect(actual.map { |e| e.attributes }).to match (expected[:data])
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_returned_object(type, expected, actual, *except)
|
26
|
+
expect(actual).to be_a(type)
|
27
|
+
expect(actual.attributes).to match(expected[:data].except(*except))
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
@expected_resources = { data: [{ id: 1257, title: 'Hello' },
|
32
|
+
{ id: 33, title: 'World' },
|
33
|
+
{ id: 38, title: 'Bonjour!' }] }
|
34
|
+
end
|
19
35
|
context '#find' do
|
36
|
+
|
20
37
|
it 'creates the resource when found' do
|
21
|
-
|
22
|
-
resource_id
|
38
|
+
expected_value = { data: { id: 1257, title: 'Hello' } }
|
39
|
+
resource_id = 3
|
23
40
|
stub_request(:get, "#{Blog.base_url}/blogs/#{resource_id}").
|
24
41
|
with(headers: { 'Accept' => 'application/json' }).
|
25
|
-
to_return(status: 200, body:
|
26
|
-
|
42
|
+
to_return(status: 200, body: expected_value.to_json)
|
27
43
|
result = Blog.find(resource_id)
|
28
|
-
|
29
|
-
expect(result.attributes).to match (resource_values)
|
44
|
+
check_returned_object(Blog, expected_value, result)
|
30
45
|
end
|
31
46
|
end
|
32
47
|
|
33
48
|
context '#all' do
|
34
|
-
it 'fetches all resourced' do
|
35
|
-
resource_values = [{ id: 1257, title: 'Hello' },
|
36
|
-
{ id: 33, title: 'World' },
|
37
|
-
{ id: 38, title: 'Bonjour!' }]
|
38
49
|
|
50
|
+
it 'fetches all resources' do
|
39
51
|
stub_request(:get, "#{Blog.base_url}/blogs").
|
40
52
|
with(headers: { 'Accept' => 'application/json' }).
|
41
|
-
to_return(status: 200, body:
|
53
|
+
to_return(status: 200, body: @expected_resources.to_json)
|
42
54
|
|
43
|
-
|
44
|
-
|
45
|
-
expect(blogs).to be_a Array
|
46
|
-
blogs.each { |e| expect(e).to be_a Blog }
|
47
|
-
expect(blogs.map { |e| e.attributes }).to match (resource_values)
|
55
|
+
result = Blog.all
|
56
|
+
check_returned_array(Blog, @expected_resources, result)
|
48
57
|
end
|
49
58
|
end
|
50
59
|
|
51
60
|
context '#where' do
|
52
|
-
|
53
|
-
@resource_values = [{ id: 1257, title: 'Hello' },
|
54
|
-
{ id: 33, title: 'World' },
|
55
|
-
{ id: 38, title: 'Bonjour!' }]
|
56
|
-
end
|
61
|
+
|
57
62
|
it 'fetches resourced filtered by query string with GET' do
|
58
63
|
stub_request(:get, "#{Blog.base_url}/blogs?title=hello+world&tags%5B%5D=hello&tags%5B%5D=first&tags%5B%5D=greeting").
|
59
64
|
with(headers: { 'Accept' => 'application/json' }).
|
60
|
-
to_return(status: 200, body: @
|
61
|
-
|
62
|
-
blogs = Blog.where(title: 'hello world', tags: ['hello', 'first', 'greeting'])
|
65
|
+
to_return(status: 200, body: @expected_resources.to_json)
|
63
66
|
|
64
|
-
|
65
|
-
|
66
|
-
expect(blogs.map { |e| e.attributes }).to match (@resource_values)
|
67
|
+
result = Blog.where(title: 'hello world', tags: ['hello', 'first', 'greeting'])
|
68
|
+
check_returned_array(Blog, @expected_resources, result)
|
67
69
|
end
|
68
70
|
|
69
|
-
it 'fetches
|
71
|
+
it 'fetches resources filtered by query string with POST' do
|
70
72
|
stub_request(:post, "#{Blog.base_url}/blogs").
|
71
73
|
with(headers: { 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded' },
|
72
74
|
body: 'title=hello%20world&tags[]=hello&tags[]=first&tags[]=greeting').
|
73
|
-
to_return(status: 200, body: @
|
74
|
-
|
75
|
-
blogs = Blog.where({ title: 'hello world', tags: ['hello', 'first', 'greeting'] }, :post)
|
75
|
+
to_return(status: 200, body: @expected_resources.to_json)
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
expect(blogs.map { |e| e.attributes }).to match (@resource_values)
|
77
|
+
result = Blog.where({ title: 'hello world', tags: ['hello', 'first', 'greeting'] }, :post)
|
78
|
+
check_returned_array(Blog, @expected_resources, result)
|
80
79
|
end
|
81
80
|
end
|
82
81
|
|
83
82
|
context '#by_parent_resource' do
|
83
|
+
|
84
84
|
it 'fetches resource nested with parent resource' do
|
85
|
-
|
86
|
-
{ id: 33, title: 'World' }]
|
87
|
-
resource_id = 3
|
85
|
+
resource_id = 3
|
88
86
|
|
89
87
|
stub_request(:get, "#{Blog.base_url}/tags/#{resource_id}/blogs").
|
90
88
|
with(headers: { 'Accept' => 'application/json' }).
|
91
|
-
to_return(status: 200, body:
|
92
|
-
|
93
|
-
blogs = Blog.by_tag(resource_id)
|
89
|
+
to_return(status: 200, body: @expected_resources.to_json)
|
94
90
|
|
95
|
-
|
96
|
-
|
97
|
-
expect(blogs.map { |e| e.attributes }).to match (resource_values)
|
91
|
+
result = Blog.by_tag(resource_id)
|
92
|
+
check_returned_array(Blog, @expected_resources, result)
|
98
93
|
end
|
99
94
|
end
|
100
95
|
|
101
96
|
context '#child_ressources' do
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
97
|
+
context 'has_many' do
|
98
|
+
it 'defines a method and parses resources from inlined json array' do
|
99
|
+
resource_values = { data: {
|
100
|
+
id: 1257, title: 'Tarte a la creme',
|
101
|
+
tags: { data: [{ id: 33, name: 'food' }, { id: 39, name: 'cuisine' }] }
|
102
|
+
} }
|
103
|
+
resource_id = 3
|
104
|
+
|
105
|
+
stub_request(:get, "#{Blog.base_url}/blogs/#{resource_id}").
|
106
|
+
with(headers: { 'Accept' => 'application/json' }).
|
107
|
+
to_return(status: 200, body: resource_values.to_json)
|
108
|
+
|
109
|
+
blog = Blog.find(resource_id)
|
110
|
+
check_returned_object(Blog, resource_values, blog, :tags)
|
111
|
+
check_returned_array(Tag, resource_values[:data][:tags], blog.tags)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'override type and retrieve meta info' do
|
115
|
+
resource_values = {
|
116
|
+
data: {
|
117
|
+
id: 1257,
|
118
|
+
title: 'Tarte a la creme',
|
119
|
+
my_sweet_tags: {
|
120
|
+
data: [{ id: 33, name: 'food' }, { id: 39, name: 'cuisine' }],
|
121
|
+
meta: { type: :tags, page: 3, per_page: 50, total: 102 }
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
resource_id = 3
|
126
|
+
|
127
|
+
stub_request(:get, "#{Blog.base_url}/blogs/#{resource_id}").
|
128
|
+
with(headers: { 'Accept' => 'application/json' }).
|
129
|
+
to_return(status: 200, body: resource_values.to_json)
|
130
|
+
|
131
|
+
blog = Blog.find(resource_id)
|
132
|
+
check_returned_object(Blog, resource_values, blog, :my_sweet_tags)
|
133
|
+
check_returned_array(Tag, resource_values[:data][:my_sweet_tags], blog.my_sweet_tags)
|
134
|
+
|
135
|
+
expect(blog.my_sweet_tags.page).to eq(3)
|
136
|
+
expect(blog.my_sweet_tags.per_page).to eq(50)
|
137
|
+
expect(blog.my_sweet_tags.total).to eq(102)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'has_one association with inlined json' do
|
142
|
+
resource_values = { data: {
|
143
|
+
id: 1257, title: 'Tarte a la creme',
|
144
|
+
category: { data: { id: 33, name: 'Hobbies' } }
|
145
|
+
} }
|
107
146
|
resource_id = 3
|
108
147
|
|
109
148
|
stub_request(:get, "#{Blog.base_url}/blogs/#{resource_id}").
|
@@ -111,18 +150,20 @@ RSpec.describe ApiResource::Resource do
|
|
111
150
|
to_return(status: 200, body: resource_values.to_json)
|
112
151
|
|
113
152
|
blog = Blog.find(resource_id)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
tags = blog.tags
|
118
|
-
expect(tags).to be_a Array
|
119
|
-
tags.each { |e| expect(e).to be_a Tag }
|
120
|
-
expect(tags.map { |e| e.attributes }).to match (resource_values[:tags])
|
153
|
+
check_returned_object(Blog, resource_values, blog, :category)
|
154
|
+
check_returned_object(Category, resource_values[:data][:category], blog.category)
|
121
155
|
end
|
122
|
-
|
156
|
+
|
157
|
+
it 'override type from meta' do
|
123
158
|
resource_values = {
|
124
|
-
|
125
|
-
|
159
|
+
data: {
|
160
|
+
id: 1257,
|
161
|
+
title: 'Tarte a la creme',
|
162
|
+
main_category: {
|
163
|
+
data: { id: 33, name: 'Hobbies' },
|
164
|
+
meta: { type: :category }
|
165
|
+
}
|
166
|
+
}
|
126
167
|
}
|
127
168
|
resource_id = 3
|
128
169
|
|
@@ -131,12 +172,8 @@ RSpec.describe ApiResource::Resource do
|
|
131
172
|
to_return(status: 200, body: resource_values.to_json)
|
132
173
|
|
133
174
|
blog = Blog.find(resource_id)
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
category = blog.category
|
138
|
-
expect(category).to be_a Category
|
139
|
-
expect(category.attributes).to match(resource_values[:category])
|
175
|
+
check_returned_object(Blog, resource_values, blog, :main_category)
|
176
|
+
check_returned_object(Category, resource_values[:data][:main_category], blog.main_category)
|
140
177
|
end
|
141
178
|
end
|
142
179
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api-resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chaker Nakhli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simple-hmac
|