deep_cloneable 1.4.0 → 1.4.1
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/Gemfile +4 -3
- data/Gemfile.lock +0 -6
- data/README.rdoc +3 -1
- data/VERSION +1 -1
- data/deep_cloneable.gemspec +4 -6
- data/lib/deep_cloneable.rb +14 -2
- data/test/models.rb +53 -0
- data/test/schema.rb +14 -1
- data/test/test_deep_cloneable.rb +43 -0
- data/test/test_helper.rb +1 -46
- metadata +5 -20
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -12,7 +12,7 @@ This gem gives every ActiveRecord::Base object the possibility to do a deep clon
|
|
12
12
|
|
13
13
|
* In your Gemfile:
|
14
14
|
|
15
|
-
gem 'deep_cloneable', '~> 1.
|
15
|
+
gem 'deep_cloneable', '~> 1.4.0'
|
16
16
|
|
17
17
|
== Example
|
18
18
|
|
@@ -62,6 +62,8 @@ If this is not an option for you, it is also possible to populate the dictionary
|
|
62
62
|
* Mart Karu
|
63
63
|
* Rolf Timmermans
|
64
64
|
* Ilya Kuzmin
|
65
|
+
* zozi
|
66
|
+
* fractious
|
65
67
|
|
66
68
|
== Note on Patches/Pull Requests
|
67
69
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.4.
|
1
|
+
1.4.1
|
data/deep_cloneable.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "deep_cloneable"
|
8
|
-
s.version = "1.4.
|
8
|
+
s.version = "1.4.1"
|
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 = "2012-
|
12
|
+
s.date = "2012-07-23"
|
13
13
|
s.description = "Extends the functionality of ActiveRecord::Base#clone to perform a deep clone that includes user specified associations. "
|
14
14
|
s.email = "r.j.delange@nedforce.nl"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
"init.rb",
|
29
29
|
"lib/deep_cloneable.rb",
|
30
30
|
"test/database.yml",
|
31
|
+
"test/models.rb",
|
31
32
|
"test/schema.rb",
|
32
33
|
"test/test_deep_cloneable.rb",
|
33
34
|
"test/test_helper.rb"
|
@@ -41,16 +42,13 @@ Gem::Specification.new do |s|
|
|
41
42
|
s.specification_version = 3
|
42
43
|
|
43
44
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
-
s.add_runtime_dependency(%q<deep_cloneable>, [">= 0"])
|
45
45
|
s.add_runtime_dependency(%q<rails>, [">= 0"])
|
46
|
-
s.
|
46
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
47
47
|
else
|
48
|
-
s.add_dependency(%q<deep_cloneable>, [">= 0"])
|
49
48
|
s.add_dependency(%q<rails>, [">= 0"])
|
50
49
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
51
50
|
end
|
52
51
|
else
|
53
|
-
s.add_dependency(%q<deep_cloneable>, [">= 0"])
|
54
52
|
s.add_dependency(%q<rails>, [">= 0"])
|
55
53
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
56
54
|
end
|
data/lib/deep_cloneable.rb
CHANGED
@@ -101,7 +101,7 @@ class ActiveRecord::Base
|
|
101
101
|
cloned_object = case association_reflection.macro
|
102
102
|
when :belongs_to, :has_one
|
103
103
|
self.send(association) && self.send(association).send(__method__, opts, &block)
|
104
|
-
when :has_many
|
104
|
+
when :has_many
|
105
105
|
primary_key_name = (@@rails31 ? association_reflection.foreign_key : association_reflection.primary_key_name).to_s
|
106
106
|
|
107
107
|
reverse_association_name = association_reflection.klass.reflect_on_all_associations.detect do |a|
|
@@ -114,7 +114,19 @@ class ActiveRecord::Base
|
|
114
114
|
tmp.send("#{reverse_association_name.to_s}=", kopy) if reverse_association_name
|
115
115
|
tmp
|
116
116
|
end
|
117
|
-
|
117
|
+
when :has_and_belongs_to_many
|
118
|
+
primary_key_name = (@@rails31 ? association_reflection.foreign_key : association_reflection.primary_key_name).to_s
|
119
|
+
|
120
|
+
reverse_association_name = association_reflection.klass.reflect_on_all_associations.detect do |a|
|
121
|
+
(a.macro == :has_and_belongs_to_many) && (a.association_foreign_key.to_s == primary_key_name)
|
122
|
+
end.try(:name)
|
123
|
+
|
124
|
+
self.send(association).collect do |obj|
|
125
|
+
obj.send(reverse_association_name).target << kopy
|
126
|
+
obj
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
118
130
|
kopy.send("#{association}=", cloned_object)
|
119
131
|
end
|
120
132
|
end
|
data/test/models.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Animal
|
2
|
+
class Human < ActiveRecord::Base
|
3
|
+
has_many :pigs
|
4
|
+
|
5
|
+
has_many :ownerships
|
6
|
+
has_many :chickens, :through => :ownerships
|
7
|
+
end
|
8
|
+
class Pig < ActiveRecord::Base
|
9
|
+
belongs_to :human
|
10
|
+
end
|
11
|
+
|
12
|
+
class Chicken < ActiveRecord::Base
|
13
|
+
has_many :ownerships
|
14
|
+
has_many :humans, :through => :ownerships
|
15
|
+
end
|
16
|
+
|
17
|
+
class Ownership < ActiveRecord::Base
|
18
|
+
belongs_to :human
|
19
|
+
belongs_to :chicken
|
20
|
+
|
21
|
+
validates_uniqueness_of :chicken_id, :scope => :human_id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class GoldPiece < ActiveRecord::Base; belongs_to :treasure end
|
26
|
+
class Matey < ActiveRecord::Base; belongs_to :pirate end
|
27
|
+
class Parrot < ActiveRecord::Base; belongs_to :pirate; attr_accessor :cloned_from_id end
|
28
|
+
class BattleShip < ActiveRecord::Base; has_many :pirates, :as => :ship end
|
29
|
+
|
30
|
+
class Pirate < ActiveRecord::Base
|
31
|
+
belongs_to :ship, :polymorphic => true
|
32
|
+
|
33
|
+
has_many :mateys
|
34
|
+
has_many :treasures, :foreign_key => 'owner'
|
35
|
+
has_many :gold_pieces, :through => :treasures
|
36
|
+
has_one :parrot
|
37
|
+
|
38
|
+
attr_accessor :cloned_from_id
|
39
|
+
end
|
40
|
+
|
41
|
+
class Treasure < ActiveRecord::Base
|
42
|
+
belongs_to :pirate, :foreign_key => :owner
|
43
|
+
belongs_to :matey
|
44
|
+
has_many :gold_pieces
|
45
|
+
end
|
46
|
+
|
47
|
+
class Person < ActiveRecord::Base
|
48
|
+
has_and_belongs_to_many :cars
|
49
|
+
end
|
50
|
+
|
51
|
+
class Car < ActiveRecord::Base
|
52
|
+
has_and_belongs_to_many :people
|
53
|
+
end
|
data/test/schema.rb
CHANGED
@@ -47,6 +47,19 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
47
47
|
create_table :ownerships, :force => true do |t|
|
48
48
|
t.column :human_id, :integer
|
49
49
|
t.column :chicken_id, :integer
|
50
|
-
end
|
50
|
+
end
|
51
|
+
|
52
|
+
create_table :cars, :force => true do |t|
|
53
|
+
t.column :name, :string
|
54
|
+
end
|
55
|
+
|
56
|
+
create_table :people, :force => true do |t|
|
57
|
+
t.column :name, :string
|
58
|
+
end
|
59
|
+
|
60
|
+
create_table :cars_people, :id => false, :force => true do |t|
|
61
|
+
t.column :car_id, :integer
|
62
|
+
t.column :person_id, :integer
|
63
|
+
end
|
51
64
|
|
52
65
|
end
|
data/test/test_deep_cloneable.rb
CHANGED
@@ -16,6 +16,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
16
16
|
|
17
17
|
def test_single_dup_exception
|
18
18
|
dup = @jack.send(@@clone_method, :except => :name)
|
19
|
+
assert dup.new_record?
|
19
20
|
assert dup.save
|
20
21
|
assert_equal @jack.name, @jack.send(@@clone_method).name # Old behaviour
|
21
22
|
assert_nil dup.name
|
@@ -24,6 +25,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
24
25
|
|
25
26
|
def test_multiple_dup_exception
|
26
27
|
dup = @jack.send(@@clone_method, :except => [:name, :nick_name])
|
28
|
+
assert dup.new_record?
|
27
29
|
assert dup.save
|
28
30
|
assert_nil dup.name
|
29
31
|
assert_equal 'no nickname', dup.nick_name
|
@@ -32,12 +34,14 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
32
34
|
|
33
35
|
def test_single_include_association
|
34
36
|
dup = @jack.send(@@clone_method, :include => :mateys)
|
37
|
+
assert dup.new_record?
|
35
38
|
assert dup.save
|
36
39
|
assert_equal 1, dup.mateys.size
|
37
40
|
end
|
38
41
|
|
39
42
|
def test_single_include_belongs_to_polymorphic_association
|
40
43
|
dup = @jack.send(@@clone_method, :include => :ship)
|
44
|
+
assert dup.new_record?
|
41
45
|
assert dup.save
|
42
46
|
assert_not_nil dup.ship
|
43
47
|
assert_not_equal @jack.ship, dup.ship
|
@@ -45,12 +49,14 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
45
49
|
|
46
50
|
def test_single_include_has_many_polymorphic_association
|
47
51
|
dup = @ship.send(@@clone_method, :include => :pirates)
|
52
|
+
assert dup.new_record?
|
48
53
|
assert dup.save
|
49
54
|
assert dup.pirates.any?
|
50
55
|
end
|
51
56
|
|
52
57
|
def test_multiple_include_association
|
53
58
|
dup = @jack.send(@@clone_method, :include => [:mateys, :treasures])
|
59
|
+
assert dup.new_record?
|
54
60
|
assert dup.save
|
55
61
|
assert_equal 1, dup.mateys.size
|
56
62
|
assert_equal 1, dup.treasures.size
|
@@ -58,6 +64,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
58
64
|
|
59
65
|
def test_deep_include_association
|
60
66
|
dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces})
|
67
|
+
assert dup.new_record?
|
61
68
|
assert dup.save
|
62
69
|
assert_equal 1, dup.treasures.size
|
63
70
|
assert_equal 1, dup.gold_pieces.size
|
@@ -65,6 +72,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
65
72
|
|
66
73
|
def test_include_association_assignments
|
67
74
|
dup = @jack.send(@@clone_method, :include => :treasures)
|
75
|
+
assert dup.new_record?
|
68
76
|
|
69
77
|
dup.treasures.each do |treasure|
|
70
78
|
assert_equal dup, treasure.pirate
|
@@ -73,6 +81,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
73
81
|
|
74
82
|
def test_multiple_and_deep_include_association
|
75
83
|
dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces, :mateys => {}})
|
84
|
+
assert dup.new_record?
|
76
85
|
assert dup.save
|
77
86
|
assert_equal 1, dup.treasures.size
|
78
87
|
assert_equal 1, dup.gold_pieces.size
|
@@ -81,6 +90,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
81
90
|
|
82
91
|
def test_multiple_and_deep_include_association_with_array
|
83
92
|
dup = @jack.send(@@clone_method, :include => [{:treasures => :gold_pieces}, :mateys])
|
93
|
+
assert dup.new_record?
|
84
94
|
assert dup.save
|
85
95
|
assert_equal 1, dup.treasures.size
|
86
96
|
assert_equal 1, dup.gold_pieces.size
|
@@ -89,12 +99,14 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
89
99
|
|
90
100
|
def test_with_belongs_to_relation
|
91
101
|
dup = @jack.send(@@clone_method, :include => :parrot)
|
102
|
+
assert dup.new_record?
|
92
103
|
assert dup.save
|
93
104
|
assert_not_equal dup.parrot, @jack.parrot
|
94
105
|
end
|
95
106
|
|
96
107
|
def test_should_pass_nested_exceptions
|
97
108
|
dup = @jack.send(@@clone_method, :include => :parrot, :except => [:name, { :parrot => [:name] }])
|
109
|
+
assert dup.new_record?
|
98
110
|
assert dup.save
|
99
111
|
assert_not_equal dup.parrot, @jack.parrot
|
100
112
|
assert_not_nil @jack.parrot.name
|
@@ -104,6 +116,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
104
116
|
def test_should_not_double_dup_when_using_dictionary
|
105
117
|
current_matey_count = Matey.count
|
106
118
|
dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
|
119
|
+
assert dup.new_record?
|
107
120
|
dup.save!
|
108
121
|
|
109
122
|
assert_equal current_matey_count + 1, Matey.count
|
@@ -116,6 +129,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
116
129
|
@jack.mateys.each{|m| dict[:mateys][m] = m.send(@@clone_method) }
|
117
130
|
|
118
131
|
dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :dictionary => dict)
|
132
|
+
assert dup.new_record?
|
119
133
|
dup.save!
|
120
134
|
|
121
135
|
assert_equal current_matey_count + 1, Matey.count
|
@@ -126,6 +140,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
126
140
|
@pig = Animal::Pig.create :human => @human, :name => 'big pig'
|
127
141
|
|
128
142
|
dup_human = @human.send(@@clone_method, :include => [:pigs])
|
143
|
+
assert dup_human.new_record?
|
129
144
|
assert dup_human.save
|
130
145
|
assert_equal 1, dup_human.pigs.count
|
131
146
|
|
@@ -133,6 +148,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
133
148
|
@pig2 = @human2.pigs.create :name => 'small pig'
|
134
149
|
|
135
150
|
dup_human_2 = @human.send(@@clone_method, :include => [:pigs])
|
151
|
+
assert dup_human_2.new_record?
|
136
152
|
assert dup_human_2.save
|
137
153
|
assert_equal 1, dup_human_2.pigs.count
|
138
154
|
end
|
@@ -146,6 +162,7 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
146
162
|
@human2.chickens << [@chicken1, @chicken2]
|
147
163
|
|
148
164
|
dup_human = @human.send(@@clone_method, :include => :ownerships)
|
165
|
+
assert dup_human.new_record?
|
149
166
|
assert dup_human.save
|
150
167
|
assert_equal 2, dup_human.chickens.count
|
151
168
|
end
|
@@ -155,8 +172,34 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
155
172
|
kopy.cloned_from_id = original.id
|
156
173
|
end
|
157
174
|
|
175
|
+
assert dup.new_record?
|
158
176
|
assert dup.save
|
159
177
|
assert_equal @jack.id, dup.cloned_from_id
|
160
178
|
assert_equal @jack.parrot.id, dup.parrot.cloned_from_id
|
161
179
|
end
|
180
|
+
|
181
|
+
def test_should_dup_habtm_associations
|
182
|
+
@person1 = Person.create :name => "Bill"
|
183
|
+
@person2 = Person.create :name => "Ted"
|
184
|
+
@car1 = Car.create :name => 'Mustang'
|
185
|
+
@car2 = Car.create :name => 'Camaro'
|
186
|
+
@person1.cars << [@car1, @car2]
|
187
|
+
@person2.cars << [@car1, @car2]
|
188
|
+
|
189
|
+
dup_person = @person1.dup :include => :cars
|
190
|
+
|
191
|
+
assert dup_person.new_record?
|
192
|
+
assert_equal [@person1, @person2, dup_person], @car1.people
|
193
|
+
assert_equal [@person1, @person2, dup_person], @car2.people
|
194
|
+
|
195
|
+
assert dup_person.save
|
196
|
+
|
197
|
+
# did NOT dup the Car instances
|
198
|
+
assert_equal 2, Car.all.count
|
199
|
+
|
200
|
+
# did dup the correct join table rows
|
201
|
+
assert_equal @person1.cars, dup_person.cars
|
202
|
+
assert_equal 2, dup_person.cars.count
|
203
|
+
end
|
204
|
+
|
162
205
|
end
|
data/test/test_helper.rb
CHANGED
@@ -7,52 +7,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
7
7
|
|
8
8
|
require 'active_record'
|
9
9
|
require File.dirname(__FILE__) + '/../init.rb'
|
10
|
-
|
11
|
-
module Animal
|
12
|
-
class Human < ActiveRecord::Base
|
13
|
-
has_many :pigs
|
14
|
-
|
15
|
-
has_many :ownerships
|
16
|
-
has_many :chickens, :through => :ownerships
|
17
|
-
end
|
18
|
-
class Pig < ActiveRecord::Base
|
19
|
-
belongs_to :human
|
20
|
-
end
|
21
|
-
|
22
|
-
class Chicken < ActiveRecord::Base
|
23
|
-
has_many :ownerships
|
24
|
-
has_many :humans, :through => :ownerships
|
25
|
-
end
|
26
|
-
|
27
|
-
class Ownership < ActiveRecord::Base
|
28
|
-
belongs_to :human
|
29
|
-
belongs_to :chicken
|
30
|
-
|
31
|
-
validates_uniqueness_of :chicken_id, :scope => :human_id
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class GoldPiece < ActiveRecord::Base; belongs_to :treasure end
|
36
|
-
class Matey < ActiveRecord::Base; belongs_to :pirate end
|
37
|
-
class Parrot < ActiveRecord::Base; belongs_to :pirate; attr_accessor :cloned_from_id end
|
38
|
-
class BattleShip < ActiveRecord::Base; has_many :pirates, :as => :ship end
|
39
|
-
|
40
|
-
class Pirate < ActiveRecord::Base
|
41
|
-
belongs_to :ship, :polymorphic => true
|
42
|
-
|
43
|
-
has_many :mateys
|
44
|
-
has_many :treasures, :foreign_key => 'owner'
|
45
|
-
has_many :gold_pieces, :through => :treasures
|
46
|
-
has_one :parrot
|
47
|
-
|
48
|
-
attr_accessor :cloned_from_id
|
49
|
-
end
|
50
|
-
|
51
|
-
class Treasure < ActiveRecord::Base
|
52
|
-
belongs_to :pirate, :foreign_key => :owner
|
53
|
-
belongs_to :matey
|
54
|
-
has_many :gold_pieces
|
55
|
-
end
|
10
|
+
require 'models'
|
56
11
|
|
57
12
|
def load_schema
|
58
13
|
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deep_cloneable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: deep_cloneable
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
30
14
|
- !ruby/object:Gem::Dependency
|
31
15
|
name: rails
|
32
16
|
requirement: !ruby/object:Gem::Requirement
|
@@ -51,7 +35,7 @@ dependencies:
|
|
51
35
|
- - ! '>='
|
52
36
|
- !ruby/object:Gem::Version
|
53
37
|
version: '0'
|
54
|
-
type: :
|
38
|
+
type: :development
|
55
39
|
prerelease: false
|
56
40
|
version_requirements: !ruby/object:Gem::Requirement
|
57
41
|
none: false
|
@@ -79,6 +63,7 @@ files:
|
|
79
63
|
- init.rb
|
80
64
|
- lib/deep_cloneable.rb
|
81
65
|
- test/database.yml
|
66
|
+
- test/models.rb
|
82
67
|
- test/schema.rb
|
83
68
|
- test/test_deep_cloneable.rb
|
84
69
|
- test/test_helper.rb
|
@@ -96,7 +81,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
81
|
version: '0'
|
97
82
|
segments:
|
98
83
|
- 0
|
99
|
-
hash: -
|
84
|
+
hash: -3012807303620209218
|
100
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
86
|
none: false
|
102
87
|
requirements:
|