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 CHANGED
@@ -1,9 +1,15 @@
1
- *2.1.2 (October 23rd, 2008)*
1
+ *2.2.1 [RC2] (November 14th, 2008)*
2
2
 
3
- * Included in Rails 2.1.2
3
+ * Fixed that ActiveResource#post would post an empty string when it shouldn't be posting anything #525 [Paolo Angelini]
4
4
 
5
5
 
6
- *2.1.1 (September 4th, 2008)*
6
+ *2.2.0 [RC1] (October 24th, 2008)*
7
+
8
+ * Add ActiveResource::Base#to_xml and ActiveResource::Base#to_json. #1011 [Rasik Pandey, Cody Fauser]
9
+
10
+ * Add ActiveResource::Base.find(:last). [#754 state:resolved] (Adrian Mugnolo)
11
+
12
+ * Fixed problems with the logger used if the logging string included %'s [#840 state:resolved] (Jamis Buck)
7
13
 
8
14
  * Fixed Base#exists? to check status code as integer [#299 state:resolved] (Wes Oldenbeuving)
9
15
 
data/README CHANGED
@@ -37,7 +37,7 @@ lifecycle methods that operate against a persistent store.
37
37
  Person.exists?(1) #=> true
38
38
 
39
39
  As you can see, the methods are quite similar to Active Record's methods for dealing with database
40
- records. But rather than dealing with
40
+ records. But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).
41
41
 
42
42
  ==== Protocol
43
43
 
data/Rakefile CHANGED
@@ -5,7 +5,6 @@ require 'rake/rdoctask'
5
5
  require 'rake/packagetask'
6
6
  require 'rake/gempackagetask'
7
7
  require 'rake/contrib/sshpublisher'
8
- require 'rake/contrib/rubyforgepublisher'
9
8
 
10
9
  require File.join(File.dirname(__FILE__), 'lib', 'active_resource', 'version')
11
10
 
@@ -66,7 +65,7 @@ spec = Gem::Specification.new do |s|
66
65
  s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
67
66
  end
68
67
 
69
- s.add_dependency('activesupport', '= 2.1.2' + PKG_BUILD)
68
+ s.add_dependency('activesupport', '= 2.2.2' + PKG_BUILD)
70
69
 
71
70
  s.require_path = 'lib'
72
71
  s.autorequire = 'active_resource'
@@ -116,8 +115,8 @@ end
116
115
 
117
116
  desc "Publish the beta gem"
118
117
  task :pgem => [:package] do
