deep_cloneable 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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