deep_cloneable 1.4.0 → 3.2.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/readme.md ADDED
@@ -0,0 +1,242 @@
1
+ # deep_cloneable
2
+
3
+ ![Build Status](https://github.com/moiristo/deep_cloneable/actions/workflows/ruby.yml/badge.svg)
4
+
5
+ This gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations. It is a rails 3+ upgrade of the [deep_cloning plugin](http://github.com/openminds/deep_cloning).
6
+
7
+ ## Requirements
8
+
9
+ - Ruby 2.3.0, 2.4.4, 2.5.5, 2.6.3, 2.7.5, 3.3.5 (tested)
10
+ - Activerecord 3.2, 4.0, 4.1, 4.2, 5.0, 5.1, 5.2, 6.0, 7.0, 8.0 (tested)
11
+ - Rails 2.x/3.0 users, please check out the 'rails2.x-3.0' branch
12
+
13
+ ## Installation
14
+
15
+ - Add deep_cloneable to your Gemfile:
16
+
17
+ ```ruby
18
+ gem 'deep_cloneable', '~> 3.2.1'
19
+ ```
20
+
21
+ ## Upgrade details
22
+
23
+ ### Upgrading from v2
24
+
25
+ There are two breaking changes that you might need to pay attention to:
26
+
27
+ - When using an optional block (see below), the block used to be evaluated before `deep_cloneable` had performed its changes (inclusions, exclusions, includes). In v3, the block is evaluated after all processing has been done, just before the copy is about to be returned.
28
+ - When a defined association is not found, `deep_cloneable` raises an exception. The exception class has changed namespace: the class definition used to be `ActiveRecord::Base::DeepCloneable::AssociationNotFoundException` and this has changed to `DeepCloneable::AssociationNotFoundException`.
29
+
30
+ ### Upgrading from v1
31
+
32
+ The `dup` method with arguments has been replaced in deep_cloneable 2 by the method `deep_clone`. Please update your sources accordingly.
33
+
34
+ ## Usage
35
+
36
+ The `deep_clone` method supports a couple options that can be specified by passing an options hash. Without options, the behaviour is the same as ActiveRecord's [`dup`](http://apidock.com/rails/ActiveRecord/Core/dup) method.
37
+
38
+ ### Association inclusion
39
+
40
+ Associations to be included in the dup can be specified with the `include` option:
41
+
42
+ ```ruby
43
+ # Single include
44
+ pirate.deep_clone include: :mateys
45
+
46
+ # Multiple includes
47
+ pirate.deep_clone include: [ :mateys, :treasures ]
48
+
49
+ # Deep includes
50
+ pirate.deep_clone include: { treasures: :gold_pieces }
51
+ pirate.deep_clone include: [ :mateys, { treasures: :gold_pieces } ]
52
+
53
+ # Disable validation for a performance speedup when saving the dup
54
+ pirate.deep_clone include: { treasures: :gold_pieces }, validate: false
55
+
56
+ # Conditional includes
57
+ pirate.deep_clone include: [
58
+ {
59
+ treasures: { gold_pieces: { if: lambda{|piece| piece.is_a?(Parrot) } } } },
60
+ mateys: { unless: lambda{|matey| matey.is_a?(GoldPiece) }
61
+ }
62
+ ]
63
+
64
+ ship.deep_clone include: [
65
+ pirates: [ :treasures, :mateys, if: lambda {|pirate| pirate.name == 'Jack Sparrow' } ]
66
+ ]
67
+ ```
68
+
69
+ #### The Dictionary (Object Reusage)
70
+
71
+ The dictionary ensures that models are not duped multiple times when it is associated to nested models. It does this by storing a mapping of the original object to its duped object. It can be used as follows:
72
+
73
+ ```ruby
74
+ # Enables the dictionary (empty on initialization)
75
+ pirate.deep_clone include: [ :mateys, { treasures: [ :matey, :gold_pieces ] } ], use_dictionary: true
76
+
77
+ # Deep clones with a prefilled dictionary
78
+ dictionary = { mateys: {} }
79
+ pirate.mateys.each{|m| dict[:mateys][m] = m.deep_clone }
80
+ pirate.deep_clone include: [ :mateys, { treasures: [ :matey, :gold_pieces ] } ], dictionary: dictionary
81
+ ```
82
+
83
+ ### Attribute Exceptions & Inclusions
84
+
85
+ The `deep_clone` method supports both `except` and `only` for specifying which attributes should be duped:
86
+
87
+ #### Exceptions
88
+
89
+ ```ruby
90
+ # Single exception
91
+ pirate.deep_clone except: :name
92
+
93
+ # Multiple exceptions
94
+ pirate.deep_clone except: [ :name, :nick_name ]
95
+
96
+ # Nested exceptions
97
+ pirate.deep_clone include: :parrot, except: [ :name, { parrot: [ :name ] } ]
98
+ ```
99
+
100
+ #### Inclusions
101
+
102
+ ```ruby
103
+ # Single attribute inclusion
104
+ pirate.deep_clone only: :name
105
+
106
+ # Multiple attribute inclusions
107
+ pirate.deep_clone only: [ :name, :nick_name ]
108
+
109
+ # Nested attribute inclusions
110
+ pirate.deep_clone include: :parrot, only: [ :name, { parrot: [ :name ] } ]
111
+
112
+ ```
113
+
114
+ ### Pre- and postprocessor
115
+
116
+ You can specify a pre- and/or a postprocessor to modify a duped object after duplication:
117
+
118
+ ```ruby
119
+ pirate.deep_clone(include: :parrot, preprocessor: ->(original, kopy) { kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id) })
120
+ pirate.deep_clone(include: :parrot, postprocessor: ->(original, kopy) { kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id) })
121
+ ```
122
+
123
+ _Note_: Specifying a postprocessor is essentially the same as specifying an optional block (see below).
124
+
125
+ _Note_: Using `deep_clone` with a processors will pass all associated objects that are being cloned to the processor, so be sure to check whether the object actually responds to your method of choice.
126
+
127
+ ### Optional Block
128
+
129
+ Pass a block to `deep_clone` to modify a duped object after duplication:
130
+
131
+ ```ruby
132
+ pirate.deep_clone include: :parrot do |original, kopy|
133
+ kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id)
134
+ end
135
+ ```
136
+
137
+ _Note_: Using `deep_clone` with a block will also pass the associated objects that are being cloned to the block, so be sure to check whether the object actually responds to your method of choice.
138
+
139
+ ### Cloning models with files
140
+
141
+ #### Carrierwave
142
+
143
+ If you are cloning models that have associated files through Carrierwave these will not get transferred automatically. To overcome the issue you need to explicitly set the file attribute.
144
+
145
+ Easiest solution is to add the code in a clone block as described above.
146
+
147
+ ```ruby
148
+ pirate.deep_clone include: :parrot do |original, kopy|
149
+ kopy.thumbnail = original.thumbnail
150
+ end
151
+ ```
152
+
153
+ #### ActiveStorage
154
+
155
+ For ActiveStorage, you have two options: you can either make a full copy, or share data blobs between two records.
156
+
157
+ ##### Full copy example
158
+
159
+ ```ruby
160
+ # Rails 5.2, has_one_attached example 1
161
+ pirate.deep_clone include: [:parrot, :avatar_attachment, :avatar_blob]
162
+
163
+ # Rails 5.2, has_one_attached example 2
164
+ pirate.deep_clone include: :parrot do |original, kopy|
165
+ if kopy.is_a?(Pirate) && original.avatar.attached?
166
+ attachment = original.avatar
167
+ kopy.avatar.attach \
168
+ :io => StringIO.new(attachment.download),
169
+ :filename => attachment.filename,
170
+ :content_type => attachment.content_type
171
+ end
172
+ end
173
+
174
+ # Rails 5.2, has_many_attached example 1 (attach one by one)
175
+ pirate.deep_clone include: :parrot do |original, kopy|
176
+ if kopy.is_a?(Pirate) && original.crew_members_images.attached?
177
+ original.crew_members_images.each do |attachment|
178
+ kopy.crew_members_images.attach \
179
+ :io => StringIO.new(attachment.download),
180
+ :filename => attachment.filename,
181
+ :content_type => attachment.content_type
182
+ end
183
+ end
184
+ end
185
+
186
+ # Rails 5.2, has_many_attached example 2 (attach bulk)
187
+ pirate.deep_clone include: :parrot do |original, kopy|
188
+ if kopy.is_a?(Pirate) && original.crew_members_images.attached?
189
+ all_attachments_arr = original.crew_members_images.map do |attachment|
190
+ {
191
+ :io => StringIO.new(attachment.download),
192
+ :filename => attachment.filename,
193
+ :content_type => attachment.content_type
194
+ }
195
+ end
196
+ kopy.crew_members_images.attach(all_attachments_arr) # attach all at once
197
+ end
198
+ end
199
+
200
+ # Rails 6
201
+ pirate.deep_clone include: :parrot do |original, kopy|
202
+ if kopy.is_a?(Pirate) && original.avatar.attached?
203
+ original.avatar.open do |tempfile|
204
+ kopy.avatar.attach({
205
+ io: File.open(tempfile.path),
206
+ filename: original.avatar.blob.filename,
207
+ content_type: original.avatar.blob.content_type
208
+ })
209
+ end
210
+ end
211
+ end
212
+ ```
213
+
214
+ ##### Shallow copy example
215
+
216
+ ```ruby
217
+ pirate.deep_clone include: :parrot do |original, kopy|
218
+ kopy.avatar.attach(original.avatar.blob) if kopy.is_a?(Pirate) && original.avatar.attached?
219
+ end
220
+ ```
221
+
222
+ ### Skipping missing associations
223
+
224
+ By default, deep_cloneable will throw a `DeepCloneable::AssociationNotFoundException` error when an association cannot be found. You can also skip missing associations by specifying `skip_missing_associations` if needed, for example when you have associations on some (but not all) subclasses of an STI model:
225
+
226
+ ```ruby
227
+ pirate.deep_clone include: [:parrot, :rum], skip_missing_associations: true
228
+ ```
229
+
230
+ ### Note on Patches/Pull Requests
231
+
232
+ - Fork the project.
233
+ - Make your feature addition or bug fix.
234
+ - Add tests for it. This is important so I don't break it in a
235
+ future version unintentionally.
236
+ - Commit, do not mess with rakefile, version, or history.
237
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
238
+ - Send me a pull request. Bonus points for topic branches.
239
+
240
+ ### Copyright
241
+
242
+ Copyright © 2024 Reinier de Lange. See LICENSE for details.
metadata CHANGED
@@ -1,113 +1,79 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deep_cloneable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
5
- prerelease:
4
+ version: 3.2.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Reinier de Lange
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-04-02 00:00:00.000000000 Z
11
+ date: 2024-11-20 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: deep_cloneable
14
+ name: activerecord
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !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
- - - ! '>='
19
+ version: 3.1.0
20
+ - - "<"
28
21
  - !ruby/object:Gem::Version
29
- version: '0'
30
- - !ruby/object:Gem::Dependency
31
- name: rails
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
22
+ version: '9'
38
23
  type: :runtime
39
24
  prerelease: false
40
25
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
26
  requirements:
43
- - - ! '>='
27
+ - - ">="
44
28
  - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: jeweler
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
29
+ version: 3.1.0
30
+ - - "<"
60
31
  - !ruby/object:Gem::Version
61
- version: '0'
62
- description: ! 'Extends the functionality of ActiveRecord::Base#clone to perform a
63
- deep clone that includes user specified associations. '
64
- email: r.j.delange@nedforce.nl
32
+ version: '9'
33
+ description: Extends the functionality of ActiveRecord::Base#dup to perform a deep
34
+ clone that includes user specified associations.
35
+ email: rjdelange@icloud.com
65
36
  executables: []
66
37
  extensions: []
67
38
  extra_rdoc_files:
68
39
  - LICENSE
69
- - README.rdoc
70
40
  files:
71
- - .document
41
+ - Appraisals
42
+ - CHANGELOG.md
72
43
  - Gemfile
73
44
  - Gemfile.lock
74
45
  - LICENSE
75
- - README.rdoc
76
46
  - Rakefile
77
- - VERSION
78
47
  - deep_cloneable.gemspec
79
48
  - init.rb
80
49
  - lib/deep_cloneable.rb
81
- - test/database.yml
82
- - test/schema.rb
83
- - test/test_deep_cloneable.rb
84
- - test/test_helper.rb
85
- homepage: http://github.com/moiristo/deep_cloneable
86
- licenses: []
87
- post_install_message:
50
+ - lib/deep_cloneable/association_not_found_exception.rb
51
+ - lib/deep_cloneable/deep_clone.rb
52
+ - lib/deep_cloneable/skip_validations.rb
53
+ - lib/deep_cloneable/version.rb
54
+ - readme.md
55
+ homepage: https://github.com/moiristo/deep_cloneable
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ post_install_message:
88
60
  rdoc_options: []
89
61
  require_paths:
90
62
  - lib
91
63
  required_ruby_version: !ruby/object:Gem::Requirement
92
- none: false
93
64
  requirements:
94
- - - ! '>='
65
+ - - ">="
95
66
  - !ruby/object:Gem::Version
96
- version: '0'
97
- segments:
98
- - 0
99
- hash: -1579513982850858765
67
+ version: 1.9.3
100
68
  required_rubygems_version: !ruby/object:Gem::Requirement
101
- none: false
102
69
  requirements:
103
- - - ! '>='
70
+ - - ">="
104
71
  - !ruby/object:Gem::Version
105
72
  version: '0'
106
73
  requirements: []
107
- rubyforge_project:
108
- rubygems_version: 1.8.21
109
- signing_key:
110
- specification_version: 3
74
+ rubygems_version: 3.5.20
75
+ signing_key:
76
+ specification_version: 4
111
77
  summary: This gem gives every ActiveRecord::Base object the possibility to do a deep
112
78
  clone.
113
79
  test_files: []
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
data/README.rdoc DELETED
@@ -1,78 +0,0 @@
1
- = Deep_cloneable
2
-
3
- This gem gives every ActiveRecord::Base object the possibility to do a deep clone. It is a rails3 upgrade of the deep_cloning plugin (http://github.com/openminds/deep_cloning).
4
-
5
- == Requirements
6
-
7
- * Activerecord 3.1, 3.2
8
-
9
- * Rails 2.x/3.0 users, please check out the 'rails2.x-3.0' branch.
10
-
11
- == Installation
12
-
13
- * In your Gemfile:
14
-
15
- gem 'deep_cloneable', '~> 1.3.1'
16
-
17
- == Example
18
-
19
- === Cloning one single association
20
- pirate.dup :include => :mateys
21
-
22
- === Cloning multiple associations
23
- pirate.dup :include => [:mateys, :treasures]
24
-
25
- === Cloning really deep
26
- pirate.dup :include => {:treasures => :gold_pieces}
27
-
28
- === Cloning really deep with multiple associations
29
- pirate.dup :include => [:mateys, {:treasures => :gold_pieces}]
30
-
31
- === Cloning really deep with multiple associations and a dictionary
32
-
33
- A dictionary ensures that models are not cloned multiple times when it is associated to nested models.
34
- When using a dictionary, ensure recurring associations are cloned first:
35
-
36
- pirate.dup :include => [:mateys, {:treasures => [:matey, :gold_pieces], :use_dictionary => true }]
37
-
38
- If this is not an option for you, it is also possible to populate the dictionary manually in advance:
39
-
40
- dict = { :mateys => {} }
41
- pirate.mateys.each{|m| dict[:mateys][m] = m.dup }
42
- pirate.dup :include => [:mateys, {:treasures => [:matey, :gold_pieces], :dictionary => dict }]
43
-
44
- === Cloning a model without an attribute
45
- pirate.dup :except => :name
46
-
47
- === Cloning a model without multiple attributes
48
- pirate.dup :except => [:name, :nick_name]
49
-
50
- === Cloning a model without an attribute or nested multiple attributes
51
- pirate.dup :include => :parrot, :except => [:name, { :parrot => [:name] }]
52
-
53
- === Cloning with a block
54
- pirate.dup :include => :parrot do |original, kopy|
55
- kopy.cloned_from_id = original.id if kopy.respond_to?(:cloned_from_id)
56
- end
57
-
58
- == Contributors
59
-
60
- * Michael He
61
- * Indrek Juhkam
62
- * Mart Karu
63
- * Rolf Timmermans
64
- * Ilya Kuzmin
65
-
66
- == Note on Patches/Pull Requests
67
-
68
- * Fork the project.
69
- * Make your feature addition or bug fix.
70
- * Add tests for it. This is important so I don't break it in a
71
- future version unintentionally.
72
- * Commit, do not mess with rakefile, version, or history.
73
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
74
- * Send me a pull request. Bonus points for topic branches.
75
-
76
- == Copyright
77
-
78
- Copyright (c) 2012 Reinier de Lange. See LICENSE for details.
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.4.0
data/test/database.yml DELETED
@@ -1,6 +0,0 @@
1
- sqlite:
2
- adapter: sqlite
3
- database: ":memory:"
4
- sqlite3:
5
- adapter: sqlite3
6
- database: ":memory:"
data/test/schema.rb DELETED
@@ -1,52 +0,0 @@
1
- ActiveRecord::Schema.define(:version => 1) do
2
- create_table :pirates, :force => true do |t|
3
- t.column :name, :string
4
- t.column :nick_name, :string, :default => 'no nickname'
5
- t.column :age, :string
6
- t.column :ship_id, :integer
7
- t.column :ship_type, :string
8
- end
9
-
10
- create_table :parrots, :force => true do |t|
11
- t.column :name, :string
12
- t.column :pirate_id, :integer
13
- end
14
-
15
- create_table :mateys, :force => true do |t|
16
- t.column :name, :string
17
- t.column :pirate_id, :integer
18
- end
19
-
20
- create_table :treasures, :force => true do |t|
21
- t.column :found_at, :string
22
- t.column :owner, :integer
23
- t.column :matey_id, :integer
24
- end
25
-
26
- create_table :gold_pieces, :force => true do |t|
27
- t.column :treasure_id, :integer
28
- end
29
-
30
- create_table :battle_ships, :force => true do |t|
31
- t.column :name, :string
32
- end
33
-
34
- create_table :pigs, :force => true do |t|
35
- t.column :name, :string
36
- t.column :human_id, :integer
37
- end
38
-
39
- create_table :humen, :force => true do |t|
40
- t.column :name, :string
41
- end
42
-
43
- create_table :chickens, :force => true do |t|
44
- t.column :name, :string
45
- end
46
-
47
- create_table :ownerships, :force => true do |t|
48
- t.column :human_id, :integer
49
- t.column :chicken_id, :integer
50
- end
51
-
52
- end
@@ -1,162 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class TestDeepCloneable < Test::Unit::TestCase
4
- load_schema
5
-
6
- @@clone_method = ActiveRecord::VERSION::MAJOR >= 3 && ActiveRecord::VERSION::MINOR > 0 ? :dup : :clone
7
-
8
- def setup
9
- @jack = Pirate.create(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
10
- @polly = Parrot.create(:name => 'Polly', :pirate => @jack)
11
- @john = Matey.create(:name => 'John', :pirate => @jack)
12
- @treasure = Treasure.create(:found_at => 'Isla del Muerte', :pirate => @jack, :matey => @john)
13
- @gold_piece = GoldPiece.create(:treasure => @treasure)
14
- @ship = BattleShip.create(:name => 'Black Pearl', :pirates => [@jack])
15
- end
16
-
17
- def test_single_dup_exception
18
- dup = @jack.send(@@clone_method, :except => :name)
19
- assert dup.save
20
- assert_equal @jack.name, @jack.send(@@clone_method).name # Old behaviour
21
- assert_nil dup.name
22
- assert_equal @jack.nick_name, dup.nick_name
23
- end
24
-
25
- def test_multiple_dup_exception
26
- dup = @jack.send(@@clone_method, :except => [:name, :nick_name])
27
- assert dup.save
28
- assert_nil dup.name
29
- assert_equal 'no nickname', dup.nick_name
30
- assert_equal @jack.age, dup.age
31
- end
32
-
33
- def test_single_include_association
34
- dup = @jack.send(@@clone_method, :include => :mateys)
35
- assert dup.save
36
- assert_equal 1, dup.mateys.size
37
- end
38
-
39
- def test_single_include_belongs_to_polymorphic_association
40
- dup = @jack.send(@@clone_method, :include => :ship)
41
- assert dup.save
42
- assert_not_nil dup.ship
43
- assert_not_equal @jack.ship, dup.ship
44
- end
45
-
46
- def test_single_include_has_many_polymorphic_association
47
- dup = @ship.send(@@clone_method, :include => :pirates)
48
- assert dup.save
49
- assert dup.pirates.any?
50
- end
51
-
52
- def test_multiple_include_association
53
- dup = @jack.send(@@clone_method, :include => [:mateys, :treasures])
54
- assert dup.save
55
- assert_equal 1, dup.mateys.size
56
- assert_equal 1, dup.treasures.size
57
- end
58
-
59
- def test_deep_include_association
60
- dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces})
61
- assert dup.save
62
- assert_equal 1, dup.treasures.size
63
- assert_equal 1, dup.gold_pieces.size
64
- end
65
-
66
- def test_include_association_assignments
67
- dup = @jack.send(@@clone_method, :include => :treasures)
68
-
69
- dup.treasures.each do |treasure|
70
- assert_equal dup, treasure.pirate
71
- end
72
- end
73
-
74
- def test_multiple_and_deep_include_association
75
- dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces, :mateys => {}})
76
- assert dup.save
77
- assert_equal 1, dup.treasures.size
78
- assert_equal 1, dup.gold_pieces.size
79
- assert_equal 1, dup.mateys.size
80
- end
81
-
82
- def test_multiple_and_deep_include_association_with_array
83
- dup = @jack.send(@@clone_method, :include => [{:treasures => :gold_pieces}, :mateys])
84
- assert dup.save
85
- assert_equal 1, dup.treasures.size
86
- assert_equal 1, dup.gold_pieces.size
87
- assert_equal 1, dup.mateys.size
88
- end
89
-
90
- def test_with_belongs_to_relation
91
- dup = @jack.send(@@clone_method, :include => :parrot)
92
- assert dup.save
93
- assert_not_equal dup.parrot, @jack.parrot
94
- end
95
-
96
- def test_should_pass_nested_exceptions
97
- dup = @jack.send(@@clone_method, :include => :parrot, :except => [:name, { :parrot => [:name] }])
98
- assert dup.save
99
- assert_not_equal dup.parrot, @jack.parrot
100
- assert_not_nil @jack.parrot.name
101
- assert_nil dup.parrot.name
102
- end
103
-
104
- def test_should_not_double_dup_when_using_dictionary
105
- current_matey_count = Matey.count
106
- dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
107
- dup.save!
108
-
109
- assert_equal current_matey_count + 1, Matey.count
110
- end
111
-
112
- def test_should_not_double_dup_when_using_manual_dictionary
113
- current_matey_count = Matey.count
114
-
115
- dict = { :mateys => {} }
116
- @jack.mateys.each{|m| dict[:mateys][m] = m.send(@@clone_method) }
117
-
118
- dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :dictionary => dict)
119
- dup.save!
120
-
121
- assert_equal current_matey_count + 1, Matey.count
122
- end
123
-
124
- def test_should_support_ar_class_under_module
125
- @human = Animal::Human.create :name => "Michael"
126
- @pig = Animal::Pig.create :human => @human, :name => 'big pig'
127
-
128
- dup_human = @human.send(@@clone_method, :include => [:pigs])
129
- assert dup_human.save
130
- assert_equal 1, dup_human.pigs.count
131
-
132
- @human2 = Animal::Human.create :name => "John"
133
- @pig2 = @human2.pigs.create :name => 'small pig'
134
-
135
- dup_human_2 = @human.send(@@clone_method, :include => [:pigs])
136
- assert dup_human_2.save
137
- assert_equal 1, dup_human_2.pigs.count
138
- end
139
-
140
- def test_should_dup_many_to_many_associations
141
- @human = Animal::Human.create :name => "Michael"
142
- @human2 = Animal::Human.create :name => "Jack"
143
- @chicken1 = Animal::Chicken.create :name => 'Chick1'
144
- @chicken2 = Animal::Chicken.create :name => 'Chick2'
145
- @human.chickens << [@chicken1, @chicken2]
146
- @human2.chickens << [@chicken1, @chicken2]
147
-
148
- dup_human = @human.send(@@clone_method, :include => :ownerships)
149
- assert dup_human.save
150
- assert_equal 2, dup_human.chickens.count
151
- end
152
-
153
- def test_should_dup_with_block
154
- dup = @jack.send(@@clone_method, :include => :parrot) do |original, kopy|
155
- kopy.cloned_from_id = original.id
156
- end
157
-
158
- assert dup.save
159
- assert_equal @jack.id, dup.cloned_from_id
160
- assert_equal @jack.parrot.id, dup.parrot.cloned_from_id
161
- end
162
- end