public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Add ActiveResource::Base.find(:last). [#754 state:resolved]

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
xymbol (author)
Thu Aug 21 19:03:26 -0700 2008
lifo (committer)
Thu Aug 21 19:06:57 -0700 2008
commit  893fb5bb639b0938f6762ef1165b05abae255986
tree    650d95e7a7bd89f4298d316ca5bfeb34c13ec748
parent  1129a24caff9f1804c2bff6569c0cbd8598dfa86
...
1
2
 
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,5 +1,7 @@
0
 *Edge*
0
 
0
+* Add ActiveResource::Base.find(:last). [#754 state:resolved] (Adrian Mugnolo)
0
+
0
 * Fixed problems with the logger used if the logging string included %'s [#840 state:resolved] (Jamis Buck)
0
 
0
 * Fixed Base#exists? to check status code as integer [#299 state:resolved] (Wes Oldenbeuving)
...
13
14
15
16
 
17
18
19
20
 
21
22
 
23
24
25
26
27
28
29
30
 
 
31
32
33
34
35
 
36
37
38
39
40
41
 
42
43
44
 
45
46
47
 
48
49
50
51
52
 
53
54
55
...
71
72
73
74
 
75
76
77
78
79
80
81
 
82
83
84
...
86
87
88
89
 
90
91
92
93
 
94
95
96
97
 
98
99
100
101
 
102
103
104
...
107
108
109
110
 
111
112
113
 
 
114
115
116
117
118
119
120
 
121
122
 
123
124
125
126
 
127
128
129
 
130
131
132
 
133
134
135
...
149
150
151
152
 
153
154
 
155
156
157
 
158
159
160
161
162
 
163
164
165
...
169
170
171
172
 
173
174
175
...
280
281
282
283
 
284
285
286
...
332
333
334
335
 
336
337
338
...
381
382
383
384
 
385
386
387
 
388
389
390
 
391
392
393
 
394
395
396
397
398
 
399
400
401
...
410
411
412
413
 
414
415
416
 
417
418
419
 
420
421
422
...
451
452
453
454
 
455
456
457
458
459
460
 
461
462
463
464
 
465
466
 
467
468
469
470
471
472
473
 
474
475
476
 
477
478
479
 
480
481
482
 
 
 
 
483
484
485
 
486
487
488
 
489
490
491
492
493
494
 
495
496
497
 
498
499
500
...
503
504
505
 
506
507
508
...
560
561
562
563
 
564
565
566
...
578
579
580
581
 
582
583
584
...
602
603
604
605
 
606
607
608
 
609
610
611
...
654
655
656
657
 
658
659
660
...
706
707
708
709
 
710
711
712
...
742
743
744
745
 
746
747
748
...
762
763
764
765
 
766
767
768
...
786
787
788
789
 
790
791
792
...
825
826
827
828
 
829
830
831
...
849
850
851
852
 
853
854
855
...
897
898
899
900
 
901
902
903
...
909
910
911
912
 
913
914
915
...
917
918
919
920
 
921
922
923
...
938
939
940
941
 
942
943
944
...
963
964
965
966
 
967
968
969
...
13
14
15
 
16
17
18
19
 
20
21
 
22
23
24
25
26
27
28
 
 
29
30
31
32
33
34
 
35
36
37
38
39
40
 
41
42
43
 
44
45
46
 
47
48
49
50
51
 
52
53
54
55
...
71
72
73
 
74
75
76
77
78
79
80
 
81
82
83
84
...
86
87
88
 
89
90
91
92
 
93
94
95
96
 
97
98
99
100
 
101
102
103
104
...
107
108
109
 
110
111
 
 
112
113
114
115
116
117
118
119
 
120
121
 
122
123
124
125
 
126
127
128
 
129
130
131
 
132
133
134
135
...
149
150
151
 
152
153
 
154
155
156
 
157
158
159
160
161
 
162
163
164
165
...
169
170
171
 
172
173
174
175
...
280
281
282
 
283
284
285
286
...
332
333
334
 
335
336
337
338
...
381
382
383
 
384
385
386
 
387
388
389
 
390
391
392
 
393
394
395
396
397
 
398
399
400
401
...
410
411
412
 
413
414
415
 
416
417
418
 
419
420
421
422
...
451
452
453
 
454
455
456
457
458
459
 
460
461
462
463
464
465
466
 
467
468
469
470
471
472
473
 
474
475
476
 
477
478
479
 
480
481
482
 
483
484
485
486
487
488
 
489
490
491
 
492
493
494
495
496
497
 
498
499
500
 
501
502
503
504
...
507
508
509
510
511
512
513
...
565
566
567
 
568
569
570
571
...
583
584
585
 
586
587
588
589
...
607
608
609
 
610
611
612
 
613
614
615
616
...
659
660
661
 
662
663
664
665
...
711
712
713
 
714
715
716
717
...
747
748
749
 
750
751
752
753
...
767
768
769
 
770
771
772
773
...
791
792
793
 
794
795
796
797
...
830
831
832
 
833
834
835
836
...
854
855
856
 
857
858
859
860
...
902
903
904
 
905
906
907
908
...
914
915
916
 
917
918
919
920
...
922
923
924
 
925
926
927
928
...
943
944
945
 
946
947
948
949
...
968
969
970
 
971
972
973
974
0
@@ -13,43 +13,43 @@ module ActiveResource
0
   # to Ruby objects, Active Resource only needs a class name that corresponds to the resource name (e.g., the class
0
   # Person maps to the resources people, very similarly to Active Record) and a +site+ value, which holds the
0
   # URI of the resources.
0
-  # 
0
+  #
0
   #   class Person < ActiveResource::Base
0
   #     self.site = "http://api.people.com:3000/"
0
   #   end
0
-  # 
0
+  #
0
   # Now the Person class is mapped to RESTful resources located at <tt>http://api.people.com:3000/people/</tt>, and
0
-  # you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have 
0
+  # you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
0
   # an existing model with the same name as the desired RESTful resource you can set the +element_name+ value.
0
   #
0
   #   class PersonResource < ActiveResource::Base
0
   #     self.site = "http://api.people.com:3000/"
0
   #     self.element_name = "person"
0
   #   end
0
-  #  
0
-  # 
0
+  #
0
+  #
0
   # == Lifecycle methods
0
   #
0
   # Active Resource exposes methods for creating, finding, updating, and deleting resources
0
   # from REST web services.
0
-  # 
0
+  #
0
   #   ryan = Person.new(:first => 'Ryan', :last => 'Daigle')
0
   #   ryan.save                # => true
0
   #   ryan.id                  # => 2
0
   #   Person.exists?(ryan.id)  # => true
0
   #   ryan.exists?             # => true
0
-  # 
0
+  #
0
   #   ryan = Person.find(1)
0
   #   # Resource holding our newly created Person object
0
-  # 
0
+  #
0
   #   ryan.first = 'Rizzle'
0
   #   ryan.save                # => true
0
-  # 
0
+  #
0
   #   ryan.destroy             # => true
0
   #
0
   # As you can see, these are very similar to Active Record's lifecycle methods for database records.
0
   # You can read more about each of these methods in their respective documentation.
0
-  # 
0
+  #
0
   # === Custom REST methods
0
   #
0
   # Since simple CRUD/lifecycle methods can't accomplish every task, Active Resource also supports
0
@@ -71,14 +71,14 @@ module ActiveResource
0
   #
0
   #   # DELETE to 'fire' a person, i.e. DELETE /people/1/fire.xml.
0
   #   Person.find(1).delete(:fire)
0
-  # 
0
+  #
0
   # For more information on using custom REST methods, see the
0
   # ActiveResource::CustomMethods documentation.
0
   #
0
   # == Validations
0
   #
0
   # You can validate resources client side by overriding validation methods in the base class.
0
-  # 
0
+  #
0
   #   class Person < ActiveResource::Base
0
   #      self.site = "http://api.people.com:3000/"
0
   #      protected
0
@@ -86,19 +86,19 @@ module ActiveResource
0
   #          errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
0
   #        end
0
   #   end
0
-  # 
0
+  #
0
   # See the ActiveResource::Validations documentation for more information.
0
   #
0
   # == Authentication
0
-  # 
0
+  #
0
   # Many REST APIs will require authentication, usually in the form of basic
0
   # HTTP authentication.  Authentication can be specified by:
0
   # * putting the credentials in the URL for the +site+ variable.
0
-  # 
0
+  #
0
   #    class Person < ActiveResource::Base
0
   #      self.site = "http://ryan:password@api.people.com:3000/"
0
   #    end
0
-  # 
0
+  #
0
   # * defining +user+ and/or +password+ variables
0
   #
0
   #    class Person < ActiveResource::Base
0
@@ -107,29 +107,29 @@ module ActiveResource
0
   #      self.password = "password"
0
   #    end
0
   #
0
-  # For obvious security reasons, it is probably best if such services are available 
0
+  # For obvious security reasons, it is probably best if such services are available
0
   # over HTTPS.
0
-  # 
0
-  # Note: Some values cannot be provided in the URL passed to site.  e.g. email addresses 
0
+  #
0
+  # Note: Some values cannot be provided in the URL passed to site.  e.g. email addresses
0
   # as usernames.  In those situations you should use the separate user and password option.
0
   # == Errors & Validation
0
   #
0
   # Error handling and validation is handled in much the same manner as you're used to seeing in
0
   # Active Record.  Both the response code in the HTTP response and the body of the response are used to
0
   # indicate that an error occurred.
0
-  # 
0
+  #
0
   # === Resource errors
0
-  # 
0
+  #
0
   # When a GET is requested for a resource that does not exist, the HTTP <tt>404</tt> (Resource Not Found)
0
   # response code will be returned from the server which will raise an ActiveResource::ResourceNotFound
0
   # exception.
0
-  # 
0
+  #
0
   #   # GET http://api.people.com:3000/people/999.xml
0
   #   ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound
0
-  # 
0
+  #
0
   # <tt>404</tt> is just one of the HTTP error response codes that Active Resource will handle with its own exception. The
0
   # following HTTP response codes will also result in these exceptions:
0
-  # 
0
+  #
0
   # * 200..399 - Valid response, no exception
0
   # * 404 - ActiveResource::ResourceNotFound
0
   # * 409 - ActiveResource::ResourceConflict
0
@@ -149,17 +149,17 @@ module ActiveResource
0
   #   end
0
   #
0
   # === Validation errors
0
-  # 
0
+  #
0
   # Active Resource supports validations on resources and will return errors if any these validations fail
0
-  # (e.g., "First name can not be blank" and so on).  These types of errors are denoted in the response by 
0
+  # (e.g., "First name can not be blank" and so on).  These types of errors are denoted in the response by
0
   # a response code of <tt>422</tt> and an XML representation of the validation errors.  The save operation will
0
   # then fail (with a <tt>false</tt> return value) and the validation errors can be accessed on the resource in question.
0
-  # 
0
+  #
0
   #   ryan = Person.find(1)
0
   #   ryan.first # => ''
0
   #   ryan.save  # => false
0
   #
0
-  #   # When 
0
+  #   # When
0
   #   # PUT http://api.people.com:3000/people/1.xml
0
   #   # is requested with invalid values, the response is:
0
   #   #
0
@@ -169,7 +169,7 @@ module ActiveResource
0
   #
0
   #   ryan.errors.invalid?(:first)  # => true
0
   #   ryan.errors.full_messages     # => ['First cannot be empty']
0
-  # 
0
+  #
0
   # Learn more about Active Resource's validation features in the ActiveResource::Validations documentation.
0
   #
0
   # === Timeouts
0
@@ -280,7 +280,7 @@ module ActiveResource
0
       #
0
       # Default format is <tt>:xml</tt>.
0
       def format=(mime_type_reference_or_format)
0
-        format = mime_type_reference_or_format.is_a?(Symbol) ? 
0
+        format = mime_type_reference_or_format.is_a?(Symbol) ?
0
           ActiveResource::Formats[mime_type_reference_or_format] : mime_type_reference_or_format
0
 
0
         write_inheritable_attribute("format", format)
0
@@ -332,7 +332,7 @@ module ActiveResource
0
 
0
       attr_accessor_with_default(:collection_name) { element_name.pluralize } #:nodoc:
0
       attr_accessor_with_default(:primary_key, 'id') #:nodoc:
0
-      
0
+
0
       # Gets the prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>)
0
       # This method is regenerated at runtime based on what the prefix is set to.
0
       def prefix(options={})
0
@@ -381,21 +381,21 @@ module ActiveResource
0
       # +query_options+ - A hash to add items to the query string for the request.
0
       #
0
       # ==== Examples
0
-      #   Post.element_path(1) 
0
+      #   Post.element_path(1)
0
       #   # => /posts/1.xml
0
       #
0
-      #   Comment.element_path(1, :post_id => 5) 
0
+      #   Comment.element_path(1, :post_id => 5)
0
       #   # => /posts/5/comments/1.xml
0
       #
0
-      #   Comment.element_path(1, :post_id => 5, :active => 1) 
0
+      #   Comment.element_path(1, :post_id => 5, :active => 1)
0
       #   # => /posts/5/comments/1.xml?active=1
0
       #
0
-      #   Comment.element_path(1, {:post_id => 5}, {:active => 1}) 
0
+      #   Comment.element_path(1, {:post_id => 5}, {:active => 1})
0
       #   # => /posts/5/comments/1.xml?active=1
0
       #
0
       def element_path(id, prefix_options = {}, query_options = nil)
0
         prefix_options, query_options = split_options(prefix_options) if query_options.nil?
0
-        "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"        
0
+        "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
0
       end
0
 
0
       # Gets the collection path for the REST resources.  If the +query_options+ parameter is omitted, Rails
0
@@ -410,13 +410,13 @@ module ActiveResource
0
       #   Post.collection_path
0
       #   # => /posts.xml
0
       #
0
-      #   Comment.collection_path(:post_id => 5) 
0
+      #   Comment.collection_path(:post_id => 5)
0
       #   # => /posts/5/comments.xml
0
       #
0
-      #   Comment.collection_path(:post_id => 5, :active => 1) 
0
+      #   Comment.collection_path(:post_id => 5, :active => 1)
0
       #   # => /posts/5/comments.xml?active=1
0
       #
0
-      #   Comment.collection_path({:post_id => 5}, {:active => 1}) 
0
+      #   Comment.collection_path({:post_id => 5}, {:active => 1})
0
       #   # => /posts/5/comments.xml?active=1
0
       #
0
       def collection_path(prefix_options = {}, query_options = nil)
0
@@ -451,50 +451,54 @@ module ActiveResource
0
       #   that_guy.valid? # => false
0
       #   that_guy.new?   # => true
0
       def create(attributes = {})
0
-        returning(self.new(attributes)) { |res| res.save }        
0
+        returning(self.new(attributes)) { |res| res.save }
0
       end
0
 
0
       # Core method for finding resources.  Used similarly to Active Record's +find+ method.
0
       #
0
       # ==== Arguments
0
-      # The first argument is considered to be the scope of the query.  That is, how many 
0
+      # The first argument is considered to be the scope of the query.  That is, how many
0
       # resources are returned from the request.  It can be one of the following.
0
       #
0
       # * <tt>:one</tt> - Returns a single resource.
0
       # * <tt>:first</tt> - Returns the first resource found.
0
+      # * <tt>:last</tt> - Returns the last resource found.
0
       # * <tt>:all</tt> - Returns every resource that matches the request.
0
-      # 
0
+      #
0
       # ==== Options
0
       #
0
       # * <tt>:from</tt> - Sets the path or custom method that resources will be fetched from.
0
       # * <tt>:params</tt> - Sets query and prefix (nested URL) parameters.
0
       #
0
       # ==== Examples
0
-      #   Person.find(1)                                         
0
+      #   Person.find(1)
0
       #   # => GET /people/1.xml
0
       #
0
-      #   Person.find(:all)                                      
0
+      #   Person.find(:all)
0
       #   # => GET /people.xml
0
       #
0
-      #   Person.find(:all, :params => { :title => "CEO" })      
0
+      #   Person.find(:all, :params => { :title => "CEO" })
0
       #   # => GET /people.xml?title=CEO
0
       #
0
-      #   Person.find(:first, :from => :managers)                  
0
+      #   Person.find(:first, :from => :managers)
0
+      #   # => GET /people/managers.xml
0
+      #
0
+      #   Person.find(:last, :from => :managers)
0
       #   # => GET /people/managers.xml
0
       #
0
-      #   Person.find(:all, :from => "/companies/1/people.xml")  
0
+      #   Person.find(:all, :from => "/companies/1/people.xml")
0
       #   # => GET /companies/1/people.xml
0
       #
0
-      #   Person.find(:one, :from => :leader)                    
0
+      #   Person.find(:one, :from => :leader)
0
       #   # => GET /people/leader.xml
0
       #
0
       #   Person.find(:all, :from => :developers, :params => { :language => 'ruby' })
0
       #   # => GET /people/developers.xml?language=ruby
0
       #
0
-      #   Person.find(:one, :from => "/companies/1/manager.xml") 
0
+      #   Person.find(:one, :from => "/companies/1/manager.xml")
0
       #   # => GET /companies/1/manager.xml
0
       #
0
-      #   StreetAddress.find(1, :params => { :person_id => 1 })  
0
+      #   StreetAddress.find(1, :params => { :person_id => 1 })
0
       #   # => GET /people/1/street_addresses/1.xml
0
       def find(*arguments)
0
         scope   = arguments.slice!(0)
0
@@ -503,6 +507,7 @@ module ActiveResource
0
         case scope
0
           when :all   then find_every(options)
0
           when :first then find_every(options).first
0
+          when :last  then find_every(options).last
0
           when :one   then find_one(options)
0
           else             find_single(scope, options)
0
         end
0
@@ -560,7 +565,7 @@ module ActiveResource
0
             instantiate_collection( (connection.get(path, headers) || []), prefix_options )
0
           end
0
         end
0
-        
0
+
0
         # Find a single resource from a one-off URL
0
         def find_one(options)
0
           case from = options[:from]
0
@@ -578,7 +583,7 @@ module ActiveResource
0
           path = element_path(scope, prefix_options, query_options)
0
           instantiate_record(connection.get(path, headers), prefix_options)
0
         end
0
-        
0
+
0
         def instantiate_collection(collection, prefix_options = {})
0
           collection.collect! { |record| instantiate_record(record, prefix_options) }
0
         end
0
@@ -602,10 +607,10 @@ module ActiveResource
0
 
0
         # Builds the query string for the request.
0
         def query_string(options)
0
-          "?#{options.to_query}" unless options.nil? || options.empty? 
0
+          "?#{options.to_query}" unless options.nil? || options.empty?
0
         end
0
 
0
-        # split an option hash into two hashes, one containing the prefix options, 
0
+        # split an option hash into two hashes, one containing the prefix options,
0
         # and the other containing the leftovers.
0
         def split_options(options = {})
0
           prefix_options, query_options = {}, {}
0
@@ -654,7 +659,7 @@ module ActiveResource
0
     #   ryan = Person.find(1)
0
     #   ryan.address = StreetAddress.find(1, :person_id => ryan.id)
0
     #   ryan.hash = {:not => "an ARes instance"}
0
-    #   
0
+    #
0
     #   not_ryan = ryan.clone
0
     #   not_ryan.new?            # => true
0
     #   not_ryan.address         # => NoMethodError
0
@@ -706,7 +711,7 @@ module ActiveResource
0
       id && id.to_s
0
     end
0
 
0
-    # Test for equality.  Resource are equal if and only if +other+ is the same object or 
0
+    # Test for equality.  Resource are equal if and only if +other+ is the same object or
0
     # is an instance of the same class, is not <tt>new?</tt>, and has the same +id+.
0
     #
0
     # ==== Examples
0
@@ -742,7 +747,7 @@ module ActiveResource
0
     def hash
0
       id.hash
0
     end
0
-    
0
+
0
     # Duplicate the current resource without saving it.
0
     #
0
     # ==== Examples
0
@@ -762,7 +767,7 @@ module ActiveResource
0
       end
0
     end
0
 
0
-    # A method to save (+POST+) or update (+PUT+) a resource.  It delegates to +create+ if a new object, 
0
+    # A method to save (+POST+) or update (+PUT+) a resource.  It delegates to +create+ if a new object,
0
     # +update+ if it is existing. If the response to the save includes a body, it will be assumed that this body
0
     # is XML for the final object as it looked after the save (which would include attributes like +created_at+
0
     # that weren't part of the original submit).
0
@@ -786,7 +791,7 @@ module ActiveResource
0
     #   my_person = Person.find(my_id)
0
     #   my_person.destroy
0
     #   Person.find(my_id) # 404 (Resource Not Found)
0
-    #   
0
+    #
0
     #   new_person = Person.create(:name => 'James')
0
     #   new_id = new_person.id # => 7
0
     #   new_person.destroy
0
@@ -825,7 +830,7 @@ module ActiveResource
0
     # * <tt>:indent</tt> - Set the indent level for the XML output (default is +2+).
0
     # * <tt>:dasherize</tt> - Boolean option to determine whether or not element names should
0
     #   replace underscores with dashes (default is <tt>false</tt>).
0
-    # * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder 
0
+    # * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
0
     #   that generates the XML declaration (default is <tt>false</tt>).
0
     #
0
     # ==== Examples
0
@@ -849,7 +854,7 @@ module ActiveResource
0
     # ==== Examples
0
     #   my_branch = Branch.find(:first)
0
     #   my_branch.name # => "Wislon Raod"
0
-    #   
0
+    #
0
     #   # Another client fixes the typo...
0
     #
0
     #   my_branch.name # => "Wislon Raod"
0
@@ -897,7 +902,7 @@ module ActiveResource
0
       end
0
       self
0
     end
0
-    
0
+
0
     # For checking <tt>respond_to?</tt> without searching the attributes (which is faster).
0
     alias_method :respond_to_without_attributes?, :respond_to?
0
 
0
@@ -909,7 +914,7 @@ module ActiveResource
0
       if attributes.nil?
0
         return super
0
       elsif attributes.has_key?(method_name)
0
-        return true 
0
+        return true
0
       elsif ['?','='].include?(method_name.last) && attributes.has_key?(method_name.first(-1))
0
         return true
0
       end
0
@@ -917,7 +922,7 @@ module ActiveResource
0
       # would return true for generated readers, even if the attribute wasn't present
0
       super
0
     end
0
-    
0
+
0
 
0
     protected
0
       def connection(refresh = false)
0
@@ -938,7 +943,7 @@ module ActiveResource
0
           load_attributes_from_response(response)
0
         end
0
       end
0
-      
0
+
0
       def load_attributes_from_response(response)
0
         if response['Content-Length'] != "0" && response.body.strip.size > 0
0
           load(self.class.format.decode(response.body))
0
@@ -963,7 +968,7 @@ module ActiveResource
0
       def find_or_create_resource_for_collection(name)
0
         find_or_create_resource_for(name.to_s.singularize)
0
       end
0
-      
0
+
0
       # Tries to find a resource in a non empty list of nested modules
0
       # Raises a NameError if it was not found in any of the given nested modules
0
       def find_resource_in_modules(resource_name, module_names)
...
8
9
10
11
 
12
13
14
...
50
51
52
53
 
54
55
56
...
62
63
64
65
 
66
67
68
...
101
102
103
104
 
105
106
 
107
108
109
110
 
111
112
113
...
194
195
196
197
198
 
 
199
200
201
 
202
203
204
 
205
206
207
208
 
209
210
211
...
317
318
319
320
 
321
322
323
 
324
325
326
327
 
328
329
330
...
393
394
395
396
 
397
398
399
400
401
402
403
 
404
405
406
407
408
409
410
 
411
412
 
413
414
415
416
 
417
418
419
420
421
422
423
 
424
425
426
...
470
471
472
473
 
474
475
476
477
478
479
480
 
481
482
483
484
485
486
487
 
488
489
490
...
504
505
506
507
 
508
509
510
...
533
534
535
 
 
 
 
 
 
536
537
538
...
547
548
549
550
 
551
552
553
...
555
556
557
558
 
559
560
561
...
563
564
565
566
 
567
568
569
...
593
594
595
596
 
597
598
599
...
610
611
612
613
 
614
615
616
617
618
 
619
620
621
622
 
623
624
625
...
634
635
636
637
638
639
 
 
 
640
641
642
643
 
644
645
646
...
650
651
652
653
 
654
655
656
657
 
658
659
660
...
716
717
718
719
 
720
721
722
...
748
749
750
751
 
752
753
754
...
778
779
780
781
 
782
783
784
785
 
786
787
788
789
790
791
 
792
793
794
 
795
796
797
 
798
799
800
...
806
807
808
809
810
 
 
811
812
813
...
8
9
10
 
11
12
13
14
...
50
51
52
 
53
54
55
56
...
62
63
64
 
65
66
67
68
...
101
102
103
 
104
105
 
106
107
108
109
 
110
111
112
113
...
194
195
196
 
 
197
198
199
200
 
201
202
203
 
204
205
206
207
 
208
209
210
211
...
317
318
319
 
320
321
322
 
323
324
325
326
 
327
328
329
330
...
393
394
395
 
396
397
398
399
400
401
402
 
403
404
405
406
407
408
409
 
410
411
 
412
413
414
415
 
416
417
418
419
420
421
422
 
423
424
425
426
...
470
471
472
 
473
474
475
476
477
478
479
 
480
481
482
483
484
485
486
 
487
488
489
490
...
504
505
506
 
507
508
509
510
...
533
534
535
536
537
538
539
540
541
542
543
544
...
553
554
555
 
556
557
558
559
...
561
562
563
 
564
565
566
567
...
569
570
571
 
572
573
574
575
...
599
600
601
 
602
603
604
605
...
616
617
618
 
619
620
621
622
623
 
624
625
626
627
 
628
629
630
631
...
640
641
642
 
 
 
643
644
645
646
647
648
 
649
650
651
652
...
656
657
658
 
659
660
661
662
 
663
664
665
666
...
722
723
724
 
725
726
727
728
...
754
755
756
 
757
758
759
760
...
784
785
786
 
787
788
789
790
 
791
792
793
794
795
796
 
797
798
799
 
800
801
802
 
803
804
805
806
...
812
813
814
 
 
815
816
817
818
819
0
@@ -8,7 +8,7 @@ class BaseTest < Test::Unit::TestCase
0
   def setup
0
     @matz  = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
0
     @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
0
-    @greg  = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')    
0
+    @greg  = { :id => 3, :name => 'Greg' }.to_xml(:root => 'person')
0
     @addy  = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address')
0
     @default_request_headers = { 'Content-Type' => 'application/xml' }
0
     @rick = { :name => "Rick", :age => 25 }.to_xml(:root => "person")
0
@@ -50,7 +50,7 @@ class BaseTest < Test::Unit::TestCase
0
     ActiveResource::HttpMock.respond_to do |mock|
0
       mock.get    "/people/1.xml",                {}, @matz
0
       mock.get    "/people/2.xml",                {}, @david
0
-      mock.get    "/people/Greg.xml",             {}, @greg      
0
+      mock.get    "/people/Greg.xml",             {}, @greg
0
       mock.get    "/people/4.xml",                {'key' => 'value'}, nil, 404
0
       mock.put    "/people/1.xml",                {}, nil, 204
0
       mock.delete "/people/1.xml",                {}, nil, 200
0
@@ -62,7 +62,7 @@ class BaseTest < Test::Unit::TestCase
0
       mock.get    "/people/1/addresses/1.xml",    {}, @addy
0
       mock.get    "/people/1/addresses/2.xml",    {}, nil, 404
0
       mock.get    "/people/2/addresses/1.xml",    {}, nil, 404
0
-      mock.get    "/people/Greg/addresses/1.xml", {}, @addy      
0
+      mock.get    "/people/Greg/addresses/1.xml", {}, @addy
0
       mock.put    "/people/1/addresses/1.xml",    {}, nil, 204
0
       mock.delete "/people/1/addresses/1.xml",    {}, nil, 200
0
       mock.post   "/people/1/addresses.xml",      {}, nil, 201, 'Location' => '/people/1/addresses/5'
0
@@ -101,13 +101,13 @@ class BaseTest < Test::Unit::TestCase
0
     assert_equal 'http://foo:bar@beast.caboo.se', Forum.site.to_s
0
     assert_equal 'http://foo:bar@beast.caboo.se/forums/:forum_id', Topic.site.to_s
0
   end
0
-  
0
+
0
   def test_site_variable_can_be_reset
0
-    actor = Class.new(ActiveResource::Base)    
0
+    actor = Class.new(ActiveResource::Base)
0
     assert_nil actor.site
0
     actor.site = 'http://localhost:31337'
0
     actor.site = nil
0
-    assert_nil actor.site    
0
+    assert_nil actor.site
0
   end
0
 
0
   def test_should_accept_setting_user
0
@@ -194,18 +194,18 @@ class BaseTest < Test::Unit::TestCase
0
     actor.site = 'http://nomad'
0
     assert_equal actor.site, jester.site
0
     assert jester.site.frozen?
0
-    
0
-    # Subclasses are always equal to superclass site when not overridden    
0
+
0
+    # Subclasses are always equal to superclass site when not overridden
0
     fruit = Class.new(ActiveResource::Base)
0
     apple = Class.new(fruit)
0
-    
0
+
0
     fruit.site = 'http://market'
0
     assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
0
-    
0
+
0
     fruit.site = 'http://supermarket'
0
     assert_equal fruit.site, apple.site, 'subclass did not adopt changes from parent class'
0
   end
0
-  
0
+
0
   def test_user_reader_uses_superclass_user_until_written
0
     # Superclass is Object so returns nil.
0
     assert_nil ActiveResource::Base.user
0
@@ -317,14 +317,14 @@ class BaseTest < Test::Unit::TestCase
0
   end
0
 
0
   def test_updating_baseclass_site_object_wipes_descendent_cached_connection_objects
0
-    # Subclasses are always equal to superclass site when not overridden    
0
+    # Subclasses are always equal to superclass site when not overridden
0
     fruit = Class.new(ActiveResource::Base)
0
     apple = Class.new(fruit)
0
-    
0
+
0
     fruit.site = 'http://market'
0
     assert_equal fruit.connection.site, apple.connection.site
0
     first_connection = apple.connection.object_id
0
-    
0
+
0
     fruit.site = 'http://supermarket'
0
     assert_equal fruit.connection.site, apple.connection.site
0
     second_connection = apple.connection.object_id
0
@@ -393,34 +393,34 @@ class BaseTest < Test::Unit::TestCase
0
     assert_equal '/people.xml?gender=', Person.collection_path(:gender => nil)
0
 
0
     assert_equal '/people.xml?gender=male', Person.collection_path('gender' => 'male')
0
-    
0
+
0
     # Use includes? because ordering of param hash is not guaranteed
0
     assert Person.collection_path(:gender => 'male', :student => true).include?('/people.xml?')
0
     assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male')
0
     assert Person.collection_path(:gender => 'male', :student => true).include?('student=true')
0
 
0
     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])
