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