deep_cloneable 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -19,3 +19,5 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
+
23
+ test/debug.log
@@ -37,6 +37,18 @@ And include the gem in your apps config
37
37
 
38
38
  === Cloning really deep with multiple associations
39
39
  pirate.clone :include => [:mateys, {:treasures => :gold_pieces}]
40
+
41
+ === Cloning really deep with multiple associations and a dictionary
42
+
43
+ A dictionary ensures that models are not cloned multiple times when it is associated to nested models.
44
+ When using a dictionary, ensure recurring associations are cloned first:
45
+
46
+ pirate.clone :include => [:mateys, {:treasures => [:matey, :gold_pieces], :use_dictionary => true }]
47
+
48
+ If this is not an option for you, it is also possible to populate the dictionary manually in advance:
49
+
50
+ dict = { :mateys => {} }
51
+ pirate.mateys.each{|m| dict[:mateys][m] = m.clone }
40
52
 
41
53
  === Cloning a model without an attribute
42
54
  pirate.clone :except => :name
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{deep_cloneable}
8
- s.version = "1.1.0"
8
+ s.version = "1.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Reinier de Lange"]
12
- s.date = %q{2010-10-19}
12
+ s.date = %q{2010-10-20}
13
13
  s.description = %q{Extends the functionality of ActiveRecord::Base#clone to perform a deep clone that includes user specified associations. }
14
14
  s.email = %q{r.j.delange@nedforce.nl}
15
15
  s.extra_rdoc_files = [
@@ -17,7 +17,20 @@ class ActiveRecord::Base
17
17
  #
18
18
  # ==== Cloning really deep with multiple associations
19
19
  # pirate.clone :include => [:mateys, {:treasures => :gold_pieces}]
20
- #
20
+ #
21
+ # ==== Cloning really deep with multiple associations and a dictionary
22
+ #
23
+ # A dictionary ensures that models are not cloned multiple times when it is associated to nested models.
24
+ # When using a dictionary, ensure recurring associations are cloned first:
25
+ #
26
+ # pirate.clone :include => [:mateys, {:treasures => [:matey, :gold_pieces], :use_dictionary => true }]
27
+ #
28
+ # If this is not an option for you, it is also possible to populate the dictionary manually in advance:
29
+ #
30
+ # dict = { :mateys => {} }
31
+ # pirate.mateys.each{|m| dict[:mateys][m] = m.clone }
32
+ # pirate.clone :include => [:mateys, {:treasures => [:matey, :gold_pieces], :dictionary => dict }]
33
+ #
21
34
  # ==== Cloning a model without an attribute
22
35
  # pirate.clone :except => :name
23
36
  #
@@ -28,7 +41,16 @@ class ActiveRecord::Base
28
41
  # pirate.clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
29
42
  #
30
43
  def clone(options = {})
31
- kopy = super()
44
+ dict = options[:dictionary]
45
+ dict ||= {} if options.delete(:use_dictionary)
46
+
47
+ kopy = unless dict
48
+ super()
49
+ else
50
+ tableized_class = self.class.name.tableize.to_sym
51
+ dict[tableized_class] ||= {}
52
+ dict[tableized_class][self] ||= super()
53
+ end
32
54
 
33
55
  deep_exceptions = {}
34
56
  if options[:except]
@@ -48,6 +70,7 @@ class ActiveRecord::Base
48
70
 
49
71
  opts = deep_associations.blank? ? {} : {:include => deep_associations}
50
72
  opts.merge!(:except => deep_exceptions[association]) if deep_exceptions[association]
73
+ opts.merge!(:dictionary => dict) if dict
51
74
 
52
75
  association_reflection = self.class.reflect_on_association(association)
53
76
  cloned_object = case association_reflection.macro
@@ -18,6 +18,7 @@ ActiveRecord::Schema.define(:version => 1) do
18
18
  create_table :treasures, :force => true do |t|
19
19
  t.column :found_at, :string
20
20
  t.column :pirate_id, :integer
21
+ t.column :matey_id, :integer
21
22
  end
22
23
 
23
24
  create_table :gold_pieces, :force => true do |t|
@@ -7,7 +7,7 @@ class TestDeepCloneable < Test::Unit::TestCase
7
7
  @jack = Pirate.create(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
8
8
  @polly = Parrot.create(:name => 'Polly', :pirate => @jack)
9
9
  @john = Matey.create(:name => 'John', :pirate => @jack)
10
- @treasure = Treasure.create(:found_at => 'Isla del Muerte', :pirate => @jack)
10
+ @treasure = Treasure.create(:found_at => 'Isla del Muerte', :pirate => @jack, :matey => @john)
11
11
  @gold_piece = GoldPiece.create(:treasure => @treasure)
12
12
  end
13
13
 
@@ -76,4 +76,24 @@ class TestDeepCloneable < Test::Unit::TestCase
76
76
  assert_not_nil @jack.parrot.name
77
77
  assert_nil clone.parrot.name
78
78
  end
79
+
80
+ def test_should_not_double_clone_when_using_dictionary
81
+ current_matey_count = Matey.count
82
+ clone = @jack.clone(:include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
83
+ clone.save!
84
+
85
+ assert_equal current_matey_count + 1, Matey.count
86
+ end
87
+
88
+ def test_should_not_double_clone_when_using_manual_dictionary
89
+ current_matey_count = Matey.count
90
+
91
+ dict = { :mateys => {} }
92
+ @jack.mateys.each{|m| dict[:mateys][m] = m.clone }
93
+
94
+ clone = @jack.clone(:include => [:mateys, { :treasures => :matey }], :dictionary => dict)
95
+ clone.save!
96
+
97
+ assert_equal current_matey_count + 1, Matey.count
98
+ end
79
99
  end
@@ -10,9 +10,9 @@ require 'active_record'
10
10
  require 'active_record/fixtures'
11
11
  require File.dirname(__FILE__) + '/../init.rb'
12
12
 
13
- class GoldPiece < ActiveRecord::Base; belongs_to :treasure end
14
- class Matey < ActiveRecord::Base; belongs_to :pirate end
15
- class Parrot < ActiveRecord::Base; belongs_to :pirate end
13
+ class GoldPiece < ActiveRecord::Base; belongs_to :treasure end
14
+ class Matey < ActiveRecord::Base; belongs_to :pirate end
15
+ class Parrot < ActiveRecord::Base; belongs_to :pirate end
16
16
 
17
17
  class Pirate < ActiveRecord::Base
18
18
  has_many :mateys
@@ -23,6 +23,7 @@ end
23
23
 
24
24
  class Treasure < ActiveRecord::Base
25
25
  belongs_to :pirate
26
+ belongs_to :matey
26
27
  has_many :gold_pieces
27
28
  end
28
29
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deep_cloneable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 1.1.0
10
+ version: 1.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Reinier de Lange
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-19 00:00:00 +02:00
18
+ date: 2010-10-20 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21