0
-    
0
+
0
     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'})
0
   end
0
 
0
   def test_custom_element_path
0
     assert_equal '/people/1/addresses/1.xml', StreetAddress.element_path(1, :person_id => 1)
0
     assert_equal '/people/1/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 1)
0
-    assert_equal '/people/Greg/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 'Greg')    
0
+    assert_equal '/people/Greg/addresses/1.xml', StreetAddress.element_path(1, 'person_id' => 'Greg')
0
   end
0
-  
0
+
0
   def test_custom_element_path_with_redefined_to_param
0
     Person.module_eval do
0
       alias_method :original_to_param_element_path, :to_param
0
-       def to_param  
0
+       def to_param
0
          name
0
        end
0
     end
0
 
0
     # Class method.
0
     assert_equal '/people/Greg.xml', Person.element_path('Greg')
0
-    
0
+
0
     # Protected Instance method.
0
     assert_equal '/people/Greg.xml', Person.find('Greg').send(:element_path)
0
 
0
@@ -470,21 +470,21 @@ class BaseTest < Test::Unit::TestCase
0
     assert_equal "/", Person.prefix
0
     assert_equal Set.new, Person.send!(:prefix_parameters)
0
   end
0
-  
0
+
0
   def test_set_prefix
0
     SetterTrap.rollback_sets(Person) do |person_class|
