activeresource 4.1.0 → 6.0.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 +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
|