activeresource 2.1.2 → 2.2.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activeresource might be problematic. Click here for more details.
- data/CHANGELOG +9 -3
- data/README +1 -1
- data/Rakefile +3 -4
- data/lib/active_resource.rb +7 -10
- data/lib/active_resource/base.rb +170 -117
- data/lib/active_resource/connection.rb +27 -16
- data/lib/active_resource/custom_methods.rb +14 -13
- data/lib/active_resource/formats/json_format.rb +7 -7
- data/lib/active_resource/formats/xml_format.rb +9 -9
- data/lib/active_resource/http_mock.rb +2 -2
- data/lib/active_resource/validations.rb +15 -29
- data/lib/active_resource/version.rb +1 -1
- data/test/authorization_test.rb +8 -8
- data/test/base/custom_methods_test.rb +3 -2
- data/test/base/load_test.rb +2 -2
- data/test/base_test.rb +80 -50
- data/test/connection_test.rb +11 -3
- data/test/format_test.rb +40 -11
- metadata +4 -4
@@ -28,24 +28,24 @@ module ActiveResource
|
|
28
28
|
|
29
29
|
# 3xx Redirection
|
30
30
|
class Redirection < ConnectionError # :nodoc:
|
31
|
-
def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end
|
32
|
-
end
|
31
|
+
def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end
|
32
|
+
end
|
33
33
|
|
34
34
|
# 4xx Client Error
|
35
35
|
class ClientError < ConnectionError; end # :nodoc:
|
36
|
-
|
36
|
+
|
37
37
|
# 400 Bad Request
|
38
38
|
class BadRequest < ClientError; end # :nodoc
|
39
|
-
|
39
|
+
|
40
40
|
# 401 Unauthorized
|
41
41
|
class UnauthorizedAccess < ClientError; end # :nodoc
|
42
|
-
|
42
|
+
|
43
43
|
# 403 Forbidden
|
44
44
|
class ForbiddenAccess < ClientError; end # :nodoc
|
45
|
-
|
45
|
+
|
46
46
|
# 404 Not Found
|
47
47
|
class ResourceNotFound < ClientError; end # :nodoc:
|
48
|
-
|
48
|
+
|
49
49
|
# 409 Conflict
|
50
50
|
class ResourceConflict < ClientError; end # :nodoc:
|
51
51
|
|
@@ -63,6 +63,13 @@ module ActiveResource
|
|
63
63
|
# This class is used by ActiveResource::Base to interface with REST
|
64
64
|
# services.
|
65
65
|
class Connection
|
66
|
+
|
67
|
+
HTTP_FORMAT_HEADER_NAMES = { :get => 'Accept',
|
68
|
+
:put => 'Content-Type',
|
69
|
+
:post => 'Content-Type',
|
70
|
+
:delete => 'Accept'
|
71
|
+
}
|
72
|
+
|
66
73
|
attr_reader :site, :user, :password, :timeout
|
67
74
|
attr_accessor :format
|
68
75
|
|
@@ -106,25 +113,25 @@ module ActiveResource
|
|
106
113
|
# Execute a GET request.
|
107
114
|
# Used to get (find) resources.
|
108
115
|
def get(path, headers = {})
|
109
|
-
format.decode(request(:get, path, build_request_headers(headers)).body)
|
116
|
+
format.decode(request(:get, path, build_request_headers(headers, :get)).body)
|
110
117
|
end
|
111
118
|
|
112
119
|
# Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
|
113
120
|
# Used to delete resources.
|
114
121
|
def delete(path, headers = {})
|
115
|
-
request(:delete, path, build_request_headers(headers))
|
122
|
+
request(:delete, path, build_request_headers(headers, :delete))
|
116
123
|
end
|
117
124
|
|
118
125
|
# Execute a PUT request (see HTTP protocol documentation if unfamiliar).
|
119
126
|
# Used to update resources.
|
120
127
|
def put(path, body = '', headers = {})
|
121
|
-
request(:put, path, body.to_s, build_request_headers(headers))
|
128
|
+
request(:put, path, body.to_s, build_request_headers(headers, :put))
|
122
129
|
end
|
123
130
|
|
124
131
|
# Execute a POST request.
|
125
132
|
# Used to create new resources.
|
126
133
|
def post(path, body = '', headers = {})
|
127
|
-
request(:post, path, body.to_s, build_request_headers(headers))
|
134
|
+
request(:post, path, body.to_s, build_request_headers(headers, :post))
|
128
135
|
end
|
129
136
|
|
130
137
|
# Execute a HEAD request.
|
@@ -140,7 +147,7 @@ module ActiveResource
|
|
140
147
|
logger.info "#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}" if logger
|
141
148
|
result = nil
|
142
149
|
time = Benchmark.realtime { result = http.send(method, path, *arguments) }
|
143
|
-
logger.info "-->
|
150
|
+
logger.info "--> %d %s (%d %.2fs)" % [result.code, result.message, result.body ? result.body.length : 0, time] if logger
|
144
151
|
handle_response(result)
|
145
152
|
rescue Timeout::Error => e
|
146
153
|
raise TimeoutError.new(e.message)
|
@@ -187,12 +194,12 @@ module ActiveResource
|
|
187
194
|
end
|
188
195
|
|
189
196
|
def default_header
|
190
|
-
@default_header ||= {
|
197
|
+
@default_header ||= {}
|
191
198
|
end
|
192
199
|
|
193
200
|
# Builds headers for request to remote service.
|
194
|
-
def build_request_headers(headers)
|
195
|
-
authorization_header.update(default_header).update(headers)
|
201
|
+
def build_request_headers(headers, http_method=nil)
|
202
|
+
authorization_header.update(default_header).update(http_format_header(http_method)).update(headers)
|
196
203
|
end
|
197
204
|
|
198
205
|
# Sets authorization header
|
@@ -200,8 +207,12 @@ module ActiveResource
|
|
200
207
|
(@user || @password ? { 'Authorization' => 'Basic ' + ["#{@user}:#{ @password}"].pack('m').delete("\r\n") } : {})
|
201
208
|
end
|
202
209
|
|
210
|
+
def http_format_header(http_method)
|
211
|
+
{HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type}
|
212
|
+
end
|
213
|
+
|
203
214
|
def logger #:nodoc:
|
204
|
-
|
215
|
+
Base.logger
|
205
216
|
end
|
206
217
|
end
|
207
218
|
end
|
@@ -30,7 +30,7 @@ module ActiveResource
|
|
30
30
|
# Person.get(:active) # GET /people/active.xml
|
31
31
|
# # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
|
32
32
|
#
|
33
|
-
module CustomMethods
|
33
|
+
module CustomMethods
|
34
34
|
def self.included(base)
|
35
35
|
base.class_eval do
|
36
36
|
extend ActiveResource::CustomMethods::ClassMethods
|
@@ -48,8 +48,8 @@ module ActiveResource
|
|
48
48
|
# # => [{:id => 1, :name => 'Ryan'}]
|
49
49
|
#
|
50
50
|
# Note: the objects returned from this method are not automatically converted
|
51
|
-
# into
|
52
|
-
#
|
51
|
+
# into ActiveResource::Base instances - they are ordinary Hashes. If you are expecting
|
52
|
+
# ActiveResource::Base instances, use the <tt>find</tt> class method with the
|
53
53
|
# <tt>:from</tt> option. For example:
|
54
54
|
#
|
55
55
|
# Person.find(:all, :from => :active)
|
@@ -83,24 +83,25 @@ module ActiveResource
|
|
83
83
|
"#{prefix(prefix_options)}#{collection_name}/#{method_name}.#{format.extension}#{query_string(query_options)}"
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
module InstanceMethods
|
88
88
|
def get(method_name, options = {})
|
89
89
|
connection.get(custom_method_element_url(method_name, options), self.class.headers)
|
90
90
|
end
|
91
|
-
|
92
|
-
def post(method_name, options = {}, body =
|
91
|
+
|
92
|
+
def post(method_name, options = {}, body = nil)
|
93
|
+
request_body = body.blank? ? encode : body
|
93
94
|
if new?
|
94
|
-
connection.post(custom_method_new_element_url(method_name, options),
|
95
|
+
connection.post(custom_method_new_element_url(method_name, options), request_body, self.class.headers)
|
95
96
|
else
|
96
|
-
connection.post(custom_method_element_url(method_name, options),
|
97
|
+
connection.post(custom_method_element_url(method_name, options), request_body, self.class.headers)
|
97
98
|
end
|
98
99
|
end
|
99
|
-
|
100
|
+
|
100
101
|
def put(method_name, options = {}, body = '')
|
101
102
|
connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
|
102
103
|
end
|
103
|
-
|
104
|
+
|
104
105
|
def delete(method_name, options = {})
|
105
106
|
connection.delete(custom_method_element_url(method_name, options), self.class.headers)
|
106
107
|
end
|
@@ -108,11 +109,11 @@ module ActiveResource
|
|
108
109
|
|
109
110
|
private
|
110
111
|
def custom_method_element_url(method_name, options = {})
|
111
|
-
"#{self.class.prefix(prefix_options)}#{self.class.collection_name}/#{id}/#{method_name}.#{self.class.format.extension}#{self.class.
|
112
|
+
"#{self.class.prefix(prefix_options)}#{self.class.collection_name}/#{id}/#{method_name}.#{self.class.format.extension}#{self.class.__send__(:query_string, options)}"
|
112
113
|
end
|
113
|
-
|
114
|
+
|
114
115
|
def custom_method_new_element_url(method_name, options = {})
|
115
|
-
"#{self.class.prefix(prefix_options)}#{self.class.collection_name}/new/#{method_name}.#{self.class.format.extension}#{self.class.
|
116
|
+
"#{self.class.prefix(prefix_options)}#{self.class.collection_name}/new/#{method_name}.#{self.class.format.extension}#{self.class.__send__(:query_string, options)}"
|
116
117
|
end
|
117
118
|
end
|
118
119
|
end
|
@@ -2,22 +2,22 @@ module ActiveResource
|
|
2
2
|
module Formats
|
3
3
|
module JsonFormat
|
4
4
|
extend self
|
5
|
-
|
5
|
+
|
6
6
|
def extension
|
7
7
|
"json"
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def mime_type
|
11
11
|
"application/json"
|
12
12
|
end
|
13
|
-
|
14
|
-
def encode(hash)
|
15
|
-
hash.to_json
|
13
|
+
|
14
|
+
def encode(hash, options={})
|
15
|
+
hash.to_json(options)
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def decode(json)
|
19
19
|
ActiveSupport::JSON.decode(json)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
|
-
end
|
23
|
+
end
|
@@ -2,23 +2,23 @@ module ActiveResource
|
|
2
2
|
module Formats
|
3
3
|
module XmlFormat
|
4
4
|
extend self
|
5
|
-
|
5
|
+
|
6
6
|
def extension
|
7
7
|
"xml"
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def mime_type
|
11
11
|
"application/xml"
|
12
12
|
end
|
13
|
-
|
14
|
-
def encode(hash)
|
15
|
-
hash.to_xml
|
13
|
+
|
14
|
+
def encode(hash, options={})
|
15
|
+
hash.to_xml(options)
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def decode(xml)
|
19
19
|
from_xml_data(Hash.from_xml(xml))
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
private
|
23
23
|
# Manipulate from_xml Hash, because xml_simple is not exactly what we
|
24
24
|
# want for Active Resource.
|
@@ -28,7 +28,7 @@ module ActiveResource
|
|
28
28
|
else
|
29
29
|
data
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
32
32
|
end
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
@@ -65,7 +65,7 @@ module ActiveResource
|
|
65
65
|
class << self
|
66
66
|
|
67
67
|
# Returns an array of all request objects that have been sent to the mock. You can use this to check
|
68
|
-
#
|
68
|
+
# if your model actually sent an HTTP request.
|
69
69
|
#
|
70
70
|
# ==== Example
|
71
71
|
# def setup
|
@@ -146,7 +146,7 @@ module ActiveResource
|
|
146
146
|
attr_accessor :path, :method, :body, :headers
|
147
147
|
|
148
148
|
def initialize(method, path, body = nil, headers = {})
|
149
|
-
@method, @path, @body, @headers = method, path, body, headers.
|
149
|
+
@method, @path, @body, @headers = method, path, body, headers.merge(ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[method] => 'application/xml')
|
150
150
|
end
|
151
151
|
|
152
152
|
def ==(other_request)
|
@@ -216,39 +216,25 @@ module ActiveResource
|
|
216
216
|
end
|
217
217
|
end
|
218
218
|
|
219
|
-
# Module to
|
220
|
-
#
|
221
|
-
# the
|
222
|
-
#
|
219
|
+
# Module to support validation and errors with Active Resource objects. The module overrides
|
220
|
+
# Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned
|
221
|
+
# in the web service response. The module also adds an +errors+ collection that mimics the interface
|
222
|
+
# of the errors provided by ActiveRecord::Errors.
|
223
223
|
#
|
224
224
|
# ==== Example
|
225
225
|
#
|
226
|
-
#
|
227
|
-
#
|
228
|
-
# protected
|
229
|
-
# def validate
|
230
|
-
# errors.add_on_empty %w( first_name last_name )
|
231
|
-
# errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/
|
232
|
-
# end
|
226
|
+
# Consider a Person resource on the server requiring both a +first_name+ and a +last_name+ with a
|
227
|
+
# <tt>validates_presence_of :first_name, :last_name</tt> declaration in the model:
|
233
228
|
#
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
#
|
243
|
-
# end
|
244
|
-
#
|
245
|
-
# person = Person.new("first_name" => "Jim", "phone_number" => "I will not tell you.")
|
246
|
-
# person.save # => false (and doesn't do the save)
|
247
|
-
# person.errors.empty? # => false
|
248
|
-
# person.errors.count # => 2
|
249
|
-
# person.errors.on "last_name" # => "can't be empty"
|
250
|
-
# person.attributes = { "last_name" => "Halpert", "phone_number" => "555-5555" }
|
251
|
-
# person.save # => true (and person is now saved to the remote service)
|
229
|
+
# person = Person.new(:first_name => "Jim", :last_name => "")
|
230
|
+
# person.save # => false (server returns an HTTP 422 status code and errors)
|
231
|
+
# person.valid? # => false
|
232
|
+
# person.errors.empty? # => false
|
233
|
+
# person.errors.count # => 1
|
234
|
+
# person.errors.full_messages # => ["Last name can't be empty"]
|
235
|
+
# person.errors.on(:last_name) # => "can't be empty"
|
236
|
+
# person.last_name = "Halpert"
|
237
|
+
# person.save # => true (and person is now saved to the remote service)
|
252
238
|
#
|
253
239
|
module Validations
|
254
240
|
def self.included(base) # :nodoc:
|
data/test/authorization_test.rb
CHANGED
@@ -19,7 +19,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_authorization_header
|
22
|
-
authorization_header = @authenticated_conn.
|
22
|
+
authorization_header = @authenticated_conn.__send__(:authorization_header)
|
23
23
|
assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization']
|
24
24
|
authorization = authorization_header["Authorization"].to_s.split
|
25
25
|
|
@@ -29,7 +29,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
29
29
|
|
30
30
|
def test_authorization_header_with_username_but_no_password
|
31
31
|
@conn = ActiveResource::Connection.new("http://david:@localhost")
|
32
|
-
authorization_header = @conn.
|
32
|
+
authorization_header = @conn.__send__(:authorization_header)
|
33
33
|
authorization = authorization_header["Authorization"].to_s.split
|
34
34
|
|
35
35
|
assert_equal "Basic", authorization[0]
|
@@ -38,7 +38,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
38
38
|
|
39
39
|
def test_authorization_header_with_password_but_no_username
|
40
40
|
@conn = ActiveResource::Connection.new("http://:test123@localhost")
|
41
|
-
authorization_header = @conn.
|
41
|
+
authorization_header = @conn.__send__(:authorization_header)
|
42
42
|
authorization = authorization_header["Authorization"].to_s.split
|
43
43
|
|
44
44
|
assert_equal "Basic", authorization[0]
|
@@ -47,7 +47,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
47
47
|
|
48
48
|
def test_authorization_header_with_decoded_credentials_from_url
|
49
49
|
@conn = ActiveResource::Connection.new("http://my%40email.com:%31%32%33@localhost")
|
50
|
-
authorization_header = @conn.
|
50
|
+
authorization_header = @conn.__send__(:authorization_header)
|
51
51
|
authorization = authorization_header["Authorization"].to_s.split
|
52
52
|
|
53
53
|
assert_equal "Basic", authorization[0]
|
@@ -58,7 +58,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
58
58
|
@authenticated_conn = ActiveResource::Connection.new("http://@localhost")
|
59
59
|
@authenticated_conn.user = 'david'
|
60
60
|
@authenticated_conn.password = 'test123'
|
61
|
-
authorization_header = @authenticated_conn.
|
61
|
+
authorization_header = @authenticated_conn.__send__(:authorization_header)
|
62
62
|
assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization']
|
63
63
|
authorization = authorization_header["Authorization"].to_s.split
|
64
64
|
|
@@ -69,7 +69,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
69
69
|
def test_authorization_header_explicitly_setting_username_but_no_password
|
70
70
|
@conn = ActiveResource::Connection.new("http://@localhost")
|
71
71
|
@conn.user = "david"
|
72
|
-
authorization_header = @conn.
|
72
|
+
authorization_header = @conn.__send__(:authorization_header)
|
73
73
|
authorization = authorization_header["Authorization"].to_s.split
|
74
74
|
|
75
75
|
assert_equal "Basic", authorization[0]
|
@@ -79,7 +79,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
79
79
|
def test_authorization_header_explicitly_setting_password_but_no_username
|
80
80
|
@conn = ActiveResource::Connection.new("http://@localhost")
|
81
81
|
@conn.password = "test123"
|
82
|
-
authorization_header = @conn.
|
82
|
+
authorization_header = @conn.__send__(:authorization_header)
|
83
83
|
authorization = authorization_header["Authorization"].to_s.split
|
84
84
|
|
85
85
|
assert_equal "Basic", authorization[0]
|
@@ -116,7 +116,7 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
116
116
|
protected
|
117
117
|
def assert_response_raises(klass, code)
|
118
118
|
assert_raise(klass, "Expected response code #{code} to raise #{klass}") do
|
119
|
-
@conn.
|
119
|
+
@conn.__send__(:handle_response, Response.new(code))
|
120
120
|
end
|
121
121
|
end
|
122
122
|
end
|
@@ -10,8 +10,7 @@ class CustomMethodsTest < Test::Unit::TestCase
|
|
10
10
|
@ryan = { :name => 'Ryan' }.to_xml(:root => 'person')
|
11
11
|
@addy = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address')
|
12
12
|
@addy_deep = { :id => 1, :street => '12345 Street', :zip => "27519" }.to_xml(:root => 'address')
|
13
|
-
|
14
|
-
|
13
|
+
|
15
14
|
ActiveResource::HttpMock.respond_to do |mock|
|
16
15
|
mock.get "/people/1.xml", {}, @matz
|
17
16
|
mock.get "/people/1/shallow.xml", {}, @matz
|
@@ -82,6 +81,8 @@ class CustomMethodsTest < Test::Unit::TestCase
|
|
82
81
|
# Test POST against a new element URL
|
83
82
|
ryan = Person.new(:name => 'Ryan')
|
84
83
|
assert_equal ActiveResource::Response.new(@ryan, 201, {'Location' => '/people/5.xml'}), ryan.post(:register)
|
84
|
+
expected_request = ActiveResource::Request.new(:post, '/people/new/register.xml', @ryan)
|
85
|
+
assert_equal expected_request.body, ActiveResource::HttpMock.requests.first.body
|
85
86
|
|
86
87
|
# Test POST against a nested collection URL
|
87
88
|
addy = StreetAddress.new(:street => '123 Test Dr.', :person_id => 1)
|
data/test/base/load_test.rb
CHANGED
@@ -84,7 +84,7 @@ class BaseLoadTest < Test::Unit::TestCase
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def test_load_collection_with_unknown_resource
|
87
|
-
Person.
|
87
|
+
Person.__send__(:remove_const, :Address) if Person.const_defined?(:Address)
|
88
88
|
assert !Person.const_defined?(:Address), "Address shouldn't exist until autocreated"
|
89
89
|
addresses = silence_warnings { @person.load(:addresses => @addresses).addresses }
|
90
90
|
assert Person.const_defined?(:Address), "Address should have been autocreated"
|
@@ -100,7 +100,7 @@ class BaseLoadTest < Test::Unit::TestCase
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def test_load_collection_with_single_unknown_resource
|
103
|
-
Person.
|
103
|
+
Person.__send__(:remove_const, :Address) if Person.const_defined?(:Address)
|
104
104
|
assert !Person.const_defined?(:Address), "Address shouldn't exist until autocreated"
|
105
105
|
addresses = silence_warnings { @person.load(:addresses => [ @first_address ]).addresses }
|
106
106
|
assert Person.const_defined?(:Address), "Address should have been autocreated"
|
data/test/base_test.rb
CHANGED
@@ -8,7 +8,7 @@ class BaseTest < Test::Unit::TestCase
|
|
8
8
|
def setup
|
9
9
|
@matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
|
10
10
|
@david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
|
11
|
-
@greg = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')
|
11
|
+
@greg = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')
|
12
12
|
@addy = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address')
|
13
13
|
@default_request_headers = { 'Content-Type' => 'application/xml' }
|
14
14
|
@rick = { :name => "Rick", :age => 25 }.to_xml(:root => "person")
|
@@ -46,11 +46,25 @@ class BaseTest < Test::Unit::TestCase
|
|
46
46
|
:children => [{:name => 'Natacha'}]},
|
47
47
|
{:name => 'Milena',
|
48
48
|
:children => []}]}]}.to_xml(:root => 'customer')
|
49
|
+
# - resource with yaml array of strings; for ActiveRecords using serialize :bar, Array
|
50
|
+
@marty = <<-eof
|
51
|
+
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
52
|
+
<person>
|
53
|
+
<id type=\"integer\">5</id>
|
54
|
+
<name>Marty</name>
|
55
|
+
<colors type=\"yaml\">---
|
56
|
+
- \"red\"
|
57
|
+
- \"green\"
|
58
|
+
- \"blue\"
|
59
|
+
</colors>
|
60
|
+
</person>
|
61
|
+
eof
|
49
62
|
|
50
63
|
ActiveResource::HttpMock.respond_to do |mock|
|
51
64
|
mock.get "/people/1.xml", {}, @matz
|
52
65
|
mock.get "/people/2.xml", {}, @david
|
53
|
-
mock.get "/people/
|
66
|
+
mock.get "/people/5.xml", {}, @marty
|
67
|
+
mock.get "/people/Greg.xml", {}, @greg
|
54
68
|
mock.get "/people/4.xml", {'key' => 'value'}, nil, 404
|
55
69
|
mock.put "/people/1.xml", {}, nil, 204
|
56
70
|
mock.delete "/people/1.xml", {}, nil, 200
|
@@ -62,7 +76,7 @@ class BaseTest < Test::Unit::TestCase
|
|
62
76
|
mock.get "/people/1/addresses/1.xml", {}, @addy
|
63
77
|
mock.get "/people/1/addresses/2.xml", {}, nil, 404
|
64
78
|
mock.get "/people/2/addresses/1.xml", {}, nil, 404
|
65
|
-
mock.get "/people/Greg/addresses/1.xml", {}, @addy
|
79
|
+
mock.get "/people/Greg/addresses/1.xml", {}, @addy
|
66
80
|
mock.put "/people/1/addresses/1.xml", {}, nil, 204
|
67
81
|
mock.delete "/people/1/addresses/1.xml", {}, nil, 200
|
68
82
|
mock.post "/people/1/addresses.xml", {}, nil, 201, 'Location' => '/people/1/addresses/5'
|
@@ -101,13 +115,13 @@ class BaseTest < Test::Unit::TestCase
|
|
101
115
|
assert_equal 'http://foo:bar@beast.caboo.se', Forum.site.to_s
|
102
116
|
assert_equal 'http://foo:bar@beast.caboo.se/forums/:forum_id', Topic.site.to_s
|
103
117
|
end
|
104
|
-
|
118
|
+
|
105
119
|
def test_site_variable_can_be_reset
|
106
|
-
actor = Class.new(ActiveResource::Base)
|
120
|
+
actor = Class.new(ActiveResource::Base)
|
107
121
|
assert_nil actor.site
|
108
122
|
actor.site = 'http://localhost:31337'
|
109
123
|
actor.site = nil
|
110
|
-
assert_nil actor.site
|
124
|
+
assert_nil actor.site
|
111
125
|
end
|
112
126
|
|
113
127
|
def test_should_accept_setting_user
|
@@ -194,18 +208,18 @@ class BaseTest < Test::Unit::TestCase
|
|
194
208
|
actor.site = 'http://nomad'
|
195
209
|
assert_equal actor.site, jester.site
|
196
210
|
assert jester.site.frozen?
|
197
|
-
|
198
|
-
# Subclasses are always equal to superclass site when not overridden
|
211
|
+
|
212
|
+
# Subclasses are always equal to superclass site when not overridden
|
199
213
|
fruit = Class.new(ActiveResource::Base)
|
200
214
|
apple = Class.new(fruit)
|
201
|
-
|
215
|
+
|
202
216
|
fruit.site = 'http://market'
|
203
217
|
assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
|
204
|
-
|
218
|
+
|
205
219
|
fruit.site = 'http://supermarket'
|
206
220
|
assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
|
207
221
|
end
|
208
|
-
|
222
|
+
|
209
223
|
def test_user_reader_uses_superclass_user_until_written
|
210
224
|
# Superclass is Object so returns nil.
|
211
225
|
assert_nil ActiveResource::Base.user
|
@@ -317,14 +331,14 @@ class BaseTest < Test::Unit::TestCase
|
|
317
331
|
end
|
318
332
|
|
319
333
|
def test_updating_baseclass_site_object_wipes_descendent_cached_connection_objects
|
320
|
-
# Subclasses are always equal to superclass site when not overridden
|
334
|
+
# Subclasses are always equal to superclass site when not overridden
|
321
335
|
fruit = Class.new(ActiveResource::Base)
|
322
336
|
apple = Class.new(fruit)
|
323
|
-
|
337
|
+
|
324
338
|
fruit.site = 'http://market'
|
325
339
|
assert_equal fruit.connection.site, apple.connection.site
|
326
340
|
first_connection = apple.connection.object_id
|
327
|
-
|
341
|
+
|
328
342
|
fruit.site = 'http://supermarket'
|
329
343
|
assert_equal fruit.connection.site, apple.connection.site
|
330
344
|
second_connection = apple.connection.object_id
|
@@ -393,34 +407,34 @@ class BaseTest < Test::Unit::TestCase
|
|
393
407
|
assert_equal '/people.xml?gender=', Person.collection_path(:gender => nil)
|
394
408
|
|
395
409
|
assert_equal '/people.xml?gender=male', Person.collection_path('gender' => 'male')
|
396
|
-
|
410
|
+
|
397
411
|
# Use includes? because ordering of param hash is not guaranteed
|
398
412
|
assert Person.collection_path(:gender => 'male', :student => true).include?('/people.xml?')
|
399
413
|
assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male')
|
400
414
|
assert Person.collection_path(:gender => 'male', :student => true).include?('student=true')
|
401
415
|
|
402
416
|
assert_equal '/people.xml?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false])
|
403
|
-
|
417
|
+
|
404
418
|
assert_equal '/people.xml?struct%5Ba%5D%5B%5D=2&struct%5Ba%5D%5B%5D=1&struct%5Bb%5D=fred', Person.collection_path(:struct => {:a => [2,1], 'b' => 'fred'})
|
405
419
|
end
|
406
420
|
|
407
421
|
def test_custom_element_path
|
408
422
|
assert_equal '/people/1/addresses/1.xml', StreetAddress.element_path(1, :person_id => 1)
|
409
423
|
assert_equal '/people/1/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 1)
|
410
|
-
assert_equal '/people/Greg/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 'Greg')
|
424
|
+
assert_equal '/people/Greg/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 'Greg')
|
411
425
|
end
|
412
|
-
|
426
|
+
|
413
427
|
def test_custom_element_path_with_redefined_to_param
|
414
428
|
Person.module_eval do
|
415
429
|
alias_method :original_to_param_element_path, :to_param
|
416
|
-
def to_param
|
430
|
+
def to_param
|
417
431
|
name
|
418
432
|
end
|
419
433
|
end
|
420
434
|
|
421
435
|
# Class method.
|
422
436
|
assert_equal '/people/Greg.xml', Person.element_path('Greg')
|
423
|
-
|
437
|
+
|
424
438
|
# Protected Instance method.
|
425
439
|
assert_equal '/people/Greg.xml', Person.find('Greg').send(:element_path)
|
426
440
|
|
@@ -468,16 +482,16 @@ class BaseTest < Test::Unit::TestCase
|
|
468
482
|
|
469
483
|
def test_prefix
|
470
484
|
assert_equal "/", Person.prefix
|
471
|
-
assert_equal Set.new, Person.
|
485
|
+
assert_equal Set.new, Person.__send__(:prefix_parameters)
|
472
486
|
end
|
473
|
-
|
487
|
+
|
474
488
|
def test_set_prefix
|
475
489
|
SetterTrap.rollback_sets(Person) do |person_class|
|
476
490
|
person_class.prefix = "the_prefix"
|
477
491
|
assert_equal "the_prefix", person_class.prefix
|
478
492
|
end
|
479
493
|
end
|
480
|
-
|
494
|
+
|
481
495
|
def test_set_prefix_with_inline_keys
|
482
496
|
SetterTrap.rollback_sets(Person) do |person_class|
|
483
497
|
person_class.prefix = "the_prefix:the_param"
|
@@ -504,7 +518,7 @@ class BaseTest < Test::Unit::TestCase
|
|
504
518
|
def test_custom_prefix
|
505
519
|
assert_equal '/people//', StreetAddress.prefix
|
506
520
|
assert_equal '/people/1/', StreetAddress.prefix(:person_id => 1)
|
507
|
-
assert_equal [:person_id].to_set, StreetAddress.
|
521
|
+
assert_equal [:person_id].to_set, StreetAddress.__send__(:prefix_parameters)
|
508
522
|
end
|
509
523
|
|
510
524
|
def test_find_by_id
|
@@ -513,7 +527,7 @@ class BaseTest < Test::Unit::TestCase
|
|
513
527
|
assert_equal "Matz", matz.name
|
514
528
|
assert matz.name?
|
515
529
|
end
|
516
|
-
|
530
|
+
|
517
531
|
def test_respond_to
|
518
532
|
matz = Person.find(1)
|
519
533
|
assert matz.respond_to?(:name)
|
@@ -542,6 +556,12 @@ class BaseTest < Test::Unit::TestCase
|
|
542
556
|
assert_equal "Matz", matz.name
|
543
557
|
end
|
544
558
|
|
559
|
+
def test_find_last
|
560
|
+
david = Person.find(:last)
|
561
|
+
assert_kind_of Person, david
|
562
|
+
assert_equal 'David', david.name
|
563
|
+
end
|
564
|
+
|
545
565
|
def test_custom_header
|
546
566
|
Person.headers['key'] = 'value'
|
547
567
|
assert_raises(ActiveResource::ResourceNotFound) { Person.find(4) }
|
@@ -556,7 +576,7 @@ class BaseTest < Test::Unit::TestCase
|
|
556
576
|
|
557
577
|
def test_find_all_by_from
|
558
578
|
ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david }
|
559
|
-
|
579
|
+
|
560
580
|
people = Person.find(:all, :from => "/companies/1/people.xml")
|
561
581
|
assert_equal 1, people.size
|
562
582
|
assert_equal "David", people.first.name
|
@@ -564,7 +584,7 @@ class BaseTest < Test::Unit::TestCase
|
|
564
584
|
|
565
585
|
def test_find_all_by_from_with_options
|
566
586
|
ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david }
|
567
|
-
|
587
|
+
|
568
588
|
people = Person.find(:all, :from => "/companies/1/people.xml")
|
569
589
|
assert_equal 1, people.size
|
570
590
|
assert_equal "David", people.first.name
|
@@ -572,7 +592,7 @@ class BaseTest < Test::Unit::TestCase
|
|
572
592
|
|
573
593
|
def test_find_all_by_symbol_from
|
574
594
|
ActiveResource::HttpMock.respond_to { |m| m.get "/people/managers.xml", {}, @people_david }
|
575
|
-
|
595
|
+
|
576
596
|
people = Person.find(:all, :from => :managers)
|
577
597
|
assert_equal 1, people.size
|
578
598
|
assert_equal "David", people.first.name
|
@@ -601,10 +621,10 @@ class BaseTest < Test::Unit::TestCase
|
|
601
621
|
def test_id_from_response
|
602
622
|
p = Person.new
|
603
623
|
resp = {'Location' => '/foo/bar/1'}
|
604
|
-
assert_equal '1', p.
|
605
|
-
|
624
|
+
assert_equal '1', p.__send__(:id_from_response, resp)
|
625
|
+
|
606
626
|
resp['Location'] << '.xml'
|
607
|
-
assert_equal '1', p.
|
627
|
+
assert_equal '1', p.__send__(:id_from_response, resp)
|
608
628
|
end
|
609
629
|
|
610
630
|
def test_create_with_custom_prefix
|
@@ -619,16 +639,16 @@ class BaseTest < Test::Unit::TestCase
|
|
619
639
|
ryan = Person.new(:id => 1, :name => 'Ryan', :address => address)
|
620
640
|
assert_equal address.prefix_options, ryan.address.prefix_options
|
621
641
|
end
|
622
|
-
|
642
|
+
|
623
643
|
def test_reload_works_with_prefix_options
|
624
644
|
address = StreetAddress.find(1, :params => { :person_id => 1 })
|
625
645
|
assert_equal address, address.reload
|
626
646
|
end
|
627
|
-
|
647
|
+
|
628
648
|
def test_reload_with_redefined_to_param
|
629
649
|
Person.module_eval do
|
630
650
|
alias_method :original_to_param_reload, :to_param
|
631
|
-
def to_param
|
651
|
+
def to_param
|
632
652
|
name
|
633
653
|
end
|
634
654
|
end
|
@@ -643,13 +663,13 @@ class BaseTest < Test::Unit::TestCase
|
|
643
663
|
alias_method :reload_to_param, :to_param
|
644
664
|
alias_method :to_param, :original_to_param_reload
|
645
665
|
end
|
646
|
-
end
|
647
|
-
|
648
|
-
def test_reload_works_without_prefix_options
|
666
|
+
end
|
667
|
+
|
668
|
+
def test_reload_works_without_prefix_options
|
649
669
|
person = Person.find(:first)
|
650
670
|
assert_equal person, person.reload
|
651
671
|
end
|
652
|
-
|
672
|
+
|
653
673
|
|
654
674
|
def test_create
|
655
675
|
rick = Person.create(:name => 'Rick')
|
@@ -659,11 +679,11 @@ class BaseTest < Test::Unit::TestCase
|
|
659
679
|
|
660
680
|
# test additional attribute returned on create
|
661
681
|
assert_equal 25, rick.age
|
662
|
-
|
682
|
+
|
663
683
|
# Test that save exceptions get bubbled up too
|
664
684
|
ActiveResource::HttpMock.respond_to do |mock|
|
665
685
|
mock.post "/people.xml", {}, nil, 409
|
666
|
-
end
|
686
|
+
end
|
667
687
|
assert_raises(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') }
|
668
688
|
end
|
669
689
|
|
@@ -725,7 +745,7 @@ class BaseTest < Test::Unit::TestCase
|
|
725
745
|
assert_equal "54321 Lane", addy.street
|
726
746
|
addy.save
|
727
747
|
end
|
728
|
-
|
748
|
+
|
729
749
|
def test_update_conflict
|
730
750
|
ActiveResource::HttpMock.respond_to do |mock|
|
731
751
|
mock.get "/people/2.xml", {}, @david
|
@@ -757,7 +777,7 @@ class BaseTest < Test::Unit::TestCase
|
|
757
777
|
end
|
758
778
|
assert_raises(ActiveResource::ResourceNotFound) { Person.find(1) }
|
759
779
|
end
|
760
|
-
|
780
|
+
|
761
781
|
def test_delete_with_custom_prefix
|
762
782
|
assert StreetAddress.delete(1, :person_id => 1)
|
763
783
|
ActiveResource::HttpMock.respond_to do |mock|
|
@@ -787,23 +807,23 @@ class BaseTest < Test::Unit::TestCase
|
|
787
807
|
assert !StreetAddress.new({:id => 1, :person_id => 2}).exists?
|
788
808
|
assert !StreetAddress.new({:id => 2, :person_id => 1}).exists?
|
789
809
|
end
|
790
|
-
|
810
|
+
|
791
811
|
def test_exists_with_redefined_to_param
|
792
812
|
Person.module_eval do
|
793
813
|
alias_method :original_to_param_exists, :to_param
|
794
|
-
def to_param
|
814
|
+
def to_param
|
795
815
|
name
|
796
816
|
end
|
797
817
|
end
|
798
818
|
|
799
819
|
# Class method.
|
800
|
-
assert Person.exists?('Greg')
|
820
|
+
assert Person.exists?('Greg')
|
801
821
|
|
802
822
|
# Instance method.
|
803
|
-
assert Person.find('Greg').exists?
|
823
|
+
assert Person.find('Greg').exists?
|
804
824
|
|
805
825
|
# Nested class method.
|
806
|
-
assert StreetAddress.exists?(1, :params => { :person_id => Person.find('Greg').to_param })
|
826
|
+
assert StreetAddress.exists?(1, :params => { :person_id => Person.find('Greg').to_param })
|
807
827
|
|
808
828
|
# Nested instance method.
|
809
829
|
assert StreetAddress.find(1, :params => { :person_id => Person.find('Greg').to_param }).exists?
|
@@ -815,11 +835,11 @@ class BaseTest < Test::Unit::TestCase
|
|
815
835
|
alias_method :exists_to_param, :to_param
|
816
836
|
alias_method :to_param, :original_to_param_exists
|
817
837
|
end
|
818
|
-
end
|
819
|
-
|
838
|
+
end
|
839
|
+
|
820
840
|
def test_to_xml
|
821
841
|
matz = Person.find(1)
|
822
|
-
xml = matz.
|
842
|
+
xml = matz.encode
|
823
843
|
assert xml.starts_with?('<?xml version="1.0" encoding="UTF-8"?>')
|
824
844
|
assert xml.include?('<name>Matz</name>')
|
825
845
|
assert xml.include?('<id type="integer">1</id>')
|
@@ -845,4 +865,14 @@ class BaseTest < Test::Unit::TestCase
|
|
845
865
|
end
|
846
866
|
end
|
847
867
|
end
|
868
|
+
|
869
|
+
def test_load_yaml_array
|
870
|
+
assert_nothing_raised do
|
871
|
+
marty = Person.find(5)
|
872
|
+
assert_equal 3, marty.colors.size
|
873
|
+
marty.colors.each do |color|
|
874
|
+
assert_kind_of String, color
|
875
|
+
end
|
876
|
+
end
|
877
|
+
end
|
848
878
|
end
|