0
       person_class.prefix = "the_prefix"
0
       assert_equal "the_prefix", person_class.prefix
0
     end
0
   end
0
-  
0
+
0
   def test_set_prefix_with_inline_keys
0
     SetterTrap.rollback_sets(Person) do |person_class|
0
       person_class.prefix = "the_prefix:the_param"
0
       assert_equal "the_prefixthe_param_value", person_class.prefix(:the_param => "the_param_value")
0
     end
0
   end
0
-  
0
+
0
   def test_set_prefix_with_default_value
0
     SetterTrap.rollback_sets(Person) do |person_class|
0
       person_class.set_prefix
0
@@ -504,7 +504,7 @@ class BaseTest < Test::Unit::TestCase
0
     assert_equal "Matz", matz.name
0
     assert matz.name?
0
   end
0
-  
0
+
0
   def test_respond_to
0
     matz = Person.find(1)
0
     assert matz.respond_to?(:name)
0
@@ -533,6 +533,12 @@ class BaseTest < Test::Unit::TestCase
0
     assert_equal "Matz", matz.name
0
   end
0
 
0
+  def test_find_last
0
+    david = Person.find(:last)
0
+    assert_kind_of Person, david
0
+    assert_equal 'David', david.name
0
+  end
0
+
0
   def test_custom_header
0
     Person.headers['key'] = 'value'
0
     assert_raises(ActiveResource::ResourceNotFound) { Person.find(4) }
0
@@ -547,7 +553,7 @@ class BaseTest < Test::Unit::TestCase
0
 
0
   def test_find_all_by_from
0
     ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david }
0
-  
0
+
0
     people = Person.find(:all, :from => "/companies/1/people.xml")
0
     assert_equal 1, people.size
0
     assert_equal "David", people.first.name
0
@@ -555,7 +561,7 @@ class BaseTest < Test::Unit::TestCase
0
 
0
   def test_find_all_by_from_with_options
0
     ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david }
0
-  
0
+
0
     people = Person.find(:all, :from => "/companies/1/people.xml")
0
     assert_equal 1, people.size
0
     assert_equal "David", people.first.name
0
@@ -563,7 +569,7 @@ class BaseTest < Test::Unit::TestCase
0
 
0
   def test_find_all_by_symbol_from
0
     ActiveResource::HttpMock.respond_to { |m| m.get "/people/managers.xml", {}, @people_david }
0
-  
0
+
0
     people = Person.find(:all, :from => :managers)
0
     assert_equal 1, people.size
0
     assert_equal "David", people.first.name
0
@@ -593,7 +599,7 @@ class BaseTest < Test::Unit::TestCase
0
     p = Person.new
