Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 9121

Show
Ignore:
Timestamp:
03/28/08 21:17:38 (1 month ago)
Author:
bitsweat
Message:

Add #clone. Closes #7352 [Ryan Daigle, thechrisoshow]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activeresource/lib/active_resource/base.rb

    r9114 r9121  
    607607    end 
    608608 
     609    # Returns a clone of the resource that hasn't been assigned an id yet and 
     610    # is treated as a new resource. 
     611    # 
     612    #  ryan = Person.find(1) 
     613    #  not_ryan = ryan.clone 
     614    #  not_ryan.new?  # => true 
     615    # 
     616    # Any active resource member attributes will NOT be cloned, though all other 
     617    # attributes are.  This is to prevent the conflict between any prefix_options 
     618    # that refer to the original parent resource and the newly cloned parent 
     619    # resource that does not exist. 
     620    # 
     621    #  ryan = Person.find(1) 
     622    #  ryan.address = StreetAddress.find(1, :person_id => ryan.id) 
     623    #  ryan.hash = {:not => "an ARes instance"} 
     624    # 
     625    #  not_ryan = ryan.clone 
     626    #  not_ryan.new?            # => true 
     627    #  not_ryan.address         # => NoMethodError 
     628    #  not_ryan.hash            # => {:not => "an ARes instance"} 
     629    # 
     630    def clone 
     631      # Clone all attributes except the pk and any nested ARes 
     632      attrs = self.attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.inject({}) do |attrs, (k, v)| 
     633        attrs[k] = v.clone 
     634        attrs 
     635      end 
     636      # Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which 
     637      # attempts to convert hashes into member objects and arrays into collections of objects.  We want 
     638      # the raw objects to be cloned so we bypass load by directly setting the attributes hash. 
     639      resource = self.class.new({}) 
     640      resource.prefix_options = self.prefix_options 
     641      resource.send :instance_variable_set, '@attributes', attrs 
     642      resource 
     643    end 
     644 
     645 
    609646    # A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet). 
    610647    # 
  • trunk/activeresource/test/base_test.rb

    r9114 r9121  
    559559  end 
    560560 
     561  def test_clone 
     562   matz = Person.find(1) 
     563   matz_c = matz.clone 
     564   assert matz_c.new? 
     565   matz.attributes.each do |k, v| 
     566     assert_equal v, matz_c.send(k) if k != Person.primary_key 
     567   end 
     568 end 
     569 
     570 def test_nested_clone 
     571   addy = StreetAddress.find(1, :params => {:person_id => 1}) 
     572   addy_c = addy.clone 
     573   assert addy_c.new? 
     574   addy.attributes.each do |k, v| 
     575     assert_equal v, addy_c.send(k) if k != StreetAddress.primary_key 
     576   end 
     577   assert_equal addy.prefix_options, addy_c.prefix_options 
     578 end 
     579 
     580 def test_complex_clone 
     581   matz = Person.find(1) 
     582   matz.address = StreetAddress.find(1, :params => {:person_id => matz.id}) 
     583   matz.non_ar_hash = {:not => "an ARes instance"} 
     584   matz.non_ar_arr = ["not", "ARes"] 
     585   matz_c = matz.clone 
     586   assert matz_c.new? 
     587   assert_raises(NoMethodError) {matz_c.address} 
     588   assert_equal matz.non_ar_hash, matz_c.non_ar_hash 
     589   assert_equal matz.non_ar_arr, matz_c.non_ar_arr 
     590 
     591   # Test that actual copy, not just reference copy 
     592   matz.non_ar_hash[:not] = "changed" 
     593   assert_not_equal matz.non_ar_hash, matz_c.non_ar_hash 
     594 end 
     595 
    561596  def test_update 
    562597    matz = Person.find(:first)