public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Add #clone. Closes #7352 [Ryan Daigle, thechrisoshow]


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@9121 
5ecf4fe2-1ee6-0310-87b1-e25e094e27de
jeremy (author)
Fri Mar 28 14:17:38 -0700 2008
commit  ad8df03f9c831d88b8a7eb80c1b7dbcf02fc1b19
tree    e38fac0f66c06e576e0127a9553fed5f26c297ed
parent  5c0656c9ee9ecc7ffeebea69dc0cd371d978b254
...
606
607
608
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
609
610
611
...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
0
@@ -606,6 +606,43 @@ module ActiveResource
0
       load(attributes)
0
     end
0
 
0
+ # Returns a clone of the resource that hasn't been assigned an id yet and
0
+ # is treated as a new resource.
0
+ #
0
+ # ryan = Person.find(1)
0
+ # not_ryan = ryan.clone
0
+ # not_ryan.new? # => true
0
+ #
0
+ # Any active resource member attributes will NOT be cloned, though all other
0
+ # attributes are. This is to prevent the conflict between any prefix_options
0
+ # that refer to the original parent resource and the newly cloned parent
0
+ # resource that does not exist.
0
+ #
0
+ # ryan = Person.find(1)
0
+ # ryan.address = StreetAddress.find(1, :person_id => ryan.id)
0
+ # ryan.hash = {:not => "an ARes instance"}
0
+ #
0
+ # not_ryan = ryan.clone
0
+ # not_ryan.new? # => true
0
+ # not_ryan.address # => NoMethodError
0
+ # not_ryan.hash # => {:not => "an ARes instance"}
0
+ #
0
+ def clone
0
+ # Clone all attributes except the pk and any nested ARes
0
+ attrs = self.attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.inject({}) do |attrs, (k, v)|
0
+ attrs[k] = v.clone
0
+ attrs
0
+ end
0
+ # Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
0
+ # attempts to convert hashes into member objects and arrays into collections of objects. We want
0
+ # the raw objects to be cloned so we bypass load by directly setting the attributes hash.
0
+ resource = self.class.new({})
0
+ resource.prefix_options = self.prefix_options
0
+ resource.send :instance_variable_set, '@attributes', attrs
0
+ resource
0
+ end
0
+
0
+
0
     # A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet).
0
     #
0
     # ==== Examples
...
558
559
560
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
561
562
563
...
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
0
@@ -558,6 +558,41 @@ class BaseTest < Test::Unit::TestCase
0
     assert_raises(ActiveResource::ResourceConflict) { Person.create(:name => 'Rick') }
0
   end
0
 
0
+ def test_clone
0
+ matz = Person.find(1)
0
+ matz_c = matz.clone
0
+ assert matz_c.new?
0
+ matz.attributes.each do |k, v|
0
+ assert_equal v, matz_c.send(k) if k != Person.primary_key
0
+ end
0
+ end
0
+
0
+ def test_nested_clone
0
+ addy = StreetAddress.find(1, :params => {:person_id => 1})
0
+ addy_c = addy.clone
0
+ assert addy_c.new?
0
+ addy.attributes.each do |k, v|
0
+ assert_equal v, addy_c.send(k) if k != StreetAddress.primary_key
0
+ end
0
+ assert_equal addy.prefix_options, addy_c.prefix_options
0
+ end
0
+
0
+ def test_complex_clone
0
+ matz = Person.find(1)
0
+ matz.address = StreetAddress.find(1, :params => {:person_id => matz.id})
0
+ matz.non_ar_hash = {:not => "an ARes instance"}
0
+ matz.non_ar_arr = ["not", "ARes"]
0
+ matz_c = matz.clone
0
+ assert matz_c.new?
0
+ assert_raises(NoMethodError) {matz_c.address}
0
+ assert_equal matz.non_ar_hash, matz_c.non_ar_hash
0
+ assert_equal matz.non_ar_arr, matz_c.non_ar_arr
0
+
0
+ # Test that actual copy, not just reference copy
0
+ matz.non_ar_hash[:not] = "changed"
0
+ assert_not_equal matz.non_ar_hash, matz_c.non_ar_hash
0
+ end
0
+
0
   def test_update
0
     matz = Person.find(:first)
0
     matz.name = "David"

Comments

    No one has commented yet.