0
     resp = {'Location' => '/foo/bar/1'}
0
     assert_equal '1', p.send!(:id_from_response, resp)
0
-    
0
+
0
     resp['Location'] << '.xml'
0
     assert_equal '1', p.send!(:id_from_response, resp)
0
   end
0
@@ -610,16 +616,16 @@ class BaseTest < Test::Unit::TestCase
0
     ryan = Person.new(:id => 1, :name => 'Ryan', :address => address)
0
     assert_equal address.prefix_options, ryan.address.prefix_options
0
   end
0
-  
0
+
0
   def test_reload_works_with_prefix_options
0
     address = StreetAddress.find(1, :params => { :person_id => 1 })
0
     assert_equal address, address.reload
0
   end
0
-  
0
+
0
   def test_reload_with_redefined_to_param
0
     Person.module_eval do
0
       alias_method :original_to_param_reload, :to_param
0
-       def to_param  
0
+       def to_param
0
          name
0
        end
0
     end
0
@@ -634,13 +640,13 @@ class BaseTest < Test::Unit::TestCase
0
         alias_method :reload_to_param, :to_param
0
         alias_method :to_param, :original_to_param_reload
0
       end
0
-  end  
0
-  
0
-  def test_reload_works_without_prefix_options    
0
+  end
0
+
0
+  def test_reload_works_without_prefix_options
0
     person = Person.find(:first)