119
- Rake::SshFilePublisher.new("david@greed.loudthinking.com", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
120
- `ssh david@greed.loudthinking.com '/u/sites/gems/gemupdate.sh'`
118
+ Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
119
+ `ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
121
120
  end
122
121
 
123
122
  desc "Publish the API documentation"
@@ -21,16 +21,13 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
- $:.unshift(File.dirname(__FILE__)) unless
25
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
26
-
27
- unless defined?(ActiveSupport)
28
- begin
29
- $:.unshift(File.dirname(__FILE__) + "/../../activesupport/lib")
24
+ begin
25
+ require 'active_support'
26
+ rescue LoadError
27
+ activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
28
+ if File.directory?(activesupport_path)
29
+ $:.unshift activesupport_path
30
30
  require 'active_support'
31
- rescue LoadError
32
- require 'rubygems'
33
- gem 'activesupport'
34
31
  end
35
32
  end
36
33
 
@@ -44,4 +41,4 @@ module ActiveResource
44
41
  include Validations
45
42
  include CustomMethods
46
43
  end
47
- end
44
+ end
@@ -13,48 +13,48 @@ module ActiveResource
13
13
  # to Ruby objects, Active Resource only needs a class name that corresponds to the resource name (e.g., the class
14
14
  # Person maps to the resources people, very similarly to Active Record) and a +site+ value, which holds the
15
15
  # URI of the resources.
16
- #
16
+ #
17
17
  # class Person < ActiveResource::Base
18
18
  # self.site = "http://api.people.com:3000/"
19
19
  # end
20
- #
20
+ #
21
21
  # Now the Person class is mapped to RESTful resources located at <tt>http://api.people.com:3000/people/</tt>, and
22
- # you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
22
+ # you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
23
23
  # an existing model with the same name as the desired RESTful resource you can set the +element_name+ value.
24
24
  #
25
25
  # class PersonResource < ActiveResource::Base
26
26
  # self.site = "http://api.people.com:3000/"
27
27
  # self.element_name = "person"
28
28
  # end
29
- #
30
- #
29
+ #
30
+ #
31
31
  # == Lifecycle methods
32
32
  #
33
33
  # Active Resource exposes methods for creating, finding, updating, and deleting resources
34
34
  # from REST web services.
35
- #
35
+ #
36
36
  # ryan = Person.new(:first => 'Ryan', :last => 'Daigle')
37
37
  # ryan.save # => true
38
38
  # ryan.id # => 2
39
39
  # Person.exists?(ryan.id) # => true
40
40
  # ryan.exists? # => true
41
- #
41
+ #
42
42
  # ryan = Person.find(1)
43
43
  # # Resource holding our newly created Person object
44
- #
44
+ #
45
45
  # ryan.first = 'Rizzle'
46
46
  # ryan.save # => true
47
- #
47
+ #
48
48
  # ryan.destroy # => true
49
49
  #
50
50
  # As you can see, these are very similar to Active Record's lifecycle methods for database records.
51
51
  # You can read more about each of these methods in their respective documentation.
52
- #
52
+ #
53
53
  # === Custom REST methods
54
54
  #
55
55
  # Since simple CRUD/lifecycle methods can't accomplish every task, Active Resource also supports
56
56
  # defining your own custom REST methods. To invoke them, Active Resource provides the <tt>get</tt>,
57
- # <tt>post</tt>, <tt>put</tt> and <tt>delete</tt> methods where you can specify a custom REST method
57
+ # <tt>post</tt>, <tt>put</tt> and <tt>\delete</tt> methods where you can specify a custom REST method
58
58
  # name to invoke.
59
59
  #
60
60
  # # POST to the custom 'register' REST method, i.e. POST /people/new/register.xml.
@@ -71,14 +71,14 @@ module ActiveResource
71
71
  #
72
72
  # # DELETE to 'fire' a person, i.e. DELETE /people/1/fire.xml.
73
73
  # Person.find(1).delete(:fire)
74
- #
74
+ #
75
75
  # For more information on using custom REST methods, see the
76
76
  # ActiveResource::CustomMethods documentation.
77
77
  #
78
78
  # == Validations
79
79
  #
80
80
  # You can validate resources client side by overriding validation methods in the base class.
81
- #
81
+ #
82
82
  # class Person < ActiveResource::Base
83
83
  # self.site = "http://api.people.com:3000/"
84
84
  # protected
@@ -86,19 +86,19 @@ module ActiveResource
86
86
  # errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
87
87
  # end
88
88
  # end
89
- #
89
+ #
90
90
  # See the ActiveResource::Validations documentation for more information.
91
91
  #
92
92
  # == Authentication
93
- #
93
+ #
94
94
  # Many REST APIs will require authentication, usually in the form of basic
95
95
  # HTTP authentication. Authentication can be specified by:
96
96
  # * putting the credentials in the URL for the +site+ variable.
97
- #
97
+ #
98
98
  # class Person < ActiveResource::Base
99
99
  # self.site = "http://ryan:password@api.people.com:3000/"
100
100
  # end
101
- #
101
+ #
102
102
  # * defining +user+ and/or +password+ variables
103
103
  #
104
104
  # class Person < ActiveResource::Base
@@ -107,35 +107,41 @@ module ActiveResource
107
107
  # self.password = "password"
108
108
  # end
109
109
  #
110
- # For obvious security reasons, it is probably best if such services are available
110
+ # For obvious security reasons, it is probably best if such services are available
111
111
  # over HTTPS.
112
- #
113
- # Note: Some values cannot be provided in the URL passed to site. e.g. email addresses
114
- # as usernames. In those situations you should use the seperate user and password option.
112
+ #
113
+ # Note: Some values cannot be provided in the URL passed to site. e.g. email addresses
114
+ # as usernames. In those situations you should use the separate user and password option.
115
115
  # == Errors & Validation
116
116
  #
117
117
  # Error handling and validation is handled in much the same manner as you're used to seeing in
118
118
  # Active Record. Both the response code in the HTTP response and the body of the response are used to
119
119
  # indicate that an error occurred.
120
- #
120
+ #
121
121
  # === Resource errors
122
- #
122
+ #
123
123
  # When a GET is requested for a resource that does not exist, the HTTP <tt>404</tt> (Resource Not Found)
124
124
  # response code will be returned from the server which will raise an ActiveResource::ResourceNotFound
125
125
  # exception.
126
- #
126
+ #
127
127
  # # GET http://api.people.com:3000/people/999.xml
128
128
  # ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound
129
- #
129
+ #
130
130
  # <tt>404</tt> is just one of the HTTP error response codes that Active Resource will handle with its own exception. The
131
131
  # following HTTP response codes will also result in these exceptions:
132
132
  #
133
- # * 200..399 - Valid response, no exception
133
+ # * 200..399 - Valid response, no exception (other than 301, 302)
134
+ # * 301, 302 - ActiveResource::Redirection
135
+ # * 400 - ActiveResource::BadRequest
136
+ # * 401 - ActiveResource::UnauthorizedAccess
137
+ # * 403 - ActiveResource::ForbiddenAccess
134
138
  # * 404 - ActiveResource::ResourceNotFound
139
+ # * 405 - ActiveResource::MethodNotAllowed
135
140
  # * 409 - ActiveResource::ResourceConflict
136
141
  # * 422 - ActiveResource::ResourceInvalid (rescued by save as validation errors)
137
142
  # * 401..499 - ActiveResource::ClientError
138
143
  # * 500..599 - ActiveResource::ServerError
144
+ # * Other - ActiveResource::ConnectionError
139
145
  #
140
146
  # These custom exceptions allow you to deal with resource errors more naturally and with more precision
141
147
  # rather than returning a general HTTP error. For example:
@@ -149,17 +155,17 @@ module ActiveResource
149
155
  # end
150
156
  #
151
157
  # === Validation errors
152
- #
158
+ #
153
159
  # Active Resource supports validations on resources and will return errors if any these validations fail
154
- # (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
160
+ # (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
155
161
  # a response code of <tt>422</tt> and an XML representation of the validation errors. The save operation will
156
162
  # then fail (with a <tt>false</tt> return value) and the validation errors can be accessed on the resource in question.
157
- #
163
+ #
158
164
  # ryan = Person.find(1)
159
165
  # ryan.first # => ''
160
166
  # ryan.save # => false
161
167
  #
162
- # # When
168
+ # # When
163
169
  # # PUT http://api.people.com:3000/people/1.xml
164
170
  # # is requested with invalid values, the response is:
165
171
  # #
@@ -169,13 +175,13 @@ module ActiveResource
169
175
  #
170
176
  # ryan.errors.invalid?(:first) # => true
171
177
  # ryan.errors.full_messages # => ['First cannot be empty']
172
- #
178
+ #
173
179
  # Learn more about Active Resource's validation features in the ActiveResource::Validations documentation.
174
180
  #
175
181
  # === Timeouts
176
182
  #
177
183
  # Active Resource relies on HTTP to access RESTful APIs and as such is inherently susceptible to slow or
178
- # unresponsive servers. In such cases, your Active Resource method calls could timeout. You can control the
184
+ # unresponsive servers. In such cases, your Active Resource method calls could \timeout. You can control the
179
185
  # amount of time before Active Resource times out with the +timeout+ variable.
180
186
  #
181
187
  # class Person < ActiveResource::Base
@@ -189,7 +195,7 @@ module ActiveResource
189
195
  # http://en.wikipedia.org/wiki/Fail-fast) rather than cause cascading failures that could incapacitate your
190
196
  # server.
191
197
  #
192
- # When a timeout occurs, an ActiveResource::TimeoutError is raised. You should rescue from
198
+ # When a \timeout occurs, an ActiveResource::TimeoutError is raised. You should rescue from
193
199
  # ActiveResource::TimeoutError in your Active Resource method calls.
194
200
  #
195
201
  # Internally, Active Resource relies on Ruby's Net::HTTP library to make HTTP requests. Setting +timeout+
@@ -200,7 +206,7 @@ module ActiveResource
200
206
  cattr_accessor :logger
201
207
 
202
208
  class << self
203
- # Gets the URI of the REST resources to map for this class. The site variable is required
209
+ # Gets the URI of the REST resources to map for this class. The site variable is required for
204
210
  # Active Resource's mapping to work.
205
211
  def site
206
212
  # Not using superclass_delegating_reader because don't want subclasses to modify superclass instance
@@ -226,7 +232,7 @@ module ActiveResource
226
232
  end
227
233
 
228
234
  # Sets the URI of the REST resources to map for this class to the value in the +site+ argument.
229
- # The site variable is required Active Resource's mapping to work.
235
+ # The site variable is required for Active Resource's mapping to work.
230
236
  def site=(site)
231
237
  @connection = nil
232
238
  if site.nil?
@@ -238,7 +244,7 @@ module ActiveResource
238
244
  end
239
245
  end
240
246
 
241
- # Gets the user for REST HTTP authentication.
247
+ # Gets the \user for REST HTTP authentication.
242
248
  def user
243
249
  # Not using superclass_delegating_reader. See +site+ for explanation
244
250
  if defined?(@user)
@@ -248,13 +254,13 @@ module ActiveResource
248
254
  end
249
255
  end
250
256
 
251
- # Sets the user for REST HTTP authentication.
257
+ # Sets the \user for REST HTTP authentication.
252
258
  def user=(user)
253
259
  @connection = nil
254
260
  @user = user
255
261
  end
256
262
 
257
- # Gets the password for REST HTTP authentication.
263
+ # Gets the \password for REST HTTP authentication.
258
264
  def password
259
265
  # Not using superclass_delegating_reader. See +site+ for explanation
260
266
  if defined?(@password)
@@ -264,7 +270,7 @@ module ActiveResource
264
270
  end
265
271
  end
266
272
 
267
- # Sets the password for REST HTTP authentication.
273
+ # Sets the \password for REST HTTP authentication.
268
274
  def password=(password)
269
275
  @connection = nil
270
276
  @password = password
@@ -280,16 +286,16 @@ module ActiveResource
280
286
  #
281
287
  # Default format is <tt>:xml</tt>.
282
288
  def format=(mime_type_reference_or_format)
283
- format = mime_type_reference_or_format.is_a?(Symbol) ?
289
+ format = mime_type_reference_or_format.is_a?(Symbol) ?
284
290
  ActiveResource::Formats[mime_type_reference_or_format] : mime_type_reference_or_format
285
291
 
286
- write_inheritable_attribute("format", format)
292
+ write_inheritable_attribute(:format, format)
287
293
  connection.format = format if site
288
294
  end
289
295
 
290
296
  # Returns the current format, default is ActiveResource::Formats::XmlFormat.
291
- def format # :nodoc:
292
- read_inheritable_attribute("format") || ActiveResource::Formats[:xml]
297
+ def format
298
+ read_inheritable_attribute(:format) || ActiveResource::Formats[:xml]
293
299
  end
294
300
 
295
301
  # Sets the number of seconds after which requests to the REST API should time out.
@@ -298,7 +304,7 @@ module ActiveResource
298
304
  @timeout = timeout
299
305
  end
300
306
 
301
- # Gets tthe number of seconds after which requests to the REST API should time out.
307
+ # Gets the number of seconds after which requests to the REST API should time out.
302
308
  def timeout
303
309
  if defined?(@timeout)
304
310
  @timeout
@@ -307,8 +313,8 @@ module ActiveResource
307
313
  end
308
314
  end
309
315
 
310
- # An instance of ActiveResource::Connection that is the base connection to the remote service.
311
- # The +refresh+ parameter toggles whether or not the connection is refreshed at every request
316
+ # An instance of ActiveResource::Connection that is the base \connection to the remote service.
317
+ # The +refresh+ parameter toggles whether or not the \connection is refreshed at every request
312
318
  # or not (defaults to <tt>false</tt>).
313
319
  def connection(refresh = false)
314
320
  if defined?(@connection) || superclass == Object
@@ -333,8 +339,8 @@ module ActiveResource
333
339
  attr_accessor_with_default(:collection_name) { element_name.pluralize } #:nodoc:
334
340
  attr_accessor_with_default(:primary_key, 'id') #:nodoc:
335
341
 
336
- # Gets the prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>)
337
- # This method is regenerated at runtime based on what the prefix is set to.
342
+ # Gets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>)
343
+ # This method is regenerated at runtime based on what the \prefix is set to.
338
344
  def prefix(options={})
339
345
  default = site.path
340
346
  default << '/' unless default[-1..-1] == '/'
@@ -343,14 +349,14 @@ module ActiveResource
343
349
  prefix(options)
344
350
  end
345
351
 
346
- # An attribute reader for the source string for the resource path prefix. This
347
- # method is regenerated at runtime based on what the prefix is set to.
352
+ # An attribute reader for the source string for the resource path \prefix. This
353
+ # method is regenerated at runtime based on what the \prefix is set to.
348
354
  def prefix_source
349
355
  prefix # generate #prefix and #prefix_source methods first
350
356
  prefix_source
351
357
  end
352
358
 
353
- # Sets the prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>).
359
+ # Sets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>).
354
360
  # Default value is <tt>site.path</tt>.
355
361
  def prefix=(value = '/')
356
362
  # Replace :placeholders with '#{embedded options[:lookups]}'
@@ -376,29 +382,29 @@ module ActiveResource
376
382
  alias_method :set_collection_name, :collection_name= #:nodoc:
377
383
 
378
384
  # Gets the element path for the given ID in +id+. If the +query_options+ parameter is omitted, Rails
379
- # will split from the prefix options.
385
+ # will split from the \prefix options.
380
386
  #
381
387
  # ==== Options
382
- # +prefix_options+ - A hash to add a prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
388
+ # +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
383
389
  # would yield a URL like <tt>/accounts/19/purchases.xml</tt>).
384
- # +query_options+ - A hash to add items to the query string for the request.
390
+ # +query_options+ - A \hash to add items to the query string for the request.
385
391
  #
386
392
  # ==== Examples
387
- # Post.element_path(1)
393
+ # Post.element_path(1)
388
394
  # # => /posts/1.xml
389
395
  #
390
- # Comment.element_path(1, :post_id => 5)
396
+ # Comment.element_path(1, :post_id => 5)
391
397
  # # => /posts/5/comments/1.xml
392
398
  #
393
- # Comment.element_path(1, :post_id => 5, :active => 1)
399
+ # Comment.element_path(1, :post_id => 5, :active => 1)
394
400
  # # => /posts/5/comments/1.xml?active=1
395
401
  #
396
- # Comment.element_path(1, {:post_id => 5}, {:active => 1})
402
+ # Comment.element_path(1, {:post_id => 5}, {:active => 1})
397
403
  # # => /posts/5/comments/1.xml?active=1
398
404
  #
399
405
  def element_path(id, prefix_options = {}, query_options = nil)
400
406
  prefix_options, query_options = split_options(prefix_options) if query_options.nil?
401
- "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
407
+ "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
402
408
  end
403
409
 
404
410
  # Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails
@@ -413,13 +419,13 @@ module ActiveResource
413
419
  # Post.collection_path
414
420
  # # => /posts.xml
415
421
  #
416
- # Comment.collection_path(:post_id => 5)
422
+ # Comment.collection_path(:post_id => 5)
417
423
  # # => /posts/5/comments.xml
418
424
  #
419
- # Comment.collection_path(:post_id => 5, :active => 1)
425
+ # Comment.collection_path(:post_id => 5, :active => 1)
420
426
  # # => /posts/5/comments.xml?active=1
421
427
  #
422
- # Comment.collection_path({:post_id => 5}, {:active => 1})
428
+ # Comment.collection_path({:post_id => 5}, {:active => 1})
423
429
  # # => /posts/5/comments.xml?active=1
424
430
  #
425
431
  def collection_path(prefix_options = {}, query_options = nil)
@@ -429,16 +435,16 @@ module ActiveResource
429
435
 
430
436
  alias_method :set_primary_key, :primary_key= #:nodoc:
431
437
 
432
- # Create a new resource instance and request to the remote service
438
+ # Creates a new resource instance and makes a request to the remote service
433
439
  # that it be saved, making it equivalent to the following simultaneous calls:
434
440
  #
435
441
  # ryan = Person.new(:first => 'ryan')
436
442
  # ryan.save
437
443
  #
438
- # The newly created resource is returned. If a failure has occurred an
439
- # exception will be raised (see save). If the resource is invalid and
440
- # has not been saved then valid? will return <tt>false</tt>,
441
- # while new? will still return <tt>true</tt>.
444
+ # Returns the newly created resource. If a failure has occurred an
445
+ # exception will be raised (see <tt>save</tt>). If the resource is invalid and
446
+ # has not been saved then <tt>valid?</tt> will return <tt>false</tt>,
447
+ # while <tt>new?</tt> will still return <tt>true</tt>.
442
448
  #
443
449
  # ==== Examples
444
450
  # Person.create(:name => 'Jeremy', :email => 'myname@nospam.com', :enabled => true)
@@ -454,50 +460,54 @@ module ActiveResource
454
460
  # that_guy.valid? # => false
455
461
  # that_guy.new? # => true
456
462
  def create(attributes = {})
457
- returning(self.new(attributes)) { |res| res.save }
463
+ returning(self.new(attributes)) { |res| res.save }
458
464
  end
459
465
 
460
466
  # Core method for finding resources. Used similarly to Active Record's +find+ method.
461
467
  #
462
468
  # ==== Arguments
463
- # The first argument is considered to be the scope of the query. That is, how many
469
+ # The first argument is considered to be the scope of the query. That is, how many
464
470
  # resources are returned from the request. It can be one of the following.
465
471
  #
466
472
  # * <tt>:one</tt> - Returns a single resource.
467
473
  # * <tt>:first</tt> - Returns the first resource found.
474
+ # * <tt>:last</tt> - Returns the last resource found.
468
475
  # * <tt>:all</tt> - Returns every resource that matches the request.
469
- #
476
+ #
470
477
  # ==== Options
471
478
  #
472
479
  # * <tt>:from</tt> - Sets the path or custom method that resources will be fetched from.
473
- # * <tt>:params</tt> - Sets query and prefix (nested URL) parameters.
480
+ # * <tt>:params</tt> - Sets query and \prefix (nested URL) parameters.
474
481
  #
475
482
  # ==== Examples
476
- # Person.find(1)
483
+ # Person.find(1)
477
484
  # # => GET /people/1.xml
478
485
  #
479
- # Person.find(:all)
486
+ # Person.find(:all)
480
487
  # # => GET /people.xml
481
488
  #
482
- # Person.find(:all, :params => { :title => "CEO" })
489
+ # Person.find(:all, :params => { :title => "CEO" })
483
490
  # # => GET /people.xml?title=CEO
484
491
  #
485
- # Person.find(:first, :from => :managers)
492
+ # Person.find(:first, :from => :managers)
493
+ # # => GET /people/managers.xml
494
+ #
495
+ # Person.find(:last, :from => :managers)
486
496
  # # => GET /people/managers.xml
487
497
  #
488
- # Person.find(:all, :from => "/companies/1/people.xml")
498
+ # Person.find(:all, :from => "/companies/1/people.xml")
489
499
  # # => GET /companies/1/people.xml
490
500
  #
491
- # Person.find(:one, :from => :leader)
501
+ # Person.find(:one, :from => :leader)
492
502
  # # => GET /people/leader.xml
493
503
  #
494
504
  # Person.find(:all, :from => :developers, :params => { :language => 'ruby' })
495
505
  # # => GET /people/developers.xml?language=ruby
496
506
  #
497
- # Person.find(:one, :from => "/companies/1/manager.xml")
507
+ # Person.find(:one, :from => "/companies/1/manager.xml")
498
508
  # # => GET /companies/1/manager.xml
499
509
  #
500
- # StreetAddress.find(1, :params => { :person_id => 1 })
510
+ # StreetAddress.find(1, :params => { :person_id => 1 })
501
511
  # # => GET /people/1/street_addresses/1.xml
502
512
  def find(*arguments)
503
513
  scope = arguments.slice!(0)
@@ -506,6 +516,7 @@ module ActiveResource
506
516
  case scope
507
517
  when :all then find_every(options)
508
518
  when :first then find_every(options).first
519
+ when :last then find_every(options).last
509
520
  when :one then find_one(options)
510
521
  else find_single(scope, options)
511
522
  end
@@ -514,7 +525,7 @@ module ActiveResource
514
525
  # Deletes the resources with the ID in the +id+ parameter.
515
526
  #
516
527
  # ==== Options
517
- # All options specify prefix and query parameters.
528
+ # All options specify \prefix and query parameters.
518
529
  #
519
530
  # ==== Examples
520
531
  # Event.delete(2) # sends DELETE /events/2
@@ -563,7 +574,7 @@ module ActiveResource
563
574
  instantiate_collection( (connection.get(path, headers) || []), prefix_options )
564
575
  end
565
576
  end
566
-
577
+
567
578
  # Find a single resource from a one-off URL
568
579
  def find_one(options)
569
580
  case from = options[:from]
@@ -581,7 +592,7 @@ module ActiveResource
581
592
  path = element_path(scope, prefix_options, query_options)
582
593
  instantiate_record(connection.get(path, headers), prefix_options)
583
594
  end
584
-
595
+
585
596
  def instantiate_collection(collection, prefix_options = {})
586
597
  collection.collect! { |record| instantiate_record(record, prefix_options) }
587
598
  end
@@ -605,10 +616,10 @@ module ActiveResource
605
616
 
606
617
  # Builds the query string for the request.
607
618
  def query_string(options)
608
- "?#{options.to_query}" unless options.nil? || options.empty?
619
+ "?#{options.to_query}" unless options.nil? || options.empty?
609
620
  end
610
621
 
611
- # split an option hash into two hashes, one containing the prefix options,
622
+ # split an option hash into two hashes, one containing the prefix options,
612
623
  # and the other containing the leftovers.
613
624
  def split_options(options = {})
614
625
  prefix_options, query_options = {}, {}
@@ -625,8 +636,8 @@ module ActiveResource
625
636
  attr_accessor :attributes #:nodoc:
626
637
  attr_accessor :prefix_options #:nodoc:
627
638
 
628
- # Constructor method for new resources; the optional +attributes+ parameter takes a hash
629
- # of attributes for the new resource.
639
+ # Constructor method for \new resources; the optional +attributes+ parameter takes a \hash
640
+ # of attributes for the \new resource.
630
641
  #
631
642
  # ==== Examples
632
643
  # my_course = Course.new
@@ -642,8 +653,8 @@ module ActiveResource
642
653
  load(attributes)
643
654
  end
644
655
 
645
- # Returns a clone of the resource that hasn't been assigned an +id+ yet and
646
- # is treated as a new resource.
656
+ # Returns a \clone of the resource that hasn't been assigned an +id+ yet and
657
+ # is treated as a \new resource.
647
658
  #
648
659
  # ryan = Person.find(1)
649
660
  # not_ryan = ryan.clone
@@ -657,7 +668,7 @@ module ActiveResource
657
668
  # ryan = Person.find(1)
658
669
  # ryan.address = StreetAddress.find(1, :person_id => ryan.id)
659
670
  # ryan.hash = {:not => "an ARes instance"}
660
- #
671
+ #
661
672
  # not_ryan = ryan.clone
662
673
  # not_ryan.new? # => true
663
674
  # not_ryan.address # => NoMethodError
@@ -678,7 +689,7 @@ module ActiveResource
678
689
  end
679
690
 
680
691
 
681
- # A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet).
692
+ # A method to determine if the resource a \new object (i.e., it has not been POSTed to the remote service yet).
682
693
  #
683
694
  # ==== Examples
684
695
  # not_new = Computer.create(:brand => 'Apple', :make => 'MacBook', :vendor => 'MacMall')
@@ -694,12 +705,12 @@ module ActiveResource
694
705
  id.nil?
695
706
  end
696
707
 
697
- # Get the +id+ attribute of the resource.
708
+ # Gets the <tt>\id</tt> attribute of the resource.
698
709
  def id
699
710
  attributes[self.class.primary_key]
700
711
  end
701
712
 
702
- # Set the +id+ attribute of the resource.
713
+ # Sets the <tt>\id</tt> attribute of the resource.
703
714
  def id=(id)
704
715
  attributes[self.class.primary_key] = id
705
716
  end
@@ -709,7 +720,7 @@ module ActiveResource
709
720
  id && id.to_s
710
721
  end
711
722
 
712
- # Test for equality. Resource are equal if and only if +other+ is the same object or
723
+ # Test for equality. Resource are equal if and only if +other+ is the same object or
713
724
  # is an instance of the same class, is not <tt>new?</tt>, and has the same +id+.
714
725
  #
715
726
  # ==== Examples
@@ -740,12 +751,12 @@ module ActiveResource
740
751
  self == other
741
752
  end
742
753
 
743
- # Delegates to id in order to allow two resources of the same type and id to work with something like:
754
+ # Delegates to id in order to allow two resources of the same type and \id to work with something like:
744
755
  # [Person.find(1), Person.find(2)] & [Person.find(1), Person.find(4)] # => [Person.find(1)]
745
756
  def hash
746
757
  id.hash
747
758
  end
748
-
759
+
749
760
  # Duplicate the current resource without saving it.
750
761
  #
751
762
  # ==== Examples
@@ -765,9 +776,9 @@ module ActiveResource
765
776
  end
766
777
  end
767
778
 
768
- # A method to save (+POST+) or update (+PUT+) a resource. It delegates to +create+ if a new object,
769
- # +update+ if it is existing. If the response to the save includes a body, it will be assumed that this body
770
- # is XML for the final object as it looked after the save (which would include attributes like +created_at+
779
+ # A method to \save (+POST+) or \update (+PUT+) a resource. It delegates to +create+ if a \new object,
780
+ # +update+ if it is existing. If the response to the \save includes a body, it will be assumed that this body
781
+ # is XML for the final object as it looked after the \save (which would include attributes like +created_at+
771
782
  # that weren't part of the original submit).
772
783
  #
773
784
  # ==== Examples
@@ -789,7 +800,7 @@ module ActiveResource
789
800
  # my_person = Person.find(my_id)
790
801
  # my_person.destroy
791
802
  # Person.find(my_id) # 404 (Resource Not Found)
792
- #
803
+ #
793
804
  # new_person = Person.create(:name => 'James')
794
805
  # new_id = new_person.id # => 7
795
806
  # new_person.destroy
@@ -815,7 +826,7 @@ module ActiveResource
815
826
  # Person.delete(guys_id)
816
827
  # that_guy.exists? # => false
817
828
  def exists?
818
- !new? && self.class.exists?(to_param, :params => prefix_options)
829
+ !new? && self.class.exists?(to_param, :params => prefix_options)
819
830
  end
820
831
 
821
832
  # A method to convert the the resource to an XML string.
@@ -828,7 +839,7 @@ module ActiveResource
828
839
  # * <tt>:indent</tt> - Set the indent level for the XML output (default is +2+).
829
840
  # * <tt>:dasherize</tt> - Boolean option to determine whether or not element names should
830
841
  # replace underscores with dashes (default is <tt>false</tt>).
831
- # * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
842
+ # * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
832
843
  # that generates the XML declaration (default is <tt>false</tt>).
833
844
  #
834
845
  # ==== Examples
@@ -847,12 +858,53 @@ module ActiveResource
847
858
  attributes.to_xml({:root => self.class.element_name}.merge(options))
848
859
  end
849
860
 
850
- # A method to reload the attributes of this object from the remote web service.
861
+ # Returns a JSON string representing the model. Some configuration is
862
+ # available through +options+.
863
+ #
864
+ # ==== Options
865
+ # The +options+ are passed to the +to_json+ method on each
866
+ # attribute, so the same options as the +to_json+ methods in
867
+ # Active Support.
868
+ #
869
+ # * <tt>:only</tt> - Only include the specified attribute or list of
870
+ # attributes in the serialized output. Attribute names must be specified
871
+ # as strings.
872
+ # * <tt>:except</tt> - Do not include the specified attribute or list of
873
+ # attributes in the serialized output. Attribute names must be specified
874
+ # as strings.
875
+ #
876
+ # ==== Examples
877
+ # person = Person.new(:first_name => "Jim", :last_name => "Smith")
878
+ # person.to_json
879
+ # # => {"first_name": "Jim", "last_name": "Smith"}
880
+ #
881
+ # person.to_json(:only => ["first_name"])
882
+ # # => {"first_name": "Jim"}
883
+ #
884
+ # person.to_json(:except => ["first_name"])
885
+ # # => {"last_name": "Smith"}
886
+ def to_json(options={})
887
+ attributes.to_json(options)
888
+ end
889
+
890
+ # Returns the serialized string representation of the resource in the configured
891
+ # serialization format specified in ActiveResource::Base.format. The options
892
+ # applicable depend on the configured encoding format.
893
+ def encode(options={})
894
+ case self.class.format
895
+ when ActiveResource::Formats[:xml]
896
+ self.class.format.encode(attributes, {:root => self.class.element_name}.merge(options))
897
+ else
898
+ self.class.format.encode(attributes, options)
899
+ end
900
+ end
901
+
902
+ # A method to \reload the attributes of this object from the remote web service.
851
903
  #
852
904
  # ==== Examples
853
905
  # my_branch = Branch.find(:first)
854
906
  # my_branch.name # => "Wislon Raod"
855
- #
907
+ #
856
908
  # # Another client fixes the typo...
857
909
  #
858
910
  # my_branch.name # => "Wislon Raod"
@@ -862,12 +914,13 @@ module ActiveResource
862
914
  self.load(self.class.find(to_param, :params => @prefix_options).attributes)
863
915
  end
864
916
 
865
- # A method to manually load attributes from a hash. Recursively loads collections of
866
- # resources. This method is called in +initialize+ and +create+ when a hash of attributes
917
+ # A method to manually load attributes from a \hash. Recursively loads collections of
918
+ # resources. This method is called in +initialize+ and +create+ when a \hash of attributes
867
919
  # is provided.
868
920
  #
869
921
  # ==== Examples
870
922
  # my_attrs = {:name => 'J&J Textiles', :industry => 'Cloth and textiles'}
923
+ # my_attrs = {:name => 'Marty', :colors => ["red", "green", "blue"]}
871
924
  #
872
925
  # the_supplier = Supplier.find(:first)
873
926
  # the_supplier.name # => 'J&M Textiles'
@@ -890,7 +943,7 @@ module ActiveResource
890
943
  case value
891
944
  when Array
892
945
  resource = find_or_create_resource_for_collection(key)
893
- value.map { |attrs| resource.new(attrs) }
946
+ value.map { |attrs| attrs.is_a?(String) ? attrs.dup : resource.new(attrs) }
894
947
  when Hash
895
948
  resource = find_or_create_resource_for(key)
896
949
  resource.new(value)
@@ -900,19 +953,19 @@ module ActiveResource
900
953
  end
901
954
  self
902
955
  end
903
-
956
+
904
957
  # For checking <tt>respond_to?</tt> without searching the attributes (which is faster).
905
958
  alias_method :respond_to_without_attributes?, :respond_to?
906
959
 
907
960
  # A method to determine if an object responds to a message (e.g., a method call). In Active Resource, a Person object with a
908
- # +name+ attribute can answer <tt>true</tt> to <tt>my_person.respond_to?("name")</tt>, <tt>my_person.respond_to?("name=")</tt>, and
909
- # <tt>my_person.respond_to?("name?")</tt>.
961
+ # +name+ attribute can answer <tt>true</tt> to <tt>my_person.respond_to?(:name)</tt>, <tt>my_person.respond_to?(:name=)</tt>, and
962
+ # <tt>my_person.respond_to?(:name?)</tt>.
910
963
  def respond_to?(method, include_priv = false)
911
964
  method_name = method.to_s
912
965
  if attributes.nil?
913
966
  return super
914
967
  elsif attributes.has_key?(method_name)
915
- return true
968
+ return true
916
969
  elsif ['?','='].include?(method_name.last) && attributes.has_key?(method_name.first(-1))
917
970
  return true
918
971
  end
@@ -920,7 +973,7 @@ module ActiveResource
920
973
  # would return true for generated readers, even if the attribute wasn't present
921
974
  super
922
975
  end
923
-
976
+
924
977
 
925
978
  protected
926
979
  def connection(refresh = false)
@@ -929,19 +982,19 @@ module ActiveResource
929
982
 
930
983
  # Update the resource on the remote service.
931
984
  def update
932
- returning connection.put(element_path(prefix_options), to_xml, self.class.headers) do |response|
985
+ returning connection.put(element_path(prefix_options), encode, self.class.headers) do |response|
933
986
  load_attributes_from_response(response)
934
987
  end
935
988
  end
936
989
 
937
- # Create (i.e., save to the remote service) the new resource.
990
+ # Create (i.e., \save to the remote service) the \new resource.
938
991
  def create
939
- returning connection.post(collection_path, to_xml, self.class.headers) do |response|
992
+ returning connection.post(collection_path, encode, self.class.headers) do |response|
940
993
  self.id = id_from_response(response)
941
994
  load_attributes_from_response(response)
942
995
  end
943
996
  end
944
-
997
+
945
998
  def load_attributes_from_response(response)
946
999
  if response['Content-Length'] != "0" && response.body.strip.size > 0
947
1000
  load(self.class.format.decode(response.body))
@@ -966,7 +1019,7 @@ module ActiveResource
966
1019
  def find_or_create_resource_for_collection(name)
967
1020
  find_or_create_resource_for(name.to_s.singularize)
968
1021
  end
969
-
1022
+
970
1023
  # Tries to find a resource in a non empty list of nested modules
971
1024
  # Raises a NameError if it was not found in any of the given nested modules
972
1025
  def find_resource_in_modules(resource_name, module_names)
@@ -1002,7 +1055,7 @@ module ActiveResource
1002
1055
  end
1003
1056
 
1004
1057
  def split_options(options = {})
1005
- self.class.send!(:split_options, options)
1058
+ self.class.__send__(:split_options, options)
1006
1059
  end
1007
1060
 
1008
1061
  def method_missing(method_symbol, *arguments) #:nodoc: