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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6f91e67baa2dd1118f4ab807655791d72e9f69e
4
- data.tar.gz: 3cd1a98dd2828ab747e267f8f749b8fc41b4cc79
3
+ metadata.gz: 2965ed86adcfda63e876533015e4a55e4fb0316f
4
+ data.tar.gz: 6d9ef9a44e135ecf9baa769e721e25c62b4f893c
5
5
  SHA512:
6
- metadata.gz: 2a23f55f760ec9de1b06fc1f2fe09f4fa28224c0a545e3607b185129c8625e7344a6e3c5de5e400bc2caedf5b39ccaa890a5e5fcddda5cceea47b2b88fad4910
7
- data.tar.gz: 490a16bde06aaa25654aa0264214f5b7474d7233c7681da4acaef0073a45fd1ecbe14814fb1cbbd219b2647b5d4c914f3dee919d33c361dc0cfcb2eeb0a7ace1
6
+ metadata.gz: e11fe1537382bc8fe904aa02f0dd33b205bc926093d383f6ef7a0023509c279e430f04732f5707c62ef077b7de86516f66d935e90055e4fd1b8a1b2f6612bb93
7
+ data.tar.gz: c2b879a4b1885214c647c632ace3f8ba895b0c13ac12d34bed2c2bb9ccf776060a1add719a6a1219a9fbe7c4b3a4b30dcb33149466bda4fefec4b2b3f66c2eb0
@@ -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.14.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
- oauth2
35
- hashie (3.4.4)
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.1.1)
39
+ jeweler (2.3.6)
39
40
  builder
40
- bundler (>= 1.0)
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
- semver
49
+ semver2
48
50
  json (1.8.3)
49
- jwt (1.5.1)
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.5.5)
55
+ multi_xml (0.6.0)
53
56
  multipart-post (2.0.0)
54
57
  nokogiri (1.5.11)
55
- oauth2 (1.1.0)
56
- faraday (>= 0.8, < 0.10)
57
- jwt (~> 1.0, < 1.5.2)
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
- semver (1.0.1)
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.11.2
94
+ 1.14.6
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2016 Reinier de Lange
1
+ Copyright (c) 2017 Reinier de Lange
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.2.2
1
+ 2.3.0
@@ -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.2.2 ruby lib
5
+ # stub: deep_cloneable 2.3.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
- s.name = "deep_cloneable".freeze
9
- s.version = "2.2.2"
8
+ s.name = "deep_cloneable"
9
+ s.version = "2.3.0"
10
10
 
11
- s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
- s.require_paths = ["lib".freeze]
13
- s.authors = ["Reinier de Lange".freeze]
14
- s.date = "2016-10-10"
15
- s.description = "Extends the functionality of ActiveRecord::Base#dup to perform a deep clone that includes user specified associations. ".freeze
16
- s.email = "r.j.delange@nedforce.nl".freeze
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".freeze
53
- s.licenses = ["MIT".freeze]
54
- s.rubygems_version = "2.6.4".freeze
55
- s.summary = "This gem gives every ActiveRecord::Base object the possibility to do a deep clone.".freeze
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>.freeze, ["< 5.2.0", ">= 3.1.0"])
61
+ s.add_runtime_dependency(%q<activerecord>, ["< 5.2.0", ">= 3.1.0"])
62
62
  else
63
- s.add_dependency(%q<activerecord>.freeze, ["< 5.2.0", ">= 3.1.0"])
63
+ s.add_dependency(%q<activerecord>, ["< 5.2.0", ">= 3.1.0"])
64
64
  end
65
65
  else
66
- s.add_dependency(%q<activerecord>.freeze, ["< 5.2.0", ">= 3.1.0"])
66
+ s.add_dependency(%q<activerecord>, ["< 5.2.0", ">= 3.1.0"])
67
67
  end
68
68
  end
69
69
 
@@ -39,7 +39,7 @@ class ActiveRecord::Base
39
39
  end
40
40
 
41
41
  if options[:include]
42
- Array(options[:include]).each do |association, conditions_or_deep_associations|
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 = conditions_or_deep_associations.blank? ? {} : {:include => conditions_or_deep_associations}
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
- association_reflection = self.class.reflect_on_association(association)
63
- raise AssociationNotFoundException.new("#{self.class}##{association}") if association_reflection.nil?
64
-
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)
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
- association_type = association_reflection.macro
76
- association_type = "#{association_type}_through" if association_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
75
+ association_type = association_reflection.macro
76
+ association_type = "#{association_type}_through" if association_reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
77
77
 
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
- )
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
- kopy.send("#{association}=", duped_object)
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-rc1 (tested)
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.2.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 &copy; 2016 Reinier de Lange. See LICENSE for details.
146
+ Copyright &copy; 2017 Reinier de Lange. See LICENSE for details.
@@ -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 Chicken < ActiveRecord::Base
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
@@ -47,10 +47,16 @@ ActiveRecord::Schema.define(:version => 1) do
47
47
  t.column :name, :string
48
48
  end
49
49
 
50
- create_table :chickens, :force => true do |t|
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
@@ -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.2.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: 2016-10-10 00:00:00.000000000 Z
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.6.4
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