deep_cloneable 1.6.1 → 1.7.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.
- checksums.yaml +6 -14
- data/Gemfile +3 -2
- data/README.rdoc +21 -17
- data/VERSION +1 -1
- data/deep_cloneable.gemspec +8 -4
- data/lib/deep_cloneable.rb +11 -5
- data/test/test_deep_cloneable.rb +191 -170
- metadata +26 -12
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
ODQ0NDJiMzkwMzY5YzNlYmMyNjc1NTlmZTIxOWNiMDcyNjg1NWJiOGYyMGJh
|
10
|
-
N2I4NDY3YWNiZmRhNjkyNTExMDMwYzBlNWZhMTEyODk0ZmM0ZGNkZDMzZmQw
|
11
|
-
MDIzYjI3OTdlYmEyOWMzNWRmZTQzZjU3NTU0NDc2MjI0NTk4NGE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YzhkMmVkYWQxYjk1MDhhMTU0MTlmNjNjNGI4NTZiNTc2M2FiZWVjOGVkNTZh
|
14
|
-
NDI3NGU0YjUzMjFkNzZlNWRjMmY0ODhlZmI0MzBjZjM0M2YzNjczZjQzZWY0
|
15
|
-
ZGVjNGU0OGEzYWQ1MDYxM2E1Njc5ZDU4Y2NlYzA2OTY2OWFjY2I=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4f8ee9b4a7a7e7e22b8a9b329e4cf95c7d5bed93
|
4
|
+
data.tar.gz: d6b6a654ee08c7c0fd903d9a75e30043033785be
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 161420b3d29dd21abd32e702f78eefed39b3dc70bad588dc94841f01c47c5e68ad71843b5d02dc70f7b5d6b893c3ee9f337cb3431e60657b4ab3919fd74d31f7
|
7
|
+
data.tar.gz: aa4d87c683367f05c1be6bc5cbf2ea725a9ec3a5a8ce5352c0f548bcb9fe7ff24303cbe07b92b41ca8eb64d2972b873748b4b99d1e77f2a96863b1096a13b89c
|
data/Gemfile
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
source 'http://rubygems.org'
|
2
2
|
|
3
|
-
gem 'minitest', :group => :test
|
4
3
|
gem 'activerecord', '>= 3.1.0'
|
5
|
-
gem 'activesupport', '>= 3.1.0'
|
4
|
+
gem 'activesupport', '>= 3.1.0'
|
5
|
+
|
6
|
+
gem 'minitest', :group => :test
|
6
7
|
gem 'appraisal', :group => :test
|
7
8
|
gem 'sqlite3', :group => :test
|
8
9
|
gem 'rdoc', '>= 2.4.2', :group => :test
|
data/README.rdoc
CHANGED
@@ -16,62 +16,66 @@ This gem gives every ActiveRecord::Base object the possibility to do a deep clon
|
|
16
16
|
|
17
17
|
* In your Gemfile:
|
18
18
|
|
19
|
-
gem 'deep_cloneable', '~> 1.
|
19
|
+
gem 'deep_cloneable', '~> 1.7.0'
|
20
|
+
|
21
|
+
== Note
|
22
|
+
|
23
|
+
Version 1.7.0 deprecates the use of the method 'dup' for deep cloning. Please update your code to use 'deep_clone' instead. The dup method will be removed in deep_cloneable 2.0.0.
|
20
24
|
|
21
25
|
== Example
|
22
26
|
|
23
27
|
=== Cloning one single association
|
24
|
-
pirate.
|
28
|
+
pirate.deep_clone :include => :mateys
|
25
29
|
|
26
30
|
=== Cloning multiple associations
|
27
|
-
pirate.
|
31
|
+
pirate.deep_clone :include => [:mateys, :treasures]
|
28
32
|
|
29
33
|
=== Cloning really deep
|
30
|
-
pirate.
|
34
|
+
pirate.deep_clone :include => {:treasures => :gold_pieces}
|
31
35
|
|
32
36
|
=== Cloning really deep with multiple associations
|
33
|
-
pirate.
|
37
|
+
pirate.deep_clone :include => [:mateys, {:treasures => :gold_pieces}]
|
34
38
|
|
35
39
|
=== Cloning really deep with multiple associations and a dictionary
|
36
40
|
|
37
41
|
A dictionary ensures that models are not cloned multiple times when it is associated to nested models.
|
38
42
|
When using a dictionary, ensure recurring associations are cloned first:
|
39
43
|
|
40
|
-
pirate.
|
44
|
+
pirate.deep_clone :include => [:mateys, {:treasures => [:matey, :gold_pieces]}], :use_dictionary => true
|
41
45
|
|
42
46
|
If this is not an option for you, it is also possible to populate the dictionary manually in advance:
|
43
47
|
|
44
48
|
dict = { :mateys => {} }
|
45
|
-
pirate.mateys.each{|m| dict[:mateys][m] = m.
|
46
|
-
pirate.
|
49
|
+
pirate.mateys.each{|m| dict[:mateys][m] = m.deep_clone }
|
50
|
+
pirate.deep_clone :include => [:mateys, {:treasures => [:matey, :gold_pieces]}], :dictionary => dict
|
47
51
|
|
48
|
-
When an object isn't found in the dictionary, it will be populated. By passing in an empty dictionary you can populate it automatically and reuse it in subsequent
|
52
|
+
When an object isn't found in the dictionary, it will be populated. By passing in an empty dictionary you can populate it automatically and reuse it in subsequent deep_clones to avoid creating multiples of the same object where you have overlapping associations.
|
49
53
|
|
50
54
|
=== Cloning a model without an attribute
|
51
|
-
pirate.
|
55
|
+
pirate.deep_clone :except => :name
|
52
56
|
|
53
57
|
=== Cloning a model without multiple attributes
|
54
|
-
pirate.
|
58
|
+
pirate.deep_clone :except => [:name, :nick_name]
|
55
59
|
|
56
60
|
=== Cloning a model without an attribute or nested multiple attributes
|
57
|
-
pirate.
|
61
|
+
pirate.deep_clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
|
58
62
|
|
59
63
|
=== Cloning with a block
|
60
|
-
pirate.
|
64
|
+
pirate.deep_clone :include => :parrot do |original, kopy|
|
61
65
|
kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id)
|
62
66
|
end
|
63
67
|
|
64
68
|
=== Cloning without validations
|
65
|
-
pirate.
|
69
|
+
pirate.deep_clone :include => {:treasures => :gold_pieces}, :validate => false
|
66
70
|
|
67
71
|
=== Cloning a model with only explicitly assigned attribute
|
68
|
-
pirate.
|
72
|
+
pirate.deep_clone :only => :name
|
69
73
|
|
70
74
|
=== Cloning a model with only multiple explicitly assigned attributes
|
71
|
-
pirate.
|
75
|
+
pirate.deep_clone :only => [:name, :nick_name]
|
72
76
|
|
73
77
|
=== Cloning a model with explicitly assigned attributes or nested multiple attributes
|
74
|
-
pirate.
|
78
|
+
pirate.deep_clone :include => :parrot, :only => [:name, { :parrot => [:name] }]
|
75
79
|
|
76
80
|
== Note on Patches/Pull Requests
|
77
81
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.7.0
|
data/deep_cloneable.gemspec
CHANGED
@@ -2,14 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: deep_cloneable 1.7.0 ruby lib
|
5
6
|
|
6
7
|
Gem::Specification.new do |s|
|
7
8
|
s.name = "deep_cloneable"
|
8
|
-
s.version = "1.
|
9
|
+
s.version = "1.7.0"
|
9
10
|
|
10
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
11
13
|
s.authors = ["Reinier de Lange"]
|
12
|
-
s.date = "2014-
|
14
|
+
s.date = "2014-06-25"
|
13
15
|
s.description = "Extends the functionality of ActiveRecord::Base#clone to perform a deep clone that includes user specified associations. "
|
14
16
|
s.email = "r.j.delange@nedforce.nl"
|
15
17
|
s.extra_rdoc_files = [
|
@@ -44,8 +46,7 @@ Gem::Specification.new do |s|
|
|
44
46
|
"test/test_helper.rb"
|
45
47
|
]
|
46
48
|
s.homepage = "http://github.com/moiristo/deep_cloneable"
|
47
|
-
s.
|
48
|
-
s.rubygems_version = "2.0.6"
|
49
|
+
s.rubygems_version = "2.2.2"
|
49
50
|
s.summary = "This gem gives every ActiveRecord::Base object the possibility to do a deep clone."
|
50
51
|
|
51
52
|
if s.respond_to? :specification_version then
|
@@ -53,11 +54,14 @@ Gem::Specification.new do |s|
|
|
53
54
|
|
54
55
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
55
56
|
s.add_runtime_dependency(%q<activerecord>, [">= 3.1.0"])
|
57
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 3.1.0"])
|
56
58
|
else
|
57
59
|
s.add_dependency(%q<activerecord>, [">= 3.1.0"])
|
60
|
+
s.add_dependency(%q<activesupport>, [">= 3.1.0"])
|
58
61
|
end
|
59
62
|
else
|
60
63
|
s.add_dependency(%q<activerecord>, [">= 3.1.0"])
|
64
|
+
s.add_dependency(%q<activesupport>, [">= 3.1.0"])
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
data/lib/deep_cloneable.rb
CHANGED
@@ -17,18 +17,18 @@ class ActiveRecord::Base
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# Deep dups an ActiveRecord model. See README.rdoc
|
20
|
-
def
|
20
|
+
def deep_clone *args, &block
|
21
21
|
options = args[0] || {}
|
22
22
|
|
23
23
|
dict = options[:dictionary]
|
24
24
|
dict ||= {} if options.delete(:use_dictionary)
|
25
25
|
|
26
26
|
kopy = unless dict
|
27
|
-
|
27
|
+
dup()
|
28
28
|
else
|
29
29
|
tableized_class = self.class.name.tableize.to_sym
|
30
30
|
dict[tableized_class] ||= {}
|
31
|
-
dict[tableized_class][self] ||=
|
31
|
+
dict[tableized_class][self] ||= dup()
|
32
32
|
end
|
33
33
|
|
34
34
|
block.call(self, kopy) if block
|
@@ -91,10 +91,16 @@ class ActiveRecord::Base
|
|
91
91
|
return kopy
|
92
92
|
end
|
93
93
|
|
94
|
+
def dup *args, &block
|
95
|
+
return super() if args.empty? && !block
|
96
|
+
ActiveSupport::Deprecation.warn("Calling dup with arguments or blocks is deprecated and will be removed in deep_cloneable 2. Use method 'deep_clone' instead.")
|
97
|
+
deep_clone *args, &block
|
98
|
+
end
|
99
|
+
|
94
100
|
private
|
95
101
|
|
96
102
|
def dup_belongs_to_association options, &block
|
97
|
-
self.send(options[:association]) && self.send(options[:association]).
|
103
|
+
self.send(options[:association]) && self.send(options[:association]).deep_clone(options[:dup_options], &block)
|
98
104
|
end
|
99
105
|
|
100
106
|
def dup_has_one_association options, &block
|
@@ -109,7 +115,7 @@ class ActiveRecord::Base
|
|
109
115
|
end.try(:name)
|
110
116
|
|
111
117
|
self.send(options[:association]).collect do |obj|
|
112
|
-
tmp = obj.
|
118
|
+
tmp = obj.deep_clone(options[:dup_options], &block)
|
113
119
|
tmp.send("#{primary_key_name}=", nil)
|
114
120
|
tmp.send("#{reverse_association_name.to_s}=", options[:copy]) if reverse_association_name
|
115
121
|
tmp
|
data/test/test_deep_cloneable.rb
CHANGED
@@ -11,155 +11,155 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
11
11
|
@ship = BattleShip.create(:name => 'Black Pearl', :pirates => [@jack])
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
16
|
-
assert
|
17
|
-
assert
|
18
|
-
assert_equal @jack.name, @jack.
|
19
|
-
assert_nil
|
20
|
-
assert_equal @jack.nick_name,
|
21
|
-
end
|
22
|
-
|
23
|
-
def
|
24
|
-
|
25
|
-
assert
|
26
|
-
assert
|
27
|
-
assert_nil
|
28
|
-
assert_equal 'no nickname',
|
29
|
-
assert_equal @jack.age,
|
30
|
-
end
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
assert
|
35
|
-
assert
|
36
|
-
assert_equal @jack.name,
|
37
|
-
assert_equal 'no nickname',
|
38
|
-
assert_nil
|
39
|
-
assert_nil
|
40
|
-
assert_nil
|
41
|
-
end
|
42
|
-
|
43
|
-
def
|
44
|
-
|
45
|
-
assert
|
46
|
-
assert
|
47
|
-
assert_equal @jack.name,
|
48
|
-
assert_equal @jack.nick_name,
|
49
|
-
assert_nil
|
50
|
-
assert_nil
|
51
|
-
assert_nil
|
14
|
+
def test_single_deep_clone_exception
|
15
|
+
deep_clone = @jack.deep_clone(:except => :name)
|
16
|
+
assert deep_clone.new_record?
|
17
|
+
assert deep_clone.save
|
18
|
+
assert_equal @jack.name, @jack.deep_clone.name
|
19
|
+
assert_nil deep_clone.name
|
20
|
+
assert_equal @jack.nick_name, deep_clone.nick_name
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_multiple_deep_clone_exception
|
24
|
+
deep_clone = @jack.deep_clone(:except => [:name, :nick_name])
|
25
|
+
assert deep_clone.new_record?
|
26
|
+
assert deep_clone.save
|
27
|
+
assert_nil deep_clone.name
|
28
|
+
assert_equal 'no nickname', deep_clone.nick_name
|
29
|
+
assert_equal @jack.age, deep_clone.age
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_single_deep_clone_onliness
|
33
|
+
deep_clone = @jack.deep_clone(:only => :name)
|
34
|
+
assert deep_clone.new_record?
|
35
|
+
assert deep_clone.save
|
36
|
+
assert_equal @jack.name, deep_clone.name
|
37
|
+
assert_equal 'no nickname', deep_clone.nick_name
|
38
|
+
assert_nil deep_clone.age
|
39
|
+
assert_nil deep_clone.ship_id
|
40
|
+
assert_nil deep_clone.ship_type
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_multiple_deep_clone_onliness
|
44
|
+
deep_clone = @jack.deep_clone(:only => [:name, :nick_name])
|
45
|
+
assert deep_clone.new_record?
|
46
|
+
assert deep_clone.save
|
47
|
+
assert_equal @jack.name, deep_clone.name
|
48
|
+
assert_equal @jack.nick_name, deep_clone.nick_name
|
49
|
+
assert_nil deep_clone.age
|
50
|
+
assert_nil deep_clone.ship_id
|
51
|
+
assert_nil deep_clone.ship_type
|
52
52
|
end
|
53
53
|
|
54
54
|
def test_single_include_association
|
55
|
-
|
56
|
-
assert
|
57
|
-
assert
|
58
|
-
assert_equal 1,
|
55
|
+
deep_clone = @jack.deep_clone(:include => :mateys)
|
56
|
+
assert deep_clone.new_record?
|
57
|
+
assert deep_clone.save
|
58
|
+
assert_equal 1, deep_clone.mateys.size
|
59
59
|
end
|
60
60
|
|
61
61
|
def test_single_include_belongs_to_polymorphic_association
|
62
|
-
|
63
|
-
assert
|
64
|
-
assert
|
65
|
-
refute_nil
|
66
|
-
refute_equal @jack.ship,
|
62
|
+
deep_clone = @jack.deep_clone(:include => :ship)
|
63
|
+
assert deep_clone.new_record?
|
64
|
+
assert deep_clone.save
|
65
|
+
refute_nil deep_clone.ship
|
66
|
+
refute_equal @jack.ship, deep_clone.ship
|
67
67
|
end
|
68
68
|
|
69
69
|
def test_single_include_has_many_polymorphic_association
|
70
|
-
|
71
|
-
assert
|
72
|
-
assert
|
73
|
-
assert
|
70
|
+
deep_clone = @ship.deep_clone(:include => :pirates)
|
71
|
+
assert deep_clone.new_record?
|
72
|
+
assert deep_clone.save
|
73
|
+
assert deep_clone.pirates.any?
|
74
74
|
end
|
75
75
|
|
76
76
|
def test_multiple_include_association
|
77
|
-
|
78
|
-
assert
|
79
|
-
assert
|
80
|
-
assert_equal 1,
|
81
|
-
assert_equal 1,
|
77
|
+
deep_clone = @jack.deep_clone(:include => [:mateys, :treasures])
|
78
|
+
assert deep_clone.new_record?
|
79
|
+
assert deep_clone.save
|
80
|
+
assert_equal 1, deep_clone.mateys.size
|
81
|
+
assert_equal 1, deep_clone.treasures.size
|
82
82
|
end
|
83
83
|
|
84
84
|
def test_deep_include_association
|
85
|
-
|
86
|
-
assert
|
87
|
-
assert
|
88
|
-
assert_equal 1,
|
89
|
-
assert_equal 1,
|
85
|
+
deep_clone = @jack.deep_clone(:include => {:treasures => :gold_pieces})
|
86
|
+
assert deep_clone.new_record?
|
87
|
+
assert deep_clone.save
|
88
|
+
assert_equal 1, deep_clone.treasures.size
|
89
|
+
assert_equal 1, deep_clone.gold_pieces.size
|
90
90
|
end
|
91
91
|
|
92
92
|
def test_include_association_assignments
|
93
|
-
|
94
|
-
assert
|
93
|
+
deep_clone = @jack.deep_clone(:include => :treasures)
|
94
|
+
assert deep_clone.new_record?
|
95
95
|
|
96
|
-
|
97
|
-
assert_equal
|
96
|
+
deep_clone.treasures.each do |treasure|
|
97
|
+
assert_equal deep_clone, treasure.pirate
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
101
|
def test_multiple_and_deep_include_association
|
102
|
-
|
103
|
-
assert
|
104
|
-
assert
|
105
|
-
assert_equal 1,
|
106
|
-
assert_equal 1,
|
107
|
-
assert_equal 1,
|
102
|
+
deep_clone = @jack.deep_clone(:include => {:treasures => :gold_pieces, :mateys => {}})
|
103
|
+
assert deep_clone.new_record?
|
104
|
+
assert deep_clone.save
|
105
|
+
assert_equal 1, deep_clone.treasures.size
|
106
|
+
assert_equal 1, deep_clone.gold_pieces.size
|
107
|
+
assert_equal 1, deep_clone.mateys.size
|
108
108
|
end
|
109
109
|
|
110
110
|
def test_multiple_and_deep_include_association_with_array
|
111
|
-
|
112
|
-
assert
|
113
|
-
assert
|
114
|
-
assert_equal 1,
|
115
|
-
assert_equal 1,
|
116
|
-
assert_equal 1,
|
111
|
+
deep_clone = @jack.deep_clone(:include => [{:treasures => :gold_pieces}, :mateys])
|
112
|
+
assert deep_clone.new_record?
|
113
|
+
assert deep_clone.save
|
114
|
+
assert_equal 1, deep_clone.treasures.size
|
115
|
+
assert_equal 1, deep_clone.gold_pieces.size
|
116
|
+
assert_equal 1, deep_clone.mateys.size
|
117
117
|
end
|
118
118
|
|
119
119
|
def test_with_belongs_to_relation
|
120
|
-
|
121
|
-
assert
|
122
|
-
assert
|
123
|
-
refute_equal
|
120
|
+
deep_clone = @jack.deep_clone(:include => :parrot)
|
121
|
+
assert deep_clone.new_record?
|
122
|
+
assert deep_clone.save
|
123
|
+
refute_equal deep_clone.parrot, @jack.parrot
|
124
124
|
end
|
125
125
|
|
126
126
|
def test_should_pass_nested_exceptions
|
127
|
-
|
128
|
-
assert
|
129
|
-
assert
|
130
|
-
refute_equal
|
131
|
-
assert_equal
|
127
|
+
deep_clone = @jack.deep_clone(:include => :parrot, :except => [:name, { :parrot => [:name] }])
|
128
|
+
assert deep_clone.new_record?
|
129
|
+
assert deep_clone.save
|
130
|
+
refute_equal deep_clone.parrot, @jack.parrot
|
131
|
+
assert_equal deep_clone.parrot.age, @jack.parrot.age
|
132
132
|
refute_nil @jack.parrot.name
|
133
|
-
assert_nil
|
133
|
+
assert_nil deep_clone.parrot.name
|
134
134
|
end
|
135
135
|
|
136
136
|
def test_should_pass_nested_onlinesses
|
137
|
-
|
138
|
-
assert
|
139
|
-
assert
|
140
|
-
refute_equal
|
141
|
-
assert_equal
|
142
|
-
assert_nil
|
137
|
+
deep_clone = @jack.deep_clone(:include => :parrot, :only => [:name, { :parrot => [:name] }])
|
138
|
+
assert deep_clone.new_record?
|
139
|
+
assert deep_clone.save
|
140
|
+
refute_equal deep_clone.parrot, @jack.parrot
|
141
|
+
assert_equal deep_clone.parrot.name, @jack.parrot.name
|
142
|
+
assert_nil deep_clone.parrot.age
|
143
143
|
end
|
144
144
|
|
145
|
-
def
|
145
|
+
def test_should_not_double_deep_clone_when_using_dictionary
|
146
146
|
current_matey_count = Matey.count
|
147
|
-
|
148
|
-
assert
|
149
|
-
|
147
|
+
deep_clone = @jack.deep_clone(:include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
|
148
|
+
assert deep_clone.new_record?
|
149
|
+
deep_clone.save!
|
150
150
|
|
151
151
|
assert_equal current_matey_count + 1, Matey.count
|
152
152
|
end
|
153
153
|
|
154
|
-
def
|
154
|
+
def test_should_not_double_deep_clone_when_using_manual_dictionary
|
155
155
|
current_matey_count = Matey.count
|
156
156
|
|
157
157
|
dict = { :mateys => {} }
|
158
|
-
@jack.mateys.each{|m| dict[:mateys][m] = m.
|
158
|
+
@jack.mateys.each{|m| dict[:mateys][m] = m.deep_clone }
|
159
159
|
|
160
|
-
|
161
|
-
assert
|
162
|
-
|
160
|
+
deep_clone = @jack.deep_clone(:include => [:mateys, { :treasures => :matey }], :dictionary => dict)
|
161
|
+
assert deep_clone.new_record?
|
162
|
+
deep_clone.save!
|
163
163
|
|
164
164
|
assert_equal current_matey_count + 1, Matey.count
|
165
165
|
end
|
@@ -168,21 +168,21 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
168
168
|
@human = Animal::Human.create :name => "Michael"
|
169
169
|
@pig = Animal::Pig.create :human => @human, :name => 'big pig'
|
170
170
|
|
171
|
-
|
172
|
-
assert
|
173
|
-
assert
|
174
|
-
assert_equal 1,
|
171
|
+
deep_clone_human = @human.deep_clone(:include => [:pigs])
|
172
|
+
assert deep_clone_human.new_record?
|
173
|
+
assert deep_clone_human.save
|
174
|
+
assert_equal 1, deep_clone_human.pigs.count
|
175
175
|
|
176
176
|
@human2 = Animal::Human.create :name => "John"
|
177
177
|
@pig2 = @human2.pigs.create :name => 'small pig'
|
178
178
|
|
179
|
-
|
180
|
-
assert
|
181
|
-
assert
|
182
|
-
assert_equal 1,
|
179
|
+
deep_clone_human_2 = @human.deep_clone(:include => [:pigs])
|
180
|
+
assert deep_clone_human_2.new_record?
|
181
|
+
assert deep_clone_human_2.save
|
182
|
+
assert_equal 1, deep_clone_human_2.pigs.count
|
183
183
|
end
|
184
184
|
|
185
|
-
def
|
185
|
+
def test_should_deep_clone_many_to_many_associations
|
186
186
|
@human = Animal::Human.create :name => "Michael"
|
187
187
|
@human2 = Animal::Human.create :name => "Jack"
|
188
188
|
@chicken1 = Animal::Chicken.create :name => 'Chick1'
|
@@ -190,24 +190,24 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
190
190
|
@human.chickens << [@chicken1, @chicken2]
|
191
191
|
@human2.chickens << [@chicken1, @chicken2]
|
192
192
|
|
193
|
-
|
194
|
-
assert
|
195
|
-
assert
|
196
|
-
assert_equal 2,
|
193
|
+
deep_clone_human = @human.deep_clone(:include => :ownerships)
|
194
|
+
assert deep_clone_human.new_record?
|
195
|
+
assert deep_clone_human.save
|
196
|
+
assert_equal 2, deep_clone_human.chickens.count
|
197
197
|
end
|
198
198
|
|
199
|
-
def
|
200
|
-
|
199
|
+
def test_should_deep_clone_with_block
|
200
|
+
deep_clone = @jack.deep_clone(:include => :parrot) do |original, kopy|
|
201
201
|
kopy.cloned_from_id = original.id
|
202
202
|
end
|
203
203
|
|
204
|
-
assert
|
205
|
-
assert
|
206
|
-
assert_equal @jack.id,
|
207
|
-
assert_equal @jack.parrot.id,
|
204
|
+
assert deep_clone.new_record?
|
205
|
+
assert deep_clone.save
|
206
|
+
assert_equal @jack.id, deep_clone.cloned_from_id
|
207
|
+
assert_equal @jack.parrot.id, deep_clone.parrot.cloned_from_id
|
208
208
|
end
|
209
209
|
|
210
|
-
def
|
210
|
+
def test_should_deep_clone_habtm_associations
|
211
211
|
@person1 = Person.create :name => "Bill"
|
212
212
|
@person2 = Person.create :name => "Ted"
|
213
213
|
@car1 = Car.create :name => 'Mustang'
|
@@ -215,42 +215,42 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
215
215
|
@person1.cars << [@car1, @car2]
|
216
216
|
@person2.cars << [@car1, @car2]
|
217
217
|
|
218
|
-
|
218
|
+
deep_clone_person = @person1.deep_clone :include => :cars
|
219
219
|
|
220
|
-
assert
|
221
|
-
assert_equal [@person1, @person2,
|
222
|
-
assert_equal [@person1, @person2,
|
220
|
+
assert deep_clone_person.new_record?
|
221
|
+
assert_equal [@person1, @person2, deep_clone_person], @car1.people
|
222
|
+
assert_equal [@person1, @person2, deep_clone_person], @car2.people
|
223
223
|
|
224
|
-
assert
|
224
|
+
assert deep_clone_person.save
|
225
225
|
|
226
|
-
# did NOT
|
226
|
+
# did NOT deep_clone the Car instances
|
227
227
|
assert_equal 2, Car.all.count
|
228
228
|
|
229
|
-
# did
|
230
|
-
assert_equal @person1.cars,
|
231
|
-
assert_equal 2,
|
229
|
+
# did deep_clone the correct join table rows
|
230
|
+
assert_equal @person1.cars, deep_clone_person.cars
|
231
|
+
assert_equal 2, deep_clone_person.cars.count
|
232
232
|
end
|
233
233
|
|
234
|
-
def
|
234
|
+
def test_should_deep_clone_habtm_associations_with_missing_reverse_association
|
235
235
|
@coin = Coin.create :value => 1
|
236
236
|
@person = Person.create :name => "Bill"
|
237
237
|
@coin.people << @person
|
238
238
|
|
239
|
-
|
240
|
-
assert
|
239
|
+
deep_clone = @coin.deep_clone :include => :people
|
240
|
+
assert deep_clone.new_record?
|
241
241
|
assert_equal [@person], @coin.people
|
242
|
-
assert
|
242
|
+
assert deep_clone.save
|
243
243
|
end
|
244
244
|
|
245
|
-
def
|
245
|
+
def test_should_deep_clone_joined_association
|
246
246
|
subject1 = Subject.create(:name => 'subject 1')
|
247
247
|
subject2 = Subject.create(:name => 'subject 2')
|
248
248
|
student = Student.create(:name => 'Parent', :subjects => [subject1, subject2])
|
249
249
|
|
250
|
-
|
251
|
-
|
252
|
-
assert_equal 2,
|
253
|
-
[subject1, subject2].each{|subject| assert !
|
250
|
+
deep_clone = student.deep_clone :include => { :student_assignments => :subject }
|
251
|
+
deep_clone.save # Subjects will have been set after save
|
252
|
+
assert_equal 2, deep_clone.subjects.size
|
253
|
+
[subject1, subject2].each{|subject| assert !deep_clone.subjects.include?(subject) }
|
254
254
|
end
|
255
255
|
|
256
256
|
def test_parent_validations_run_on_save_after_clone
|
@@ -258,13 +258,13 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
258
258
|
parent = ParentWithValidation.new :children => [child]
|
259
259
|
parent.save :validate => false
|
260
260
|
|
261
|
-
|
261
|
+
deep_clone_parent = parent.deep_clone :include => :children
|
262
262
|
|
263
|
-
assert !
|
264
|
-
assert
|
265
|
-
assert !
|
266
|
-
assert
|
267
|
-
assert_equal
|
263
|
+
assert !deep_clone_parent.save
|
264
|
+
assert deep_clone_parent.new_record?
|
265
|
+
assert !deep_clone_parent.valid?
|
266
|
+
assert deep_clone_parent.children.first.valid?
|
267
|
+
assert_equal deep_clone_parent.errors.messages, :name => ["can't be blank"]
|
268
268
|
end
|
269
269
|
|
270
270
|
def test_parent_validations_dont_run_on_save_after_clone
|
@@ -272,13 +272,13 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
272
272
|
parent = ParentWithValidation.new :children => [child]
|
273
273
|
parent.save :validate => false
|
274
274
|
|
275
|
-
|
275
|
+
deep_clone_parent = parent.deep_clone :include => :children, :validate => false
|
276
276
|
|
277
|
-
assert
|
278
|
-
assert !
|
279
|
-
assert !
|
280
|
-
assert
|
281
|
-
assert_equal
|
277
|
+
assert deep_clone_parent.save
|
278
|
+
assert !deep_clone_parent.new_record?
|
279
|
+
assert !deep_clone_parent.valid?
|
280
|
+
assert deep_clone_parent.children.first.valid?
|
281
|
+
assert_equal deep_clone_parent.errors.messages, :name => ["can't be blank"]
|
282
282
|
end
|
283
283
|
|
284
284
|
def test_child_validations_run_on_save_after_clone
|
@@ -286,13 +286,13 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
286
286
|
child.save :validate => false
|
287
287
|
parent = ParentWithValidation.create :name => 'John', :children => [child]
|
288
288
|
|
289
|
-
|
289
|
+
deep_clone_parent = parent.deep_clone :include => :children
|
290
290
|
|
291
|
-
assert !
|
292
|
-
assert
|
293
|
-
assert !
|
294
|
-
assert !
|
295
|
-
assert_equal
|
291
|
+
assert !deep_clone_parent.save
|
292
|
+
assert deep_clone_parent.new_record?
|
293
|
+
assert !deep_clone_parent.valid?
|
294
|
+
assert !deep_clone_parent.children.first.valid?
|
295
|
+
assert_equal deep_clone_parent.errors.messages, :children => ["is invalid"]
|
296
296
|
end
|
297
297
|
|
298
298
|
def test_child_validations_run_on_save_after_clone
|
@@ -300,13 +300,13 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
300
300
|
child.save :validate => false
|
301
301
|
parent = ParentWithValidation.create :name => 'John', :children => [child]
|
302
302
|
|
303
|
-
|
303
|
+
deep_clone_parent = parent.deep_clone :include => :children, :validate => false
|
304
304
|
|
305
|
-
assert
|
306
|
-
assert !
|
307
|
-
assert !
|
308
|
-
assert !
|
309
|
-
assert_equal
|
305
|
+
assert deep_clone_parent.save
|
306
|
+
assert !deep_clone_parent.new_record?
|
307
|
+
assert !deep_clone_parent.valid?
|
308
|
+
assert !deep_clone_parent.children.first.valid?
|
309
|
+
assert_equal deep_clone_parent.errors.messages, :children => ["is invalid"]
|
310
310
|
end
|
311
311
|
|
312
312
|
def test_self_join_has_many
|
@@ -314,9 +314,9 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
314
314
|
child1 = Part.create(:name => 'Child 1', :parent_part_id => parent_part.id)
|
315
315
|
child2 = Part.create(:name => 'Child 2', :parent_part_id => parent_part.id)
|
316
316
|
|
317
|
-
|
318
|
-
assert
|
319
|
-
assert_equal 2,
|
317
|
+
deep_clone_part = parent_part.deep_clone :include => :child_parts
|
318
|
+
assert deep_clone_part.save
|
319
|
+
assert_equal 2, deep_clone_part.child_parts.size
|
320
320
|
end
|
321
321
|
|
322
322
|
def test_should_include_has_many_through_associations
|
@@ -324,9 +324,30 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
324
324
|
subject2 = Subject.create(:name => 'subject 2')
|
325
325
|
student = Student.create(:name => 'Parent', :subjects => [subject1, subject2])
|
326
326
|
|
327
|
-
|
328
|
-
assert_equal 2,
|
329
|
-
assert_equal [[student,
|
327
|
+
deep_clone = student.deep_clone :include => :subjects
|
328
|
+
assert_equal 2, deep_clone.subjects.size
|
329
|
+
assert_equal [[student, deep_clone],[student, deep_clone]], deep_clone.subjects.map{|subject| subject.students }
|
330
|
+
end
|
331
|
+
|
332
|
+
def test_should_deep_clone_unsaved_objects
|
333
|
+
jack = Pirate.new(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
|
334
|
+
jack.mateys.build(:name => 'John')
|
335
|
+
|
336
|
+
deep_clone = jack.deep_clone(:include => :mateys)
|
337
|
+
assert deep_clone.new_record?
|
338
|
+
assert_equal 1, deep_clone.mateys.size
|
339
|
+
assert_equal 'John', deep_clone.mateys.first.name
|
340
|
+
end
|
341
|
+
|
342
|
+
def test_should_deep_clone_via_dup
|
343
|
+
deep_clone = @jack.dup(:include => :parrot) do |original, kopy|
|
344
|
+
kopy.cloned_from_id = original.id
|
345
|
+
end
|
346
|
+
|
347
|
+
assert deep_clone.new_record?
|
348
|
+
assert deep_clone.save
|
349
|
+
assert_equal @jack.id, deep_clone.cloned_from_id
|
350
|
+
assert_equal @jack.parrot.id, deep_clone.parrot.cloned_from_id
|
330
351
|
end
|
331
352
|
|
332
353
|
end
|
metadata
CHANGED
@@ -1,31 +1,45 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deep_cloneable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reinier de Lange
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
|
-
- -
|
17
|
+
- - ">="
|
17
18
|
- !ruby/object:Gem::Version
|
18
19
|
version: 3.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
19
22
|
version_requirements: !ruby/object:Gem::Requirement
|
20
23
|
requirements:
|
21
|
-
- -
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
22
32
|
- !ruby/object:Gem::Version
|
23
33
|
version: 3.1.0
|
24
34
|
type: :runtime
|
25
35
|
prerelease: false
|
26
|
-
|
27
|
-
|
28
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.1.0
|
41
|
+
description: 'Extends the functionality of ActiveRecord::Base#clone to perform a deep
|
42
|
+
clone that includes user specified associations. '
|
29
43
|
email: r.j.delange@nedforce.nl
|
30
44
|
executables: []
|
31
45
|
extensions: []
|
@@ -33,8 +47,8 @@ extra_rdoc_files:
|
|
33
47
|
- LICENSE
|
34
48
|
- README.rdoc
|
35
49
|
files:
|
36
|
-
- .document
|
37
|
-
- .travis.yml
|
50
|
+
- ".document"
|
51
|
+
- ".travis.yml"
|
38
52
|
- Appraisals
|
39
53
|
- Gemfile
|
40
54
|
- Gemfile.lock
|
@@ -67,17 +81,17 @@ require_paths:
|
|
67
81
|
- lib
|
68
82
|
required_ruby_version: !ruby/object:Gem::Requirement
|
69
83
|
requirements:
|
70
|
-
- -
|
84
|
+
- - ">="
|
71
85
|
- !ruby/object:Gem::Version
|
72
86
|
version: '0'
|
73
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
88
|
requirements:
|
75
|
-
- -
|
89
|
+
- - ">="
|
76
90
|
- !ruby/object:Gem::Version
|
77
91
|
version: '0'
|
78
92
|
requirements: []
|
79
93
|
rubyforge_project:
|
80
|
-
rubygems_version: 2.
|
94
|
+
rubygems_version: 2.2.2
|
81
95
|
signing_key:
|
82
96
|
specification_version: 4
|
83
97
|
summary: This gem gives every ActiveRecord::Base object the possibility to do a deep
|