deep_cloneable 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,9 +1,10 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gemspec
4
-
5
3
  gem 'rails'
6
- gem 'jeweler'
4
+
5
+ group :development do
6
+ gem 'jeweler'
7
+ end
7
8
 
8
9
  group :test do
9
10
  gem 'sqlite3'
data/Gemfile.lock CHANGED
@@ -1,8 +1,3 @@
1
- PATH
2
- remote: .
3
- specs:
4
- deep_cloneable (1.3.1)
5
-
6
1
  GEM
7
2
  remote: http://rubygems.org/
8
3
  specs:
@@ -94,7 +89,6 @@ PLATFORMS
94
89
  ruby
95
90
 
96
91
  DEPENDENCIES
97
- deep_cloneable!
98
92
  jeweler
99
93
  rails
100
94
  sqlite3
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.3.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.0
1
+ 1.4.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "deep_cloneable"
8
- s.version = "1.4.0"
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-04-02"
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.add_runtime_dependency(%q<jeweler>, [">= 0"])
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
@@ -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, :has_and_belongs_to_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
- end
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
@@ -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.0
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-04-02 00:00:00.000000000 Z
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: :runtime
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: -1579513982850858765
84
+ hash: -3012807303620209218
100
85
  required_rubygems_version: !ruby/object:Gem::Requirement
101
86
  none: false
102
87
  requirements: