activeresource 4.1.0 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/MIT-LICENSE +20 -0
- data/README.md +324 -0
- data/lib/active_resource/active_job_serializer.rb +26 -0
- data/lib/active_resource/associations/builder/association.rb +6 -6
- data/lib/active_resource/associations/builder/belongs_to.rb +5 -3
- data/lib/active_resource/associations/builder/has_many.rb +4 -2
- data/lib/active_resource/associations/builder/has_one.rb +5 -3
- data/lib/active_resource/associations.rb +23 -20
- data/lib/active_resource/base.rb +233 -113
- data/lib/active_resource/callbacks.rb +3 -1
- data/lib/active_resource/collection.rb +21 -12
- data/lib/active_resource/connection.rb +78 -81
- data/lib/active_resource/custom_methods.rb +8 -6
- data/lib/active_resource/exceptions.rb +17 -5
- data/lib/active_resource/formats/json_format.rb +4 -1
- data/lib/active_resource/formats/xml_format.rb +4 -2
- data/lib/active_resource/formats.rb +5 -3
- data/lib/active_resource/http_mock.rb +23 -27
- data/lib/active_resource/inheriting_hash.rb +15 -0
- data/lib/active_resource/log_subscriber.rb +14 -3
- data/lib/active_resource/railtie.rb +10 -10
- data/lib/active_resource/reflection.rb +11 -10
- data/lib/active_resource/schema.rb +6 -3
- data/lib/active_resource/singleton.rb +25 -28
- data/lib/active_resource/threadsafe_attributes.rb +35 -31
- data/lib/active_resource/validations.rb +18 -15
- data/lib/active_resource/version.rb +6 -4
- data/lib/active_resource.rb +8 -7
- data/lib/activeresource.rb +3 -1
- metadata +41 -24
- data/README.rdoc +0 -231
- data/lib/active_resource/observing.rb +0 -31
@@ -1,19 +1,22 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/delegation"
|
4
|
+
require "active_support/inflector"
|
3
5
|
|
4
6
|
module ActiveResource # :nodoc:
|
5
7
|
class Collection # :nodoc:
|
8
|
+
SELF_DEFINE_METHODS = [:to_a, :collect!, :map!, :all?]
|
6
9
|
include Enumerable
|
7
|
-
delegate :to_yaml, :all?, *Array.instance_methods(false), :
|
10
|
+
delegate :to_yaml, :all?, *(Array.instance_methods(false) - SELF_DEFINE_METHODS), to: :to_a
|
8
11
|
|
9
12
|
# The array of actual elements returned by index actions
|
10
13
|
attr_accessor :elements, :resource_class, :original_params
|
11
|
-
|
14
|
+
|
12
15
|
# ActiveResource::Collection is a wrapper to handle parsing index responses that
|
13
16
|
# do not directly map to Rails conventions.
|
14
17
|
#
|
15
|
-
# You can define a custom class that
|
16
|
-
# in order to to set the elements instance.
|
18
|
+
# You can define a custom class that inherits from ActiveResource::Collection
|
19
|
+
# in order to to set the elements instance.
|
17
20
|
#
|
18
21
|
# GET /posts.json delivers following response body:
|
19
22
|
# {
|
@@ -21,12 +24,12 @@ module ActiveResource # :nodoc:
|
|
21
24
|
# {
|
22
25
|
# title: "ActiveResource now has associations",
|
23
26
|
# body: "Lorem Ipsum"
|
24
|
-
# }
|
27
|
+
# },
|
25
28
|
# {...}
|
26
|
-
# ]
|
29
|
+
# ],
|
27
30
|
# next_page: "/posts.json?page=2"
|
28
31
|
# }
|
29
|
-
#
|
32
|
+
#
|
30
33
|
# A Post class can be setup to handle it with:
|
31
34
|
#
|
32
35
|
# class Post < ActiveResource::Base
|
@@ -44,7 +47,7 @@ module ActiveResource # :nodoc:
|
|
44
47
|
# end
|
45
48
|
# end
|
46
49
|
#
|
47
|
-
# The result from a find method that returns multiple entries will now be a
|
50
|
+
# The result from a find method that returns multiple entries will now be a
|
48
51
|
# PostParser instance. ActiveResource::Collection includes Enumerable and
|
49
52
|
# instances can be iterated over just like an array.
|
50
53
|
# @posts = Post.find(:all) # => PostCollection:xxx
|
@@ -56,11 +59,11 @@ module ActiveResource # :nodoc:
|
|
56
59
|
def initialize(elements = [])
|
57
60
|
@elements = elements
|
58
61
|
end
|
59
|
-
|
62
|
+
|
60
63
|
def to_a
|
61
64
|
elements
|
62
65
|
end
|
63
|
-
|
66
|
+
|
64
67
|
def collect!
|
65
68
|
return elements unless block_given?
|
66
69
|
set = []
|
@@ -81,5 +84,11 @@ module ActiveResource # :nodoc:
|
|
81
84
|
rescue NoMethodError
|
82
85
|
raise "Cannot build resource from resource type: #{resource_class.inspect}"
|
83
86
|
end
|
87
|
+
|
88
|
+
def where(clauses = {})
|
89
|
+
raise ArgumentError, "expected a clauses Hash, got #{clauses.inspect}" unless clauses.is_a? Hash
|
90
|
+
new_clauses = original_params.merge(clauses)
|
91
|
+
resource_class.where(new_clauses)
|
92
|
+
end
|
84
93
|
end
|
85
94
|
end
|
@@ -1,27 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/benchmark"
|
4
|
+
require "active_support/core_ext/object/inclusion"
|
5
|
+
require "net/https"
|
6
|
+
require "date"
|
7
|
+
require "time"
|
8
|
+
require "uri"
|
8
9
|
|
9
10
|
module ActiveResource
|
10
11
|
# Class to handle connections to remote web services.
|
11
12
|
# This class is used by ActiveResource::Base to interface with REST
|
12
13
|
# services.
|
13
14
|
class Connection
|
14
|
-
|
15
|
-
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:head => 'Accept'
|
15
|
+
HTTP_FORMAT_HEADER_NAMES = { get: "Accept",
|
16
|
+
put: "Content-Type",
|
17
|
+
post: "Content-Type",
|
18
|
+
patch: "Content-Type",
|
19
|
+
delete: "Accept",
|
20
|
+
head: "Accept"
|
21
21
|
}
|
22
22
|
|
23
|
-
attr_reader :site, :user, :password, :auth_type, :timeout, :open_timeout, :read_timeout, :proxy, :ssl_options
|
24
|
-
attr_accessor :format
|
23
|
+
attr_reader :site, :user, :password, :bearer_token, :auth_type, :timeout, :open_timeout, :read_timeout, :proxy, :ssl_options
|
24
|
+
attr_accessor :format, :logger
|
25
25
|
|
26
26
|
class << self
|
27
27
|
def requests
|
@@ -31,19 +31,20 @@ module ActiveResource
|
|
31
31
|
|
32
32
|
# The +site+ parameter is required and will set the +site+
|
33
33
|
# attribute to the URI for the remote resource service.
|
34
|
-
def initialize(site, format = ActiveResource::Formats::JsonFormat)
|
35
|
-
raise ArgumentError,
|
36
|
-
@proxy = @user = @password = nil
|
34
|
+
def initialize(site, format = ActiveResource::Formats::JsonFormat, logger: nil)
|
35
|
+
raise ArgumentError, "Missing site URI" unless site
|
36
|
+
@proxy = @user = @password = @bearer_token = nil
|
37
37
|
self.site = site
|
38
38
|
self.format = format
|
39
|
+
self.logger = logger
|
39
40
|
end
|
40
41
|
|
41
42
|
# Set URI for remote service.
|
42
43
|
def site=(site)
|
43
44
|
@site = site.is_a?(URI) ? site : URI.parse(site)
|
44
45
|
@ssl_options ||= {} if @site.is_a?(URI::HTTPS)
|
45
|
-
@user = URI.
|
46
|
-
@password = URI.
|
46
|
+
@user = URI::DEFAULT_PARSER.unescape(@site.user) if @site.user
|
47
|
+
@password = URI::DEFAULT_PARSER.unescape(@site.password) if @site.password
|
47
48
|
end
|
48
49
|
|
49
50
|
# Set the proxy for remote service.
|
@@ -52,14 +53,13 @@ module ActiveResource
|
|
52
53
|
end
|
53
54
|
|
54
55
|
# Sets the user for remote service.
|
55
|
-
|
56
|
-
@user = user
|
57
|
-
end
|
56
|
+
attr_writer :user
|
58
57
|
|
59
58
|
# Sets the password for remote service.
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
attr_writer :password
|
60
|
+
|
61
|
+
# Sets the bearer token for remote service.
|
62
|
+
attr_writer :bearer_token
|
63
63
|
|
64
64
|
# Sets the auth type for remote service.
|
65
65
|
def auth_type=(auth_type)
|
@@ -67,24 +67,16 @@ module ActiveResource
|
|
67
67
|
end
|
68
68
|
|
69
69
|
# Sets the number of seconds after which HTTP requests to the remote service should time out.
|
70
|
-
|
71
|
-
@timeout = timeout
|
72
|
-
end
|
70
|
+
attr_writer :timeout
|
73
71
|
|
74
72
|
# Sets the number of seconds after which HTTP connects to the remote service should time out.
|
75
|
-
|
76
|
-
@open_timeout = timeout
|
77
|
-
end
|
73
|
+
attr_writer :open_timeout
|
78
74
|
|
79
75
|
# Sets the number of seconds after which HTTP read requests to the remote service should time out.
|
80
|
-
|
81
|
-
@read_timeout = timeout
|
82
|
-
end
|
76
|
+
attr_writer :read_timeout
|
83
77
|
|
84
78
|
# Hash of options applied to Net::HTTP instance when +site+ protocol is 'https'.
|
85
|
-
|
86
|
-
@ssl_options = options
|
87
|
-
end
|
79
|
+
attr_writer :ssl_options
|
88
80
|
|
89
81
|
# Executes a GET request.
|
90
82
|
# Used to get (find) resources.
|
@@ -100,19 +92,19 @@ module ActiveResource
|
|
100
92
|
|
101
93
|
# Executes a PATCH request (see HTTP protocol documentation if unfamiliar).
|
102
94
|
# Used to update resources.
|
103
|
-
def patch(path, body =
|
95
|
+
def patch(path, body = "", headers = {})
|
104
96
|
with_auth { request(:patch, path, body.to_s, build_request_headers(headers, :patch, self.site.merge(path))) }
|
105
97
|
end
|
106
98
|
|
107
99
|
# Executes a PUT request (see HTTP protocol documentation if unfamiliar).
|
108
100
|
# Used to update resources.
|
109
|
-
def put(path, body =
|
101
|
+
def put(path, body = "", headers = {})
|
110
102
|
with_auth { request(:put, path, body.to_s, build_request_headers(headers, :put, self.site.merge(path))) }
|
111
103
|
end
|
112
104
|
|
113
105
|
# Executes a POST request.
|
114
106
|
# Used to create new resources.
|
115
|
-
def post(path, body =
|
107
|
+
def post(path, body = "", headers = {})
|
116
108
|
with_auth { request(:post, path, body.to_s, build_request_headers(headers, :post, self.site.merge(path))) }
|
117
109
|
end
|
118
110
|
|
@@ -140,32 +132,36 @@ module ActiveResource
|
|
140
132
|
# Handles response and error codes from the remote service.
|
141
133
|
def handle_response(response)
|
142
134
|
case response.code.to_i
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
135
|
+
when 301, 302, 303, 307
|
136
|
+
raise(Redirection.new(response))
|
137
|
+
when 200...400
|
138
|
+
response
|
139
|
+
when 400
|
140
|
+
raise(BadRequest.new(response))
|
141
|
+
when 401
|
142
|
+
raise(UnauthorizedAccess.new(response))
|
143
|
+
when 403
|
144
|
+
raise(ForbiddenAccess.new(response))
|
145
|
+
when 404
|
146
|
+
raise(ResourceNotFound.new(response))
|
147
|
+
when 405
|
148
|
+
raise(MethodNotAllowed.new(response))
|
149
|
+
when 409
|
150
|
+
raise(ResourceConflict.new(response))
|
151
|
+
when 410
|
152
|
+
raise(ResourceGone.new(response))
|
153
|
+
when 412
|
154
|
+
raise(PreconditionFailed.new(response))
|
155
|
+
when 422
|
156
|
+
raise(ResourceInvalid.new(response))
|
157
|
+
when 429
|
158
|
+
raise(TooManyRequests.new(response))
|
159
|
+
when 401...500
|
160
|
+
raise(ClientError.new(response))
|
161
|
+
when 500...600
|
162
|
+
raise(ServerError.new(response))
|
163
|
+
else
|
164
|
+
raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
|
169
165
|
end
|
170
166
|
end
|
171
167
|
|
@@ -177,7 +173,9 @@ module ActiveResource
|
|
177
173
|
|
178
174
|
def new_http
|
179
175
|
if @proxy
|
180
|
-
|
176
|
+
user = URI::DEFAULT_PARSER.unescape(@proxy.user) if @proxy.user
|
177
|
+
password = URI::DEFAULT_PARSER.unescape(@proxy.password) if @proxy.password
|
178
|
+
Net::HTTP.new(@site.host, @site.port, @proxy.host, @proxy.port, user, password)
|
181
179
|
else
|
182
180
|
Net::HTTP.new(@site.host, @site.port)
|
183
181
|
end
|
@@ -201,9 +199,6 @@ module ActiveResource
|
|
201
199
|
if defined? @ssl_options
|
202
200
|
http.use_ssl = true
|
203
201
|
|
204
|
-
# Default to no cert verification (WTF? FIXME)
|
205
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
206
|
-
|
207
202
|
# All the SSL options have corresponding http settings.
|
208
203
|
@ssl_options.each { |key, value| http.send "#{key}=", value }
|
209
204
|
end
|
@@ -228,7 +223,7 @@ module ActiveResource
|
|
228
223
|
yield
|
229
224
|
rescue UnauthorizedAccess => e
|
230
225
|
raise if retried || auth_type != :digest
|
231
|
-
@response_auth_header = e.response[
|
226
|
+
@response_auth_header = e.response["WWW-Authenticate"]
|
232
227
|
retried = true
|
233
228
|
retry
|
234
229
|
end
|
@@ -236,10 +231,12 @@ module ActiveResource
|
|
236
231
|
def authorization_header(http_method, uri)
|
237
232
|
if @user || @password
|
238
233
|
if auth_type == :digest
|
239
|
-
{
|
234
|
+
{ "Authorization" => digest_auth_header(http_method, uri) }
|
240
235
|
else
|
241
|
-
{
|
236
|
+
{ "Authorization" => "Basic " + ["#{@user}:#{@password}"].pack("m").delete("\r\n") }
|
242
237
|
end
|
238
|
+
elsif @bearer_token
|
239
|
+
{ "Authorization" => "Bearer #{@bearer_token}" }
|
243
240
|
else
|
244
241
|
{}
|
245
242
|
end
|
@@ -254,8 +251,8 @@ module ActiveResource
|
|
254
251
|
ha1 = Digest::MD5.hexdigest("#{@user}:#{params['realm']}:#{@password}")
|
255
252
|
ha2 = Digest::MD5.hexdigest("#{http_method.to_s.upcase}:#{request_uri}")
|
256
253
|
|
257
|
-
params
|
258
|
-
request_digest = Digest::MD5.hexdigest([ha1, params[
|
254
|
+
params["cnonce"] = client_nonce
|
255
|
+
request_digest = Digest::MD5.hexdigest([ha1, params["nonce"], "0", params["cnonce"], params["qop"], ha2].join(":"))
|
259
256
|
"Digest #{auth_attributes_for(uri, request_digest, params)}"
|
260
257
|
end
|
261
258
|
|
@@ -279,22 +276,22 @@ module ActiveResource
|
|
279
276
|
%Q(qop="#{params['qop']}"),
|
280
277
|
%Q(uri="#{uri.path}"),
|
281
278
|
%Q(nonce="#{params['nonce']}"),
|
282
|
-
|
279
|
+
'nc="0"',
|
283
280
|
%Q(cnonce="#{params['cnonce']}"),
|
284
281
|
%Q(response="#{request_digest}")]
|
285
282
|
|
286
|
-
auth_attrs << %Q(opaque="#{params['opaque']}") unless params[
|
283
|
+
auth_attrs << %Q(opaque="#{params['opaque']}") unless params["opaque"].blank?
|
287
284
|
auth_attrs.join(", ")
|
288
285
|
end
|
289
286
|
|
290
287
|
def http_format_header(http_method)
|
291
|
-
{HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type}
|
288
|
+
{ HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type }
|
292
289
|
end
|
293
290
|
|
294
291
|
def legitimize_auth_type(auth_type)
|
295
292
|
return :basic if auth_type.nil?
|
296
293
|
auth_type = auth_type.to_sym
|
297
|
-
auth_type.in?([:basic, :digest]) ? auth_type : :basic
|
294
|
+
auth_type.in?([:basic, :digest, :bearer]) ? auth_type : :basic
|
298
295
|
end
|
299
296
|
end
|
300
297
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/object/blank"
|
2
4
|
|
3
5
|
module ActiveResource
|
4
6
|
# A module to support custom REST methods and sub-resources, allowing you to break out
|
@@ -59,15 +61,15 @@ module ActiveResource
|
|
59
61
|
derooted.is_a?(Array) ? derooted.map { |e| Formats.remove_root(e) } : derooted
|
60
62
|
end
|
61
63
|
|
62
|
-
def post(custom_method_name, options = {}, body =
|
64
|
+
def post(custom_method_name, options = {}, body = "")
|
63
65
|
connection.post(custom_method_collection_url(custom_method_name, options), body, headers)
|
64
66
|
end
|
65
67
|
|
66
|
-
def patch(custom_method_name, options = {}, body =
|
68
|
+
def patch(custom_method_name, options = {}, body = "")
|
67
69
|
connection.patch(custom_method_collection_url(custom_method_name, options), body, headers)
|
68
70
|
end
|
69
71
|
|
70
|
-
def put(custom_method_name, options = {}, body =
|
72
|
+
def put(custom_method_name, options = {}, body = "")
|
71
73
|
connection.put(custom_method_collection_url(custom_method_name, options), body, headers)
|
72
74
|
end
|
73
75
|
|
@@ -102,11 +104,11 @@ module ActiveResource
|
|
102
104
|
end
|
103
105
|
end
|
104
106
|
|
105
|
-
def patch(method_name, options = {}, body =
|
107
|
+
def patch(method_name, options = {}, body = "")
|
106
108
|
connection.patch(custom_method_element_url(method_name, options), body, self.class.headers)
|
107
109
|
end
|
108
110
|
|
109
|
-
def put(method_name, options = {}, body =
|
111
|
+
def put(method_name, options = {}, body = "")
|
110
112
|
connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
|
111
113
|
end
|
112
114
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveResource
|
2
4
|
class ConnectionError < StandardError # :nodoc:
|
3
5
|
attr_reader :response
|
@@ -8,7 +10,9 @@ module ActiveResource
|
|
8
10
|
end
|
9
11
|
|
10
12
|
def to_s
|
11
|
-
message
|
13
|
+
return @message if @message
|
14
|
+
|
15
|
+
message = +"Failed."
|
12
16
|
message << " Response code = #{response.code}." if response.respond_to?(:code)
|
13
17
|
message << " Response message = #{response.message}." if response.respond_to?(:message)
|
14
18
|
message
|
@@ -20,7 +24,7 @@ module ActiveResource
|
|
20
24
|
def initialize(message)
|
21
25
|
@message = message
|
22
26
|
end
|
23
|
-
def to_s; @message ;end
|
27
|
+
def to_s; @message ; end
|
24
28
|
end
|
25
29
|
|
26
30
|
# Raised when a OpenSSL::SSL::SSLError occurs.
|
@@ -28,13 +32,13 @@ module ActiveResource
|
|
28
32
|
def initialize(message)
|
29
33
|
@message = message
|
30
34
|
end
|
31
|
-
def to_s; @message ;end
|
35
|
+
def to_s; @message ; end
|
32
36
|
end
|
33
37
|
|
34
38
|
# 3xx Redirection
|
35
39
|
class Redirection < ConnectionError # :nodoc:
|
36
40
|
def to_s
|
37
|
-
response[
|
41
|
+
response["Location"] ? "#{super} => #{response['Location']}" : super
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
@@ -69,6 +73,14 @@ module ActiveResource
|
|
69
73
|
class ResourceGone < ClientError # :nodoc:
|
70
74
|
end
|
71
75
|
|
76
|
+
# 412 Precondition Failed
|
77
|
+
class PreconditionFailed < ClientError # :nodoc:
|
78
|
+
end
|
79
|
+
|
80
|
+
# 429 Too Many Requests
|
81
|
+
class TooManyRequests < ClientError # :nodoc:
|
82
|
+
end
|
83
|
+
|
72
84
|
# 5xx Server Error
|
73
85
|
class ServerError < ConnectionError # :nodoc:
|
74
86
|
end
|
@@ -76,7 +88,7 @@ module ActiveResource
|
|
76
88
|
# 405 Method Not Allowed
|
77
89
|
class MethodNotAllowed < ClientError # :nodoc:
|
78
90
|
def allowed_methods
|
79
|
-
@response[
|
91
|
+
@response["Allow"].split(",").map { |verb| verb.strip.downcase.to_sym }
|
80
92
|
end
|
81
93
|
end
|
82
94
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/json"
|
2
4
|
|
3
5
|
module ActiveResource
|
4
6
|
module Formats
|
@@ -18,6 +20,7 @@ module ActiveResource
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def decode(json)
|
23
|
+
return nil if json.nil?
|
21
24
|
Formats.remove_root(ActiveSupport::JSON.decode(json))
|
22
25
|
end
|
23
26
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/conversions"
|
2
4
|
|
3
5
|
module ActiveResource
|
4
6
|
module Formats
|
@@ -13,7 +15,7 @@ module ActiveResource
|
|
13
15
|
"application/xml"
|
14
16
|
end
|
15
17
|
|
16
|
-
def encode(hash, options={})
|
18
|
+
def encode(hash, options = {})
|
17
19
|
hash.to_xml(options)
|
18
20
|
end
|
19
21
|
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveResource
|
2
4
|
module Formats
|
3
|
-
autoload :XmlFormat,
|
4
|
-
autoload :JsonFormat,
|
5
|
+
autoload :XmlFormat, "active_resource/formats/xml_format"
|
6
|
+
autoload :JsonFormat, "active_resource/formats/json_format"
|
5
7
|
|
6
8
|
# Lookup the format class from a mime type reference symbol. Example:
|
7
9
|
#
|
@@ -12,7 +14,7 @@ module ActiveResource
|
|
12
14
|
end
|
13
15
|
|
14
16
|
def self.remove_root(data)
|
15
|
-
if data.is_a?(Hash) && data.keys.size == 1
|
17
|
+
if data.is_a?(Hash) && data.keys.size == 1 && data.values.first.is_a?(Enumerable)
|
16
18
|
data.values.first
|
17
19
|
else
|
18
20
|
data
|
@@ -1,8 +1,10 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/kernel/reporting"
|
4
|
+
require "active_support/core_ext/object/inclusion"
|
3
5
|
|
4
6
|
module ActiveResource
|
5
|
-
class InvalidRequestError < StandardError; end
|
7
|
+
class InvalidRequestError < StandardError; end # :nodoc:
|
6
8
|
|
7
9
|
# One thing that has always been a pain with remote web services is testing. The HttpMock
|
8
10
|
# class makes it easy to test your Active Resource models by creating a set of mock responses to specific
|
@@ -50,7 +52,7 @@ module ActiveResource
|
|
50
52
|
# end
|
51
53
|
#
|
52
54
|
class HttpMock
|
53
|
-
class Responder
|
55
|
+
class Responder # :nodoc:
|
54
56
|
def initialize(responses)
|
55
57
|
@responses = responses
|
56
58
|
end
|
@@ -72,14 +74,12 @@ module ActiveResource
|
|
72
74
|
end
|
73
75
|
|
74
76
|
private
|
75
|
-
|
76
77
|
def delete_duplicate_responses(request)
|
77
|
-
@responses.delete_if {|r| r[0] == request }
|
78
|
+
@responses.delete_if { |r| r[0] == request }
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
81
82
|
class << self
|
82
|
-
|
83
83
|
# Returns an array of all request objects that have been sent to the mock. You can use this to check
|
84
84
|
# if your model actually sent an HTTP request.
|
85
85
|
#
|
@@ -189,7 +189,7 @@ module ActiveResource
|
|
189
189
|
# ActiveResource::HttpMock.respond_to(pairs, false)
|
190
190
|
# ActiveResource::HttpMock.responses.length #=> 2
|
191
191
|
#
|
192
|
-
def respond_to(*args)
|
192
|
+
def respond_to(*args) # :yields: mock
|
193
193
|
pairs = args.first || {}
|
194
194
|
reset! if args.last.class != FalseClass
|
195
195
|
|
@@ -203,9 +203,9 @@ module ActiveResource
|
|
203
203
|
end
|
204
204
|
|
205
205
|
def delete_responses_to_replace(new_responses)
|
206
|
-
new_responses.each{|nr|
|
206
|
+
new_responses.each { |nr|
|
207
207
|
request_to_remove = nr[0]
|
208
|
-
@@responses = responses.delete_if{|r| r[0] == request_to_remove}
|
208
|
+
@@responses = responses.delete_if { |r| r[0] == request_to_remove }
|
209
209
|
}
|
210
210
|
end
|
211
211
|
|
@@ -238,7 +238,6 @@ module ActiveResource
|
|
238
238
|
def net_connection_disabled?
|
239
239
|
!net_connection_enabled?
|
240
240
|
end
|
241
|
-
|
242
241
|
end
|
243
242
|
|
244
243
|
# body? methods
|
@@ -268,11 +267,11 @@ module ActiveResource
|
|
268
267
|
end
|
269
268
|
end
|
270
269
|
|
271
|
-
def initialize(site)
|
270
|
+
def initialize(site) # :nodoc:
|
272
271
|
@site = site
|
273
272
|
end
|
274
273
|
|
275
|
-
def inspect_responses
|
274
|
+
def inspect_responses # :nodoc:
|
276
275
|
self.class.responses.map { |r| r[0].to_s }.inspect
|
277
276
|
end
|
278
277
|
end
|
@@ -293,16 +292,15 @@ module ActiveResource
|
|
293
292
|
end
|
294
293
|
|
295
294
|
private
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
295
|
+
def headers_match?(req)
|
296
|
+
# Ignore format header on equality if it's not defined
|
297
|
+
format_header = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[method]
|
298
|
+
if headers[format_header].present? || req.headers[format_header].blank?
|
299
|
+
headers == req.headers
|
300
|
+
else
|
301
|
+
headers.dup.merge(format_header => req.headers[format_header]) == req.headers
|
302
|
+
end
|
304
303
|
end
|
305
|
-
end
|
306
304
|
end
|
307
305
|
|
308
306
|
class Response
|
@@ -310,15 +308,14 @@ module ActiveResource
|
|
310
308
|
|
311
309
|
def initialize(body, message = 200, headers = {})
|
312
310
|
@body, @message, @headers = body, message.to_s, headers
|
313
|
-
@code = @message[0,3].to_i
|
311
|
+
@code = @message[0, 3].to_i
|
314
312
|
|
315
313
|
resp_cls = Net::HTTPResponse::CODE_TO_OBJ[@code.to_s]
|
316
314
|
if resp_cls && !resp_cls.body_permitted?
|
317
315
|
@body = nil
|
318
316
|
end
|
319
317
|
|
320
|
-
self[
|
321
|
-
|
318
|
+
self["Content-Length"] = @body.nil? ? "0" : body.size.to_s
|
322
319
|
end
|
323
320
|
|
324
321
|
# Returns true if code is 2xx,
|
@@ -338,7 +335,7 @@ module ActiveResource
|
|
338
335
|
# Returns true if the other is a Response with an equal body, equal message
|
339
336
|
# and equal headers. Otherwise it returns false.
|
340
337
|
def ==(other)
|
341
|
-
if
|
338
|
+
if other.is_a?(Response)
|
342
339
|
other.body == body && other.message == message && other.headers == headers
|
343
340
|
else
|
344
341
|
false
|
@@ -369,7 +366,6 @@ module ActiveResource
|
|
369
366
|
def stub_http?
|
370
367
|
HttpMock.net_connection_disabled? && defined?(@http) && @http.kind_of?(Net::HTTP)
|
371
368
|
end
|
372
|
-
|
373
369
|
end
|
374
370
|
end
|
375
371
|
end
|