deep_cloneable 2.2.2 → 2.3.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 +4 -4
- data/Gemfile.lock +18 -14
- data/LICENSE +1 -1
- data/VERSION +1 -1
- data/deep_cloneable.gemspec +16 -16
- data/lib/deep_cloneable.rb +37 -21
- data/readme.md +11 -3
- data/test/models.rb +14 -1
- data/test/schema.rb +7 -1
- data/test/test_deep_cloneable.rb +25 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2965ed86adcfda63e876533015e4a55e4fb0316f
|
4
|
+
data.tar.gz: 6d9ef9a44e135ecf9baa769e721e25c62b4f893c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e11fe1537382bc8fe904aa02f0dd33b205bc926093d383f6ef7a0023509c279e430f04732f5707c62ef077b7de86516f66d935e90055e4fd1b8a1b2f6612bb93
|
7
|
+
data.tar.gz: c2b879a4b1885214c647c632ace3f8ba895b0c13ac12d34bed2c2bb9ccf776060a1add719a6a1219a9fbe7c4b3a4b30dcb33149466bda4fefec4b2b3f66c2eb0
|
data/Gemfile.lock
CHANGED
@@ -26,43 +26,47 @@ GEM
|
|
26
26
|
faraday (0.9.2)
|
27
27
|
multipart-post (>= 1.2, < 3)
|
28
28
|
git (1.2.9.1)
|
29
|
-
github_api (0.
|
29
|
+
github_api (0.16.0)
|
30
30
|
addressable (~> 2.4.0)
|
31
31
|
descendants_tracker (~> 0.0.4)
|
32
32
|
faraday (~> 0.8, < 0.10)
|
33
33
|
hashie (>= 3.4)
|
34
|
-
|
35
|
-
|
34
|
+
mime-types (>= 1.16, < 3.0)
|
35
|
+
oauth2 (~> 1.0)
|
36
|
+
hashie (3.5.5)
|
36
37
|
highline (1.6.21)
|
37
38
|
i18n (0.6.11)
|
38
|
-
jeweler (2.
|
39
|
+
jeweler (2.3.6)
|
39
40
|
builder
|
40
|
-
bundler (>= 1
|
41
|
+
bundler (>= 1)
|
41
42
|
git (>= 1.2.5)
|
42
|
-
github_api
|
43
|
+
github_api (~> 0.16.0)
|
43
44
|
highline (>= 1.6.15)
|
44
45
|
nokogiri (>= 1.5.10)
|
46
|
+
psych (~> 2.2)
|
45
47
|
rake
|
46
48
|
rdoc
|
47
|
-
|
49
|
+
semver2
|
48
50
|
json (1.8.3)
|
49
|
-
jwt (1.5.
|
51
|
+
jwt (1.5.6)
|
52
|
+
mime-types (2.99.3)
|
50
53
|
minitest (5.9.0)
|
51
54
|
multi_json (1.12.1)
|
52
|
-
multi_xml (0.
|
55
|
+
multi_xml (0.6.0)
|
53
56
|
multipart-post (2.0.0)
|
54
57
|
nokogiri (1.5.11)
|
55
|
-
oauth2 (1.
|
56
|
-
faraday (>= 0.8, < 0.
|
57
|
-
jwt (~> 1.0
|
58
|
+
oauth2 (1.4.0)
|
59
|
+
faraday (>= 0.8, < 0.13)
|
60
|
+
jwt (~> 1.0)
|
58
61
|
multi_json (~> 1.3)
|
59
62
|
multi_xml (~> 0.5)
|
60
63
|
rack (>= 1.2, < 3)
|
64
|
+
psych (2.2.4)
|
61
65
|
rack (1.6.4)
|
62
66
|
rake (10.5.0)
|
63
67
|
rdoc (4.2.2)
|
64
68
|
json (~> 1.4)
|
65
|
-
|
69
|
+
semver2 (3.4.2)
|
66
70
|
sqlite3 (1.3.11)
|
67
71
|
thor (0.19.1)
|
68
72
|
thread_safe (0.3.5)
|
@@ -87,4 +91,4 @@ DEPENDENCIES
|
|
87
91
|
sqlite3
|
88
92
|
|
89
93
|
BUNDLED WITH
|
90
|
-
1.
|
94
|
+
1.14.6
|
data/LICENSE
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.3.0
|
data/deep_cloneable.gemspec
CHANGED
@@ -2,18 +2,18 @@
|
|
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 2.
|
5
|
+
# stub: deep_cloneable 2.3.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
|
-
s.name = "deep_cloneable"
|
9
|
-
s.version = "2.
|
8
|
+
s.name = "deep_cloneable"
|
9
|
+
s.version = "2.3.0"
|
10
10
|
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0"
|
12
|
-
s.require_paths = ["lib"
|
13
|
-
s.authors = ["Reinier de Lange"
|
14
|
-
s.date = "
|
15
|
-
s.description = "Extends the functionality of ActiveRecord::Base#dup to perform a deep clone that includes user specified associations. "
|
16
|
-
s.email = "r.j.delange@nedforce.nl"
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Reinier de Lange"]
|
14
|
+
s.date = "2017-06-14"
|
15
|
+
s.description = "Extends the functionality of ActiveRecord::Base#dup to perform a deep clone that includes user specified associations. "
|
16
|
+
s.email = "r.j.delange@nedforce.nl"
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"LICENSE",
|
19
19
|
"readme.md"
|
@@ -49,21 +49,21 @@ Gem::Specification.new do |s|
|
|
49
49
|
"test/test_deep_cloneable.rb",
|
50
50
|
"test/test_helper.rb"
|
51
51
|
]
|
52
|
-
s.homepage = "http://github.com/moiristo/deep_cloneable"
|
53
|
-
s.licenses = ["MIT"
|
54
|
-
s.rubygems_version = "2.
|
55
|
-
s.summary = "This gem gives every ActiveRecord::Base object the possibility to do a deep clone."
|
52
|
+
s.homepage = "http://github.com/moiristo/deep_cloneable"
|
53
|
+
s.licenses = ["MIT"]
|
54
|
+
s.rubygems_version = "2.4.8"
|
55
|
+
s.summary = "This gem gives every ActiveRecord::Base object the possibility to do a deep clone."
|
56
56
|
|
57
57
|
if s.respond_to? :specification_version then
|
58
58
|
s.specification_version = 4
|
59
59
|
|
60
60
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
61
|
-
s.add_runtime_dependency(%q<activerecord
|
61
|
+
s.add_runtime_dependency(%q<activerecord>, ["< 5.2.0", ">= 3.1.0"])
|
62
62
|
else
|
63
|
-
s.add_dependency(%q<activerecord
|
63
|
+
s.add_dependency(%q<activerecord>, ["< 5.2.0", ">= 3.1.0"])
|
64
64
|
end
|
65
65
|
else
|
66
|
-
s.add_dependency(%q<activerecord
|
66
|
+
s.add_dependency(%q<activerecord>, ["< 5.2.0", ">= 3.1.0"])
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
data/lib/deep_cloneable.rb
CHANGED
@@ -39,7 +39,7 @@ class ActiveRecord::Base
|
|
39
39
|
end
|
40
40
|
|
41
41
|
if options[:include]
|
42
|
-
|
42
|
+
normalized_includes_list(options[:include]).each do |association, conditions_or_deep_associations|
|
43
43
|
conditions = {}
|
44
44
|
|
45
45
|
if association.kind_of? Hash
|
@@ -54,34 +54,37 @@ class ActiveRecord::Base
|
|
54
54
|
conditions_or_deep_associations.delete_if {|entry| conditions.merge!(entry) if entry.is_a?(Hash) && (entry.key?(:if) || entry.key?(:unless)) }
|
55
55
|
end
|
56
56
|
|
57
|
-
dup_options =
|
57
|
+
dup_options = {}
|
58
|
+
dup_options.merge!(:include => conditions_or_deep_associations) if conditions_or_deep_associations.present?
|
58
59
|
dup_options.merge!(:except => deep_exceptions[association]) if deep_exceptions[association]
|
59
60
|
dup_options.merge!(:only => deep_onlinesses[association]) if deep_onlinesses[association]
|
60
61
|
dup_options.merge!(:dictionary => dict) if dict
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
62
|
+
dup_options.merge!(:skip_missing_associations => options[:skip_missing_associations]) if options[:skip_missing_associations]
|
63
|
+
|
64
|
+
if association_reflection = self.class.reflect_on_association(association)
|
65
|
+
if options[:validate] == false
|
66
|
+
kopy.instance_eval do
|
67
|
+
# Force :validate => false on all saves.
|
68
|
+
def perform_validations(options={})
|
69
|
+
options[:validate] = false
|
70
|
+
super(options)
|
71
|
+
end
|
71
72
|
end
|
72
73
|
end
|
73
|
-
end
|
74
74
|
|
75
|
-
|
76
|
-
|
75
|
+
association_type = association_reflection.macro
|
76
|
+
association_type = "#{association_type}_through" if association_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
77
77
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
duped_object = send(
|
79
|
+
"dup_#{association_type}_association",
|
80
|
+
{ :reflection => association_reflection, :association => association, :copy => kopy, :conditions => conditions, :dup_options => dup_options },
|
81
|
+
&block
|
82
|
+
)
|
83
83
|
|
84
|
-
|
84
|
+
kopy.send("#{association}=", duped_object)
|
85
|
+
elsif !options[:skip_missing_associations]
|
86
|
+
raise AssociationNotFoundException.new("#{self.class}##{association}")
|
87
|
+
end
|
85
88
|
end
|
86
89
|
end
|
87
90
|
|
@@ -173,6 +176,19 @@ class ActiveRecord::Base
|
|
173
176
|
def evaluate_conditions object, conditions
|
174
177
|
(conditions[:if] && conditions[:if].call(object)) || (conditions[:unless] && !conditions[:unless].call(object))
|
175
178
|
end
|
179
|
+
|
180
|
+
def normalized_includes_list includes
|
181
|
+
list = []
|
182
|
+
Array(includes).each do |item|
|
183
|
+
if item.is_a?(Hash) && item.size > 1
|
184
|
+
item.each{|key, value| list << { key => value } }
|
185
|
+
else
|
186
|
+
list << item
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
list
|
191
|
+
end
|
176
192
|
|
177
193
|
class AssociationNotFoundException < StandardError; end
|
178
194
|
|
data/readme.md
CHANGED
@@ -7,7 +7,7 @@ This gem gives every ActiveRecord::Base object the possibility to do a deep clon
|
|
7
7
|
## Requirements
|
8
8
|
|
9
9
|
* Ruby 1.8.7, 1.9.2, 1.9.3, 2.0.0, 2.1.5, 2.2.2, 2.3.0 (tested)
|
10
|
-
* Activerecord 3.1, 3.2, 4.0, 4.1, 4.2, 5.0.0
|
10
|
+
* Activerecord 3.1, 3.2, 4.0, 4.1, 4.2, 5.0.0.1 (tested)
|
11
11
|
* Rails 2.x/3.0 users, please check out the 'rails2.x-3.0' branch
|
12
12
|
|
13
13
|
## Installation
|
@@ -15,7 +15,7 @@ This gem gives every ActiveRecord::Base object the possibility to do a deep clon
|
|
15
15
|
* Add deep_cloneable to your Gemfile:
|
16
16
|
|
17
17
|
```ruby
|
18
|
-
gem 'deep_cloneable', '~> 2.
|
18
|
+
gem 'deep_cloneable', '~> 2.3.0'
|
19
19
|
```
|
20
20
|
|
21
21
|
## Upgrading from v1
|
@@ -123,6 +123,14 @@ pirate.deep_clone include: :parrot do |original, kopy|
|
|
123
123
|
end
|
124
124
|
```
|
125
125
|
|
126
|
+
### Skipping missing associations
|
127
|
+
|
128
|
+
By default, deep_cloneable will throw a `ActiveRecord::Base::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:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
pirate.deep_clone include: [:parrot, :rum], skip_missing_associations: true
|
132
|
+
```
|
133
|
+
|
126
134
|
### Note on Patches/Pull Requests
|
127
135
|
|
128
136
|
* Fork the project.
|
@@ -135,4 +143,4 @@ end
|
|
135
143
|
|
136
144
|
### Copyright
|
137
145
|
|
138
|
-
Copyright ©
|
146
|
+
Copyright © 2017 Reinier de Lange. See LICENSE for details.
|
data/test/models.rb
CHANGED
@@ -5,15 +5,28 @@ module Animal
|
|
5
5
|
has_many :ownerships
|
6
6
|
has_many :chickens, :through => :ownerships
|
7
7
|
end
|
8
|
+
|
8
9
|
class Pig < ActiveRecord::Base
|
9
10
|
belongs_to :human
|
10
11
|
end
|
11
12
|
|
12
|
-
class
|
13
|
+
class Bird < ActiveRecord::Base
|
14
|
+
belongs_to :planet
|
15
|
+
end
|
16
|
+
|
17
|
+
class Chicken < Bird
|
13
18
|
has_many :ownerships
|
14
19
|
has_many :humans, :through => :ownerships
|
15
20
|
end
|
16
21
|
|
22
|
+
class Dove < Bird
|
23
|
+
end
|
24
|
+
|
25
|
+
class Planet < ActiveRecord::Base
|
26
|
+
has_many :birds
|
27
|
+
end
|
28
|
+
|
29
|
+
|
17
30
|
class Ownership < ActiveRecord::Base
|
18
31
|
belongs_to :human
|
19
32
|
belongs_to :chicken
|
data/test/schema.rb
CHANGED
@@ -47,10 +47,16 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
47
47
|
t.column :name, :string
|
48
48
|
end
|
49
49
|
|
50
|
-
create_table :
|
50
|
+
create_table :planets, :force => true do |t|
|
51
51
|
t.column :name, :string
|
52
52
|
end
|
53
53
|
|
54
|
+
create_table :birds, :force => true do |t|
|
55
|
+
t.column :name, :string
|
56
|
+
t.column :type, :string
|
57
|
+
t.column :planet_id, :integer
|
58
|
+
end
|
59
|
+
|
54
60
|
create_table :ownerships, :force => true do |t|
|
55
61
|
t.column :human_id, :integer
|
56
62
|
t.column :chicken_id, :integer
|
data/test/test_deep_cloneable.rb
CHANGED
@@ -126,6 +126,15 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
126
126
|
assert_equal 1, deep_clone.gold_pieces.size
|
127
127
|
assert_equal 1, deep_clone.mateys.size
|
128
128
|
end
|
129
|
+
|
130
|
+
def test_multiple_and_deep_include_association_with_array_and_multikey_hash
|
131
|
+
deep_clone = @jack.deep_clone(:include => [:parrot, {:treasures => :gold_pieces, :mateys => {}}])
|
132
|
+
assert deep_clone.new_record?
|
133
|
+
assert deep_clone.save
|
134
|
+
assert_equal 1, deep_clone.treasures.size
|
135
|
+
assert_equal 1, deep_clone.gold_pieces.size
|
136
|
+
assert_equal 1, deep_clone.mateys.size
|
137
|
+
end
|
129
138
|
|
130
139
|
def test_with_belongs_to_relation
|
131
140
|
deep_clone = @jack.deep_clone(:include => :parrot)
|
@@ -208,6 +217,21 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
208
217
|
assert_equal 2, deep_clone_human.chickens.count
|
209
218
|
end
|
210
219
|
|
220
|
+
def test_should_skip_missing_associations
|
221
|
+
@earth = Animal::Planet.create :name => 'Earth'
|
222
|
+
@human = Animal::Human.create :name => "Michael"
|
223
|
+
@chicken = Animal::Chicken.create :name => 'Chick', :humans => [@human], :planet => @earth, :humans => [@human]
|
224
|
+
@dove = Animal::Dove.create :name => 'Dovey', :planet => @earth
|
225
|
+
|
226
|
+
assert_raises ActiveRecord::Base::DeepCloneable::AssociationNotFoundException do
|
227
|
+
@earth.deep_clone(:include => { :birds => :ownerships })
|
228
|
+
end
|
229
|
+
|
230
|
+
deep_clone_earth = @earth.deep_clone(:include => { :birds => :ownerships }, :skip_missing_associations => true)
|
231
|
+
assert_equal 2, deep_clone_earth.birds.size
|
232
|
+
assert deep_clone_earth.birds.detect{|bird| bird.is_a?(Animal::Chicken) }.ownerships.any?
|
233
|
+
end
|
234
|
+
|
211
235
|
def test_should_deep_clone_with_block
|
212
236
|
deep_clone = @jack.deep_clone(:include => :parrot) do |original, kopy|
|
213
237
|
kopy.cloned_from_id = original.id
|
@@ -427,4 +451,5 @@ class TestDeepCloneable < MiniTest::Unit::TestCase
|
|
427
451
|
assert_nil deep_clone.name
|
428
452
|
refute deep_clone.name_changed?
|
429
453
|
end
|
454
|
+
|
430
455
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deep_cloneable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.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:
|
11
|
+
date: 2017-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
88
|
version: '0'
|
89
89
|
requirements: []
|
90
90
|
rubyforge_project:
|
91
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.4.8
|
92
92
|
signing_key:
|
93
93
|
specification_version: 4
|
94
94
|
summary: This gem gives every ActiveRecord::Base object the possibility to do a deep
|