restful_resource 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +20 -0
- data/.codeclimate.yml +3 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +203 -0
- data/CHANGELOG.md +5 -0
- data/README.md +1 -1
- data/Rakefile +5 -5
- data/lib/restful_resource/associations.rb +10 -8
- data/lib/restful_resource/base.rb +36 -33
- data/lib/restful_resource/http_client.rb +50 -48
- data/lib/restful_resource/instrumentation.rb +17 -20
- data/lib/restful_resource/null_logger.rb +1 -2
- data/lib/restful_resource/open_object.rb +2 -2
- data/lib/restful_resource/paginated_array.rb +3 -1
- data/lib/restful_resource/rails_validations.rb +12 -12
- data/lib/restful_resource/redirections.rb +5 -6
- data/lib/restful_resource/request.rb +0 -1
- data/lib/restful_resource/resource_id_missing_error.rb +1 -1
- data/lib/restful_resource/response.rb +4 -2
- data/lib/restful_resource/version.rb +1 -1
- data/restful_resource.gemspec +26 -25
- data/spec/fixtures.rb +7 -7
- data/spec/restful_resource/associations_spec.rb +23 -21
- data/spec/restful_resource/base_authorization_spec.rb +6 -7
- data/spec/restful_resource/base_spec.rb +134 -117
- data/spec/restful_resource/http_client_configuration_spec.rb +20 -19
- data/spec/restful_resource/http_client_spec.rb +38 -38
- data/spec/restful_resource/open_object_spec.rb +8 -8
- data/spec/restful_resource/rails_validations_spec.rb +68 -68
- data/spec/restful_resource/redirections_spec.rb +26 -26
- data/spec/spec_helper.rb +3 -4
- metadata +44 -13
- data/circle.yml +0 -3
@@ -1,5 +1,5 @@
|
|
1
1
|
# Use the Faraday-Typhoeus adapter provided by Typhoeus, not Faraday
|
2
|
-
require
|
2
|
+
require 'typhoeus/adapters/faraday'
|
3
3
|
|
4
4
|
module RestfulResource
|
5
5
|
class HttpClient
|
@@ -7,15 +7,16 @@ module RestfulResource
|
|
7
7
|
attr_reader :request, :response
|
8
8
|
|
9
9
|
def initialize(request, response = nil)
|
10
|
-
@request
|
10
|
+
@request = request
|
11
|
+
@response = assign_response(response)
|
11
12
|
end
|
12
13
|
|
13
14
|
def assign_response(response = nil)
|
14
|
-
if response
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
@response = if response
|
16
|
+
Response.new(body: response[:body], headers: response[:headers], status: response[:status])
|
17
|
+
else
|
18
|
+
Response.new
|
19
|
+
end
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
@@ -24,7 +25,7 @@ module RestfulResource
|
|
24
25
|
|
25
26
|
class ResourceNotFound < HttpError
|
26
27
|
def message
|
27
|
-
|
28
|
+
'HTTP 404: Resource Not Found'
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
@@ -40,44 +41,45 @@ module RestfulResource
|
|
40
41
|
|
41
42
|
class BadGateway < RetryableError
|
42
43
|
def message
|
43
|
-
|
44
|
+
'HTTP 502: Bad gateway'
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
48
|
class ServiceUnavailable < RetryableError
|
48
49
|
def message
|
49
|
-
|
50
|
+
'HTTP 503: Service unavailable'
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
54
|
class Timeout < RetryableError
|
54
55
|
def message
|
55
|
-
|
56
|
+
'Timeout: Service not responding'
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
59
60
|
class TooManyRequests < RetryableError
|
60
61
|
def message
|
61
|
-
|
62
|
+
'HTTP 429: Too Many Requests'
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
65
66
|
class ClientError < RetryableError
|
66
67
|
def message
|
67
|
-
|
68
|
+
'There was some client error'
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
72
|
def initialize(username: nil,
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
73
|
+
password: nil,
|
74
|
+
auth_token: nil,
|
75
|
+
logger: nil,
|
76
|
+
cache_store: nil,
|
77
|
+
connection: nil,
|
78
|
+
instrumentation: {},
|
79
|
+
open_timeout: 2,
|
80
|
+
timeout: 10,
|
81
|
+
faraday_config: nil,
|
82
|
+
faraday_options: nil)
|
81
83
|
api_name = instrumentation[:api_name] ||= 'api'
|
82
84
|
instrumentation[:request_instrument_name] ||= "http.#{api_name}"
|
83
85
|
instrumentation[:cache_instrument_name] ||= "http_cache.#{api_name}"
|
@@ -85,11 +87,13 @@ module RestfulResource
|
|
85
87
|
|
86
88
|
if instrumentation[:metric_class]
|
87
89
|
@metrics = Instrumentation.new(instrumentation.slice(:app_name,
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
:api_name,
|
91
|
+
:request_instrument_name,
|
92
|
+
:cache_instrument_name,
|
93
|
+
:server_cache_instrument_name,
|
94
|
+
:metric_class
|
95
|
+
)
|
96
|
+
)
|
93
97
|
@metrics.subscribe_to_notifications
|
94
98
|
end
|
95
99
|
|
@@ -100,7 +104,9 @@ module RestfulResource
|
|
100
104
|
request_instrument_name: instrumentation.fetch(:request_instrument_name, nil),
|
101
105
|
cache_instrument_name: instrumentation.fetch(:cache_instrument_name, nil),
|
102
106
|
server_cache_instrument_name: instrumentation.fetch(:server_cache_instrument_name, nil),
|
103
|
-
faraday_config: faraday_config
|
107
|
+
faraday_config: faraday_config,
|
108
|
+
faraday_options: faraday_options
|
109
|
+
)
|
104
110
|
|
105
111
|
if auth_token
|
106
112
|
@connection.headers[:authorization] = "Bearer #{auth_token}"
|
@@ -168,20 +174,19 @@ module RestfulResource
|
|
168
174
|
attr_reader :default_open_timeout, :default_timeout
|
169
175
|
|
170
176
|
def initialize_connection(logger: nil,
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
177
|
+
cache_store: nil,
|
178
|
+
instrumenter: nil,
|
179
|
+
request_instrument_name: nil,
|
180
|
+
cache_instrument_name: nil,
|
181
|
+
server_cache_instrument_name: nil,
|
182
|
+
faraday_config: nil,
|
183
|
+
faraday_options: nil)
|
184
|
+
|
185
|
+
@connection = Faraday.new(nil, faraday_options) do |b|
|
179
186
|
b.request :json
|
180
187
|
b.response :raise_error
|
181
188
|
|
182
|
-
if logger
|
183
|
-
b.response :logger, logger
|
184
|
-
end
|
189
|
+
b.response :logger, logger if logger
|
185
190
|
|
186
191
|
if server_cache_instrument_name
|
187
192
|
b.use :cdn_metrics, instrumenter: instrumenter,
|
@@ -195,13 +200,9 @@ module RestfulResource
|
|
195
200
|
instrument_name: cache_instrument_name
|
196
201
|
end
|
197
202
|
|
198
|
-
if instrumenter && request_instrument_name
|
199
|
-
b.use :instrumentation, name: request_instrument_name
|
200
|
-
end
|
203
|
+
b.use :instrumentation, name: request_instrument_name if instrumenter && request_instrument_name
|
201
204
|
|
202
|
-
|
203
|
-
faraday_config.call(b)
|
204
|
-
end
|
205
|
+
faraday_config&.call(b)
|
205
206
|
|
206
207
|
b.response :encoding
|
207
208
|
b.use :gzip
|
@@ -211,7 +212,7 @@ module RestfulResource
|
|
211
212
|
end
|
212
213
|
|
213
214
|
def build_user_agent(app_name)
|
214
|
-
parts = [
|
215
|
+
parts = ['carwow/internal']
|
215
216
|
parts << "RestfulResource/#{VERSION}"
|
216
217
|
parts << "(#{app_name})" if app_name
|
217
218
|
parts << "Faraday/#{Faraday::VERSION}"
|
@@ -232,10 +233,11 @@ module RestfulResource
|
|
232
233
|
rescue Faraday::ConnectionFailed
|
233
234
|
raise
|
234
235
|
rescue Faraday::TimeoutError
|
235
|
-
raise HttpClient::Timeout
|
236
|
+
raise HttpClient::Timeout, request
|
236
237
|
rescue Faraday::ClientError => e
|
237
238
|
response = e.response
|
238
|
-
raise ClientError
|
239
|
+
raise ClientError, request unless response
|
240
|
+
|
239
241
|
case response[:status]
|
240
242
|
when 404 then raise HttpClient::ResourceNotFound.new(request, response)
|
241
243
|
when 409 then raise HttpClient::Conflict.new(request, response)
|
@@ -2,7 +2,6 @@ require 'active_support/notifications'
|
|
2
2
|
|
3
3
|
module RestfulResource
|
4
4
|
class Instrumentation
|
5
|
-
|
6
5
|
def initialize(app_name:, api_name:, request_instrument_name:, cache_instrument_name:, server_cache_instrument_name:, metric_class:)
|
7
6
|
@app_name = app_name
|
8
7
|
@api_name = api_name
|
@@ -50,18 +49,18 @@ module RestfulResource
|
|
50
49
|
# count#quotes_site.research_site_api.cache_hit=1
|
51
50
|
# count#quotes_site.research_site_api.api_v2_cap_derivatives.cache_hit=1
|
52
51
|
case cache_status
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
52
|
+
when :fresh, :valid
|
53
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_hit'), 1
|
54
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_hit', event: event), 1
|
55
|
+
when :invalid, :miss
|
56
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_miss'), 1
|
57
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_miss', event: event), 1
|
58
|
+
when :unacceptable
|
59
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_not_cacheable'), 1
|
60
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_not_cacheable', event: event), 1
|
61
|
+
when :bypass
|
62
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_bypass'), 1
|
63
|
+
metric_class.count cache_notifier_namespace(metric: 'cache_bypass', event: event), 1
|
65
64
|
end
|
66
65
|
end
|
67
66
|
|
@@ -71,7 +70,7 @@ module RestfulResource
|
|
71
70
|
client_cache_status = event.payload.fetch(:client_cache_status, nil)
|
72
71
|
server_cache_status = event.payload.fetch(:server_cache_status, nil)
|
73
72
|
|
74
|
-
if client_cache_status.nil? || !client_cache_status.in?([
|
73
|
+
if client_cache_status.nil? || !client_cache_status.in?(%i[fresh valid])
|
75
74
|
# Outputs log lines like:
|
76
75
|
# count#quotes_site.research_site_api.server_cache_hit=1
|
77
76
|
# count#quotes_site.research_site_api.api_v2_cap_derivatives.server_cache_hit=1
|
@@ -100,19 +99,17 @@ module RestfulResource
|
|
100
99
|
end
|
101
100
|
|
102
101
|
def validate_metric_class!
|
103
|
-
metric_methods = %i
|
104
|
-
if metric_methods.any? {|m| !metric_class.respond_to?(m) }
|
105
|
-
raise ArgumentError.new "Metric class '#{metric_class}' does not respond to #{metric_methods.join ','}"
|
106
|
-
end
|
102
|
+
metric_methods = %i[count sample measure]
|
103
|
+
raise ArgumentError, "Metric class '#{metric_class}' does not respond to #{metric_methods.join ','}" if metric_methods.any? { |m| !metric_class.respond_to?(m) }
|
107
104
|
end
|
108
105
|
|
109
106
|
def cache_notifier_namespace(metric:, event: nil)
|
110
107
|
[app_name, api_name, base_request_path(event), metric].compact.join('.')
|
111
108
|
end
|
112
109
|
|
113
|
-
#
|
110
|
+
# Converts a path like "/api/v2/cap_derivatives/75423/with_colours" to "api_v2_cap_derivatives_with_colours"
|
114
111
|
def base_request_path(event)
|
115
|
-
path_from_event(event).split('/').drop(1).select {|a| a.match(/\d+/).nil? }.join('_') if event
|
112
|
+
path_from_event(event).split('/').drop(1).select { |a| a.match(/\d+/).nil? }.join('_') if event
|
116
113
|
end
|
117
114
|
|
118
115
|
def path_from_event(event)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RestfulResource
|
2
2
|
class OpenObject
|
3
|
-
def initialize(attributes = {},
|
3
|
+
def initialize(attributes = {}, _hack_for_activeresource = false)
|
4
4
|
@inner_object = OpenStruct.new(attributes)
|
5
5
|
end
|
6
6
|
|
@@ -16,7 +16,7 @@ module RestfulResource
|
|
16
16
|
super || @inner_object.respond_to?(method, include_private)
|
17
17
|
end
|
18
18
|
|
19
|
-
def as_json(options=nil)
|
19
|
+
def as_json(options = nil)
|
20
20
|
@inner_object.send(:table).as_json(options)
|
21
21
|
end
|
22
22
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RestfulResource
|
2
2
|
class PaginatedArray < Array
|
3
|
-
def initialize(original_array, previous_page_url:, next_page_url:, total_count:
|
3
|
+
def initialize(original_array, previous_page_url:, next_page_url:, total_count:)
|
4
4
|
super(original_array)
|
5
5
|
|
6
6
|
@previous_page_url = previous_page_url
|
@@ -21,8 +21,10 @@ module RestfulResource
|
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
24
|
+
|
24
25
|
def get_page_from_url(url)
|
25
26
|
return nil unless url
|
27
|
+
|
26
28
|
params = Rack::Utils.parse_query URI(url).query
|
27
29
|
params['page'].to_i
|
28
30
|
end
|
@@ -6,13 +6,13 @@ module RestfulResource
|
|
6
6
|
rescue HttpClient::UnprocessableEntity => e
|
7
7
|
errors = parse_json(e.response.body)
|
8
8
|
result = nil
|
9
|
-
if errors.is_a?(Hash) && errors.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
result = if errors.is_a?(Hash) && errors.key?('errors')
|
10
|
+
data.merge(errors)
|
11
|
+
else
|
12
|
+
data.merge(errors: errors)
|
13
|
+
end
|
14
14
|
result = result.merge(id: id)
|
15
|
-
|
15
|
+
new(result)
|
16
16
|
end
|
17
17
|
|
18
18
|
def post(data: {}, **)
|
@@ -30,12 +30,12 @@ module RestfulResource
|
|
30
30
|
rescue HttpClient::UnprocessableEntity => e
|
31
31
|
errors = parse_json(e.response.body)
|
32
32
|
result = nil
|
33
|
-
if errors.is_a?(Hash) && errors.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
result = if errors.is_a?(Hash) && errors.key?('errors')
|
34
|
+
data.merge(errors)
|
35
|
+
else
|
36
|
+
data.merge(errors: errors)
|
37
|
+
end
|
38
|
+
new(result)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RestfulResource
|
2
2
|
class MaximumAttemptsReached < StandardError
|
3
3
|
def message
|
4
|
-
|
4
|
+
'The maximum attempts limit was reached before the resource was ready'
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
@@ -11,12 +11,13 @@ module RestfulResource
|
|
11
11
|
def post(data: {}, delay: 1.0, max_attempts: 10, headers: {}, open_timeout: nil, timeout: nil, **params)
|
12
12
|
url = collection_url(params)
|
13
13
|
|
14
|
-
response =
|
14
|
+
response = accept_redirected_result(response: http.post(url, data: data, headers: headers, open_timeout: nil, timeout: nil), delay: delay, max_attempts: max_attempts)
|
15
15
|
|
16
|
-
|
16
|
+
new(parse_json(response.body))
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
20
|
+
|
20
21
|
def self.accept_redirected_result(response:, delay:, max_attempts:)
|
21
22
|
new_response = response
|
22
23
|
if response.status == 303
|
@@ -32,9 +33,7 @@ module RestfulResource
|
|
32
33
|
new_response = http.get(resource_location, headers: {}, open_timeout: nil, timeout: nil)
|
33
34
|
end
|
34
35
|
|
35
|
-
if attempts == max_attempts
|
36
|
-
raise RestfulResource::MaximumAttemptsReached
|
37
|
-
end
|
36
|
+
raise RestfulResource::MaximumAttemptsReached if attempts == max_attempts
|
38
37
|
end
|
39
38
|
response = new_response
|
40
39
|
end
|
@@ -2,8 +2,10 @@ module RestfulResource
|
|
2
2
|
class Response
|
3
3
|
attr_reader :body, :headers, :status
|
4
4
|
|
5
|
-
def initialize(body:
|
6
|
-
@body
|
5
|
+
def initialize(body: '{}', headers: {}, status: nil)
|
6
|
+
@body = body
|
7
|
+
@headers = headers
|
8
|
+
@status = status
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
data/restful_resource.gemspec
CHANGED
@@ -1,36 +1,37 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'restful_resource/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'restful_resource'
|
8
7
|
spec.version = RestfulResource::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.description =
|
12
|
-
spec.summary =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
8
|
+
spec.authors = ['David Santoro', 'Federico Rebora']
|
9
|
+
spec.email = ['developers@carwow.co.uk']
|
10
|
+
spec.description = 'A simple activerecord inspired rest resource base class implemented using rest-client'
|
11
|
+
spec.summary = 'A simple activerecord inspired rest resource base class implemented using rest-client'
|
12
|
+
spec.homepage = 'http://www.github.com/carwow/restful_resource'
|
13
|
+
spec.license = 'MIT'
|
15
14
|
|
16
|
-
spec.files = `git ls-files`.split(
|
15
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
20
|
-
spec.required_ruby_version = '>= 2.
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
spec.required_ruby_version = '>= 2.4'
|
21
20
|
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'carwow_rubocop', '~> 2.0'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.1'
|
25
|
+
spec.add_development_dependency 'rspec_junit_formatter'
|
26
|
+
spec.add_development_dependency 'rspec-its'
|
26
27
|
|
27
|
-
spec.add_dependency
|
28
|
-
spec.add_dependency
|
29
|
-
spec.add_dependency
|
30
|
-
spec.add_dependency
|
31
|
-
spec.add_dependency
|
32
|
-
spec.add_dependency
|
33
|
-
spec.add_dependency
|
34
|
-
spec.add_dependency
|
35
|
-
spec.add_dependency
|
28
|
+
spec.add_dependency 'activesupport'
|
29
|
+
spec.add_dependency 'faraday'
|
30
|
+
spec.add_dependency 'faraday-cdn-metrics'
|
31
|
+
spec.add_dependency 'faraday-encoding'
|
32
|
+
spec.add_dependency 'faraday-http-cache'
|
33
|
+
spec.add_dependency 'faraday_middleware'
|
34
|
+
spec.add_dependency 'link_header'
|
35
|
+
spec.add_dependency 'rack'
|
36
|
+
spec.add_dependency 'typhoeus'
|
36
37
|
end
|
data/spec/fixtures.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
class Make < RestfulResource::Base
|
2
|
-
resource_path
|
2
|
+
resource_path 'makes'
|
3
3
|
has_many :models
|
4
4
|
end
|
5
5
|
|
6
6
|
class Model < RestfulResource::Base
|
7
7
|
has_one :make
|
8
|
-
resource_path
|
8
|
+
resource_path 'groups/:group_id/makes/:make_slug/models'
|
9
9
|
end
|
10
10
|
|
11
11
|
class Dealer < RestfulResource::Base
|
12
12
|
include RestfulResource::RailsValidations
|
13
13
|
|
14
|
-
resource_path
|
14
|
+
resource_path 'dealers'
|
15
15
|
end
|
16
16
|
|
17
17
|
class BaseA < RestfulResource::Base
|
@@ -21,11 +21,11 @@ class BaseB < RestfulResource::Base
|
|
21
21
|
end
|
22
22
|
|
23
23
|
class TestA < BaseA
|
24
|
-
|
24
|
+
resource_path 'testa'
|
25
25
|
end
|
26
26
|
|
27
27
|
class TestB < BaseB
|
28
|
-
|
28
|
+
resource_path 'testb'
|
29
29
|
end
|
30
30
|
|
31
31
|
class ModelWithRedirections < RestfulResource::Base
|
@@ -36,7 +36,7 @@ end
|
|
36
36
|
|
37
37
|
module ComplicatedModule
|
38
38
|
class Parent < BaseA
|
39
|
-
resource_path
|
39
|
+
resource_path 'parent'
|
40
40
|
has_many :children
|
41
41
|
has_many :other_things
|
42
42
|
has_many :missing
|
@@ -51,7 +51,7 @@ module ComplicatedModule
|
|
51
51
|
has_one :parent
|
52
52
|
|
53
53
|
def full_name
|
54
|
-
"#{
|
54
|
+
"#{first_name} #{second_name}"
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -1,53 +1,55 @@
|
|
1
1
|
require_relative '../spec_helper'
|
2
2
|
|
3
3
|
describe RestfulResource::Associations do
|
4
|
-
describe
|
5
|
-
before
|
6
|
-
@parent = ComplicatedModule::Parent.new(
|
4
|
+
describe '#has_many' do
|
5
|
+
before do
|
6
|
+
@parent = ComplicatedModule::Parent.new(
|
7
7
|
name: 'John Doe',
|
8
|
-
other_things: [{stuff: 'aaa'}, {stuff: 'bbb'}],
|
8
|
+
other_things: [{ stuff: 'aaa' }, { stuff: 'bbb' }],
|
9
9
|
children:
|
10
10
|
[
|
11
|
-
{first_name: 'David', second_name: 'Doe'},
|
12
|
-
{first_name: 'Mary', second_name: 'Doe'}
|
11
|
+
{ first_name: 'David', second_name: 'Doe' },
|
12
|
+
{ first_name: 'Mary', second_name: 'Doe' }
|
13
13
|
]
|
14
|
-
|
14
|
+
|
15
|
+
)
|
15
16
|
end
|
16
17
|
|
17
|
-
it
|
18
|
+
it 'adds a method to access nested resource' do
|
18
19
|
expect(@parent.children.first.first_name).to eq 'David'
|
19
20
|
expect(@parent.children.last.first_name).to eq 'Mary'
|
20
|
-
expect(@parent.children.first.to_json).to eq({first_name: 'David', second_name: 'Doe'}.to_json)
|
21
|
+
expect(@parent.children.first.to_json).to eq({ first_name: 'David', second_name: 'Doe' }.to_json)
|
21
22
|
end
|
22
23
|
|
23
|
-
it
|
24
|
+
it 'picks the right class for the instantiation of chilren' do
|
24
25
|
expect(@parent.children.first.full_name).to eq 'David Doe'
|
25
26
|
end
|
26
27
|
|
27
|
-
it "
|
28
|
+
it "uses open object when can't infer class name of association" do
|
28
29
|
expect(@parent.other_things.first.stuff).to eq 'aaa'
|
29
30
|
end
|
30
31
|
|
31
|
-
it
|
32
|
+
it 'returns nil for missing associations' do
|
32
33
|
expect(@parent.missing).to be_nil
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
|
-
describe
|
37
|
-
before
|
38
|
-
@child = ComplicatedModule::Child.new(
|
37
|
+
describe '#has_one' do
|
38
|
+
before do
|
39
|
+
@child = ComplicatedModule::Child.new(
|
39
40
|
first_name: 'David', second_name: 'Smith',
|
40
|
-
parent: {name: 'John Smith'}
|
41
|
-
|
41
|
+
parent: { name: 'John Smith' }
|
42
|
+
|
43
|
+
)
|
42
44
|
end
|
43
45
|
|
44
|
-
it
|
46
|
+
it 'adds a method to access nested resource' do
|
45
47
|
expect(@child.parent.name).to eq 'John Smith'
|
46
|
-
expect(@child.parent.to_json).to eq({name: 'John Smith'}.to_json)
|
48
|
+
expect(@child.parent.to_json).to eq({ name: 'John Smith' }.to_json)
|
47
49
|
end
|
48
50
|
|
49
|
-
it
|
50
|
-
expect(@child.parent
|
51
|
+
it 'picks the right class for the instantiation of chilren' do
|
52
|
+
expect(@child.parent).to be_is_parent
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative '../spec_helper'
|
2
2
|
|
3
3
|
describe RestfulResource::Base, 'authorization' do
|
4
|
-
before
|
4
|
+
before do
|
5
5
|
class FirstClient < RestfulResource::Base
|
6
6
|
end
|
7
7
|
|
@@ -21,20 +21,19 @@ describe RestfulResource::Base, 'authorization' do
|
|
21
21
|
FirstClient.configure(base_url: 'http://api.carwow.co.uk/api/first')
|
22
22
|
SecondClient.configure(base_url: 'http://api.carwow.co.uk/api/second',
|
23
23
|
username: 'test_user',
|
24
|
-
password: 'test_pass'
|
24
|
+
password: 'test_pass'
|
25
|
+
)
|
25
26
|
end
|
26
27
|
|
27
|
-
it
|
28
|
+
it 'uses two different http instances' do
|
28
29
|
expect(FirstTest.send(:http)).not_to equal(SecondTest.send(:http))
|
29
30
|
end
|
30
31
|
|
31
|
-
it '
|
32
|
+
it 'has same http auth on superclass' do
|
32
33
|
expect(SecondTest.send(:http)).to equal(SecondClient.send(:http))
|
33
34
|
end
|
34
35
|
|
35
|
-
it '
|
36
|
+
it 'raises exception if base_url is not set' do
|
36
37
|
expect { NotConfiguredClient.send(:base_url) }.to raise_error 'Base url missing'
|
37
38
|
end
|
38
|
-
|
39
39
|
end
|
40
|
-
|