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.

@@ -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 "--> #{result.code} #{result.message} (#{result.body ? result.body.length : 0}b %.2fs)" % time if logger
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 ||= { 'Content-Type' => format.mime_type }
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
- ActiveResource::Base.logger
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 Active Resource instances - they are ordinary Hashes. If you are expecting
52
- # Active Resource instances, use the <tt>find</tt> class method with the
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), (body.nil? ? to_xml : body), self.class.headers)
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), body, self.class.headers)
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.send!(:query_string, options)}"
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.send!(:query_string, options)}"
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
- # wether or not your model actually sent an HTTP request.
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.reverse_merge('Content-Type' => 'application/xml')
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 allow validation of Active Resource objects, which creates an Errors instance for every resource.
220
- # Methods are implemented by overriding Base#validate or its variants Each of these methods can inspect
221
- # the state of the object, which usually means ensuring that a number of attributes have a certain value
222
- # (such as not empty, within a given range, matching a certain regular expression and so on).
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
- # class Person < ActiveResource::Base
227
- # self.site = "http://www.localhost.com:3000/"
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
- # def validate_on_create # is only run the first time a new object is saved
235
- # unless valid_member?(self)
236
- # errors.add("membership_discount", "has expired")
237
- # end
238
- # end
239
- #
240
- # def validate_on_update
241
- # errors.add_to_base("No changes have occurred") if unchanged_attributes?
242
- # end
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:
@@ -1,7 +1,7 @@
1
1
  module ActiveResource
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
- MINOR = 1
4
+ MINOR = 2
5
5
  TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
@@ -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.send!(:authorization_header)
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.send!(:authorization_header)
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.send!(:authorization_header)
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.send!(:authorization_header)
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.send!(:authorization_header)
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.send!(:authorization_header)
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.send!(:authorization_header)
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.send!(:handle_response, Response.new(code))
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
- @default_request_headers = { 'Content-Type' => 'application/xml' }
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)
@@ -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.send!(:remove_const, :Address) if Person.const_defined?(:Address)
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.send!(:remove_const, :Address) if Person.const_defined?(:Address)
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/Greg.xml", {}, @greg
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.send!(:prefix_parameters)
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.send!(:prefix_parameters)
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.send!(:id_from_response, resp)
605
-
624
+ assert_equal '1', p.__send__(:id_from_response, resp)
625
+
606
626
  resp['Location'] << '.xml'
607
- assert_equal '1', p.send!(:id_from_response, resp)
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.to_xml
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