0
     assert_equal person, person.reload
0
   end
0
-    
0
+
0
 
0
   def test_create
0
     rick = Person.create(:name => 'Rick')
0
@@ -650,11 +656,11 @@ class BaseTest < Test::Unit::TestCase
0
 
0
     # test additional attribute returned on create
0
     assert_equal 25, rick.age
0
-    
0
+
0
     # Test that save exceptions get bubbled up too
0
     ActiveResource::HttpMock.respond_to do |mock|
0
       mock.post   "/people.xml", {}, nil, 409
0
-    end    
0
+    end
0
     assert_raises(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') }
0
   end
0
 
0
@@ -716,7 +722,7 @@ class BaseTest < Test::Unit::TestCase
0
     assert_equal "54321 Lane", addy.street
0
     addy.save
0
   end
0
-  
0
+
0
   def test_update_conflict
0
     ActiveResource::HttpMock.respond_to do |mock|
0
       mock.get "/people/2.xml", {}, @david
0
@@ -748,7 +754,7 @@ class BaseTest < Test::Unit::TestCase
0
     end
0
     assert_raises(ActiveResource::ResourceNotFound) { Person.find(1) }
0
   end
0
-  
0
+
0
   def test_delete_with_custom_prefix
0
     assert StreetAddress.delete(1, :person_id => 1)
0
     ActiveResource::HttpMock.respond_to do |mock|
0
@@ -778,23 +784,23 @@ class BaseTest < Test::Unit::TestCase
0
     assert !StreetAddress.new({:id => 1, :person_id => 2}).exists?
0
     assert !StreetAddress.new({:id => 2, :person_id => 1}).exists?
0
   end
0
-  
0
+
0
   def test_exists_with_redefined_to_param
0
     Person.module_eval do
0
       alias_method :original_to_param_exists, :to_param
0
-       def to_param  
0
+       def to_param
0
          name
0
        end
0
     end
0
 
0
     # Class method.
0
-    assert Person.exists?('Greg')    
0
+    assert Person.exists?('Greg')
0
 
0
     # Instance method.
0
-    assert Person.find('Greg').exists?    
0
+    assert Person.find('Greg').exists?
0
 
0
     # Nested class method.
0
-    assert StreetAddress.exists?(1,  :params => { :person_id => Person.find('Greg').to_param })    
0
+    assert StreetAddress.exists?(1,  :params => { :person_id => Person.find('Greg').to_param })
0
 
0
     # Nested instance method.
0
     assert StreetAddress.find(1, :params => { :person_id => Person.find('Greg').to_param }).exists?
0
@@ -806,8 +812,8 @@ class BaseTest < Test::Unit::TestCase
0
         alias_method :exists_to_param, :to_param
0
         alias_method :to_param, :original_to_param_exists
0
       end
0
-  end  
0
-  
0
+  end
0
+
0
   def test_to_xml
0
     matz = Person.find(1)
0
     xml = matz.to_xml

Comments