deep_cloneable 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
6
+
7
+ gemfile:
8
+ - gemfiles/3.0.gemfile
9
+ - gemfiles/3.1.gemfile
10
+ - gemfiles/3.2.gemfile
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise '3.0' do
2
+ gem 'activerecord', '~> 3.0'
3
+ end
4
+
5
+ appraise '3.1' do
6
+ gem 'activerecord', '~> 3.1'
7
+ end
8
+
9
+ appraise '3.2' do
10
+ gem 'activerecord', '~> 3.2'
11
+ end
data/Gemfile CHANGED
@@ -1,11 +1,8 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'activerecord', '>= 3.1'
3
+ gem 'appraisal'
4
+ gem 'activerecord', '>= 3.2'
5
+ gem 'jeweler'
6
+ gem 'sqlite3'
4
7
 
5
- group :development do
6
- gem 'jeweler'
7
- end
8
-
9
- group :test do
10
- gem 'sqlite3'
11
- end
8
+ # gem 'debugger'
data/Gemfile.lock CHANGED
@@ -1,38 +1,42 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- activemodel (3.2.12)
5
- activesupport (= 3.2.12)
4
+ activemodel (3.2.13)
5
+ activesupport (= 3.2.13)
6
6
  builder (~> 3.0.0)
7
- activerecord (3.2.12)
8
- activemodel (= 3.2.12)
9
- activesupport (= 3.2.12)
7
+ activerecord (3.2.13)
8
+ activemodel (= 3.2.13)
9
+ activesupport (= 3.2.13)
10
10
  arel (~> 3.0.2)
11
11
  tzinfo (~> 0.3.29)
12
- activesupport (3.2.12)
13
- i18n (~> 0.6)
12
+ activesupport (3.2.13)
13
+ i18n (= 0.6.1)
14
14
  multi_json (~> 1.0)
15
+ appraisal (0.5.2)
16
+ bundler
17
+ rake
15
18
  arel (3.0.2)
16
19
  builder (3.0.4)
17
20
  git (1.2.5)
18
- i18n (0.6.4)
21
+ i18n (0.6.1)
19
22
  jeweler (1.8.4)
20
23
  bundler (~> 1.0)
21
24
  git (>= 1.2.5)
22
25
  rake
23
26
  rdoc
24
- json (1.7.7)
25
- multi_json (1.6.1)
26
- rake (10.0.3)
27
- rdoc (4.0.0)
27
+ json (1.8.0)
28
+ multi_json (1.7.3)
29
+ rake (10.0.4)
30
+ rdoc (4.0.1)
28
31
  json (~> 1.4)
29
32
  sqlite3 (1.3.7)
30
- tzinfo (0.3.36)
33
+ tzinfo (0.3.37)
31
34
 
32
35
  PLATFORMS
33
36
  ruby
34
37
 
35
38
  DEPENDENCIES
36
- activerecord (>= 3.1)
39
+ activerecord (>= 3.2)
40
+ appraisal
37
41
  jeweler
38
42
  sqlite3
data/README.rdoc CHANGED
@@ -1,12 +1,14 @@
1
1
  = Deep_cloneable
2
2
 
3
+ {<img src="https://travis-ci.org/moiristo/deep_cloneable.png?branch=master" alt="Build Status" />}[https://travis-ci.org/moiristo/deep_cloneable]
4
+
3
5
  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
6
 
5
7
  == Requirements
6
8
 
7
- * Ruby 1.8.7, 1.9, 2.0.0
9
+ * Ruby 1.8.7, 1.9.3, 2.0.0
8
10
 
9
- * Activerecord 3.1, 3.2
11
+ * Activerecord 3.0 (when using _dup_), 3.1, 3.2
10
12
 
11
13
  * Rails 2.x/3.0 users, please check out the 'rails2.x-3.0' branch.
12
14
 
@@ -14,7 +16,7 @@ This gem gives every ActiveRecord::Base object the possibility to do a deep clon
14
16
 
15
17
  * In your Gemfile:
16
18
 
17
- gem 'deep_cloneable', '~> 1.5.0'
19
+ gem 'deep_cloneable', '~> 1.5.2'
18
20
 
19
21
  == Example
20
22
 
@@ -71,6 +73,8 @@ If this is not an option for you, it is also possible to populate the dictionary
71
73
  * fractious
72
74
  * Georges Gabereau
73
75
  * Christophe Belpaire
76
+ * Kevin Carter
77
+ * fokcep
74
78
 
75
79
  == Note on Patches/Pull Requests
76
80
 
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
- require 'rake'
2
+ require 'bundler/setup'
3
+ require 'appraisal'
3
4
 
4
5
  begin
5
6
  require 'jeweler'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.1
1
+ 1.5.2
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "deep_cloneable"
8
- s.version = "1.5.1"
8
+ s.version = "1.5.2"
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 = "2013-03-06"
12
+ s.date = "2013-06-10"
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 = [
@@ -18,6 +18,8 @@ Gem::Specification.new do |s|
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
+ ".travis.yml",
22
+ "Appraisals",
21
23
  "Gemfile",
22
24
  "Gemfile.lock",
23
25
  "LICENSE",
@@ -25,6 +27,12 @@ Gem::Specification.new do |s|
25
27
  "Rakefile",
26
28
  "VERSION",
27
29
  "deep_cloneable.gemspec",
30
+ "gemfiles/3.0.gemfile",
31
+ "gemfiles/3.0.gemfile.lock",
32
+ "gemfiles/3.1.gemfile",
33
+ "gemfiles/3.1.gemfile.lock",
34
+ "gemfiles/3.2.gemfile",
35
+ "gemfiles/3.2.gemfile.lock",
28
36
  "init.rb",
29
37
  "lib/deep_cloneable.rb",
30
38
  "test/database.yml",
@@ -35,22 +43,28 @@ Gem::Specification.new do |s|
35
43
  ]
36
44
  s.homepage = "http://github.com/moiristo/deep_cloneable"
37
45
  s.require_paths = ["lib"]
38
- s.rubygems_version = "1.8.24"
46
+ s.rubygems_version = "1.8.25"
39
47
  s.summary = "This gem gives every ActiveRecord::Base object the possibility to do a deep clone."
40
48
 
41
49
  if s.respond_to? :specification_version then
42
50
  s.specification_version = 3
43
51
 
44
52
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
- s.add_runtime_dependency(%q<activerecord>, [">= 3.1"])
46
- s.add_development_dependency(%q<jeweler>, [">= 0"])
53
+ s.add_runtime_dependency(%q<appraisal>, [">= 0"])
54
+ s.add_runtime_dependency(%q<activerecord>, [">= 3.2"])
55
+ s.add_runtime_dependency(%q<jeweler>, [">= 0"])
56
+ s.add_runtime_dependency(%q<sqlite3>, [">= 0"])
47
57
  else
48
- s.add_dependency(%q<activerecord>, [">= 3.1"])
58
+ s.add_dependency(%q<appraisal>, [">= 0"])
59
+ s.add_dependency(%q<activerecord>, [">= 3.2"])
49
60
  s.add_dependency(%q<jeweler>, [">= 0"])
61
+ s.add_dependency(%q<sqlite3>, [">= 0"])
50
62
  end
51
63
  else
52
- s.add_dependency(%q<activerecord>, [">= 3.1"])
64
+ s.add_dependency(%q<appraisal>, [">= 0"])
65
+ s.add_dependency(%q<activerecord>, [">= 3.2"])
53
66
  s.add_dependency(%q<jeweler>, [">= 0"])
67
+ s.add_dependency(%q<sqlite3>, [">= 0"])
54
68
  end
55
69
  end
56
70
 
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "jeweler"
7
+ gem "sqlite3"
8
+ gem "activerecord", "~> 3.0"
9
+
@@ -0,0 +1,42 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.13)
5
+ activesupport (= 3.2.13)
6
+ builder (~> 3.0.0)
7
+ activerecord (3.2.13)
8
+ activemodel (= 3.2.13)
9
+ activesupport (= 3.2.13)
10
+ arel (~> 3.0.2)
11
+ tzinfo (~> 0.3.29)
12
+ activesupport (3.2.13)
13
+ i18n (= 0.6.1)
14
+ multi_json (~> 1.0)
15
+ appraisal (0.5.2)
16
+ bundler
17
+ rake
18
+ arel (3.0.2)
19
+ builder (3.0.4)
20
+ git (1.2.5)
21
+ i18n (0.6.1)
22
+ jeweler (1.8.4)
23
+ bundler (~> 1.0)
24
+ git (>= 1.2.5)
25
+ rake
26
+ rdoc
27
+ json (1.8.0)
28
+ multi_json (1.7.3)
29
+ rake (10.0.4)
30
+ rdoc (4.0.1)
31
+ json (~> 1.4)
32
+ sqlite3 (1.3.7)
33
+ tzinfo (0.3.37)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ activerecord (~> 3.0)
40
+ appraisal
41
+ jeweler
42
+ sqlite3
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "jeweler"
7
+ gem "sqlite3"
8
+ gem "activerecord", "~> 3.1"
9
+
@@ -0,0 +1,42 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.13)
5
+ activesupport (= 3.2.13)
6
+ builder (~> 3.0.0)
7
+ activerecord (3.2.13)
8
+ activemodel (= 3.2.13)
9
+ activesupport (= 3.2.13)
10
+ arel (~> 3.0.2)
11
+ tzinfo (~> 0.3.29)
12
+ activesupport (3.2.13)
13
+ i18n (= 0.6.1)
14
+ multi_json (~> 1.0)
15
+ appraisal (0.5.2)
16
+ bundler
17
+ rake
18
+ arel (3.0.2)
19
+ builder (3.0.4)
20
+ git (1.2.5)
21
+ i18n (0.6.1)
22
+ jeweler (1.8.4)
23
+ bundler (~> 1.0)
24
+ git (>= 1.2.5)
25
+ rake
26
+ rdoc
27
+ json (1.8.0)
28
+ multi_json (1.7.3)
29
+ rake (10.0.4)
30
+ rdoc (4.0.1)
31
+ json (~> 1.4)
32
+ sqlite3 (1.3.7)
33
+ tzinfo (0.3.37)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ activerecord (~> 3.1)
40
+ appraisal
41
+ jeweler
42
+ sqlite3
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "jeweler"
7
+ gem "sqlite3"
8
+ gem "activerecord", "~> 3.2"
9
+
@@ -0,0 +1,42 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.13)
5
+ activesupport (= 3.2.13)
6
+ builder (~> 3.0.0)
7
+ activerecord (3.2.13)
8
+ activemodel (= 3.2.13)
9
+ activesupport (= 3.2.13)
10
+ arel (~> 3.0.2)
11
+ tzinfo (~> 0.3.29)
12
+ activesupport (3.2.13)
13
+ i18n (= 0.6.1)
14
+ multi_json (~> 1.0)
15
+ appraisal (0.5.2)
16
+ bundler
17
+ rake
18
+ arel (3.0.2)
19
+ builder (3.0.4)
20
+ git (1.2.5)
21
+ i18n (0.6.1)
22
+ jeweler (1.8.4)
23
+ bundler (~> 1.0)
24
+ git (>= 1.2.5)
25
+ rake
26
+ rdoc
27
+ json (1.8.0)
28
+ multi_json (1.7.3)
29
+ rake (10.0.4)
30
+ rdoc (4.0.1)
31
+ json (~> 1.4)
32
+ sqlite3 (1.3.7)
33
+ tzinfo (0.3.37)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ activerecord (~> 3.2)
40
+ appraisal
41
+ jeweler
42
+ sqlite3
@@ -3,12 +3,12 @@ class ActiveRecord::Base
3
3
  # ActiveRecord::Base has its own dup method for Ruby 1.8.7. We have to
4
4
  # redefine it and put it in a module so that we can override it in a
5
5
  # module and call the original with super().
6
- if !Object.respond_to? :initialize_dup, true
6
+ unless Object.respond_to?(:initialize_dup, true)
7
7
  ActiveRecord::Base.class_eval do
8
8
  module Dup
9
9
  def dup
10
10
  copy = super
11
- copy.initialize_dup(self)
11
+ copy.send(:initialize_dup, self)
12
12
  copy
13
13
  end
14
14
  end
@@ -57,7 +57,7 @@ class ActiveRecord::Base
57
57
  # ==== Cloning a model without an attribute or nested multiple attributes
58
58
  # pirate.clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
59
59
  #
60
- define_method :dup do |*args, &block|
60
+ def dup *args, &block
61
61
  options = args[0] || {}
62
62
 
63
63
  dict = options[:dictionary]
@@ -89,9 +89,9 @@ class ActiveRecord::Base
89
89
  association = association.keys.first
90
90
  end
91
91
 
92
- opts = deep_associations.blank? ? {} : {:include => deep_associations}
93
- opts.merge!(:except => deep_exceptions[association]) if deep_exceptions[association]
94
- opts.merge!(:dictionary => dict) if dict
92
+ dup_options = deep_associations.blank? ? {} : {:include => deep_associations}
93
+ dup_options.merge!(:except => deep_exceptions[association]) if deep_exceptions[association]
94
+ dup_options.merge!(:dictionary => dict) if dict
95
95
 
96
96
  association_reflection = self.class.reflect_on_association(association)
97
97
  raise AssociationNotFoundException.new("#{self.class}##{association}") if association_reflection.nil?
@@ -106,34 +106,11 @@ class ActiveRecord::Base
106
106
  end
107
107
  end
108
108
 
109
- cloned_object = case association_reflection.macro
110
- when :belongs_to, :has_one
111
- self.send(association) && self.send(association).send(__method__, opts, &block)
112
- when :has_many
113
- primary_key_name = association_reflection.foreign_key.to_s
114
-
115
- reverse_association_name = association_reflection.klass.reflect_on_all_associations.detect do |a|
116
- a.foreign_key.to_s == primary_key_name
117
- end.try(:name)
118
-
119
- self.send(association).collect do |obj|
120
- tmp = obj.send(__method__, opts, &block)
121
- tmp.send("#{primary_key_name}=", nil)
122
- tmp.send("#{reverse_association_name.to_s}=", kopy) if reverse_association_name
123
- tmp
124
- end
125
- when :has_and_belongs_to_many
126
- primary_key_name = association_reflection.foreign_key.to_s
127
-
128
- reverse_association_name = association_reflection.klass.reflect_on_all_associations.detect do |a|
129
- (a.macro == :has_and_belongs_to_many) && (a.association_foreign_key.to_s == primary_key_name)
130
- end.try(:name)
131
-
132
- self.send(association).collect do |obj|
133
- obj.send(reverse_association_name).target << kopy
134
- obj
135
- end
136
- end
109
+ cloned_object = send(
110
+ "dup_#{association_reflection.macro}_#{association_reflection.class.name.demodulize.underscore.gsub('_reflection', '')}",
111
+ { :reflection => association_reflection, :association => association, :copy => kopy, :dup_options => dup_options },
112
+ &block
113
+ )
137
114
 
138
115
  kopy.send("#{association}=", cloned_object)
139
116
  end
@@ -141,7 +118,55 @@ class ActiveRecord::Base
141
118
 
142
119
  return kopy
143
120
  end
144
-
121
+
122
+ private
123
+
124
+ def dup_belongs_to_association options, &block
125
+ self.send(options[:association]) && self.send(options[:association]).dup(options[:dup_options], &block)
126
+ end
127
+
128
+ def dup_has_one_association options, &block
129
+ dup_belongs_to_association options, &block
130
+ end
131
+
132
+ def dup_has_many_association options, &block
133
+ primary_key_name = options[:reflection].foreign_key.to_s
134
+
135
+ reverse_association_name = options[:reflection].klass.reflect_on_all_associations.detect do |reflection|
136
+ reflection.foreign_key.to_s == primary_key_name && reflection != options[:reflection]
137
+ end.try(:name)
138
+
139
+ self.send(options[:association]).collect do |obj|
140
+ tmp = obj.dup(options[:dup_options], &block)
141
+ tmp.send("#{primary_key_name}=", nil)
142
+ tmp.send("#{reverse_association_name.to_s}=", options[:copy]) if reverse_association_name
143
+ tmp
144
+ end
145
+ end
146
+
147
+ def dup_has_many_through options, &block
148
+ dup_join_association(
149
+ options.merge(:macro => :has_many, :primary_key_name => options[:reflection].through_reflection.foreign_key.to_s),
150
+ &block)
151
+ end
152
+
153
+ def dup_has_and_belongs_to_many_association options, &block
154
+ dup_join_association(
155
+ options.merge(:macro => :has_and_belongs_to_many, :primary_key_name => options[:reflection].foreign_key.to_s),
156
+ &block)
157
+ end
158
+
159
+ def dup_join_association options, &block
160
+ reverse_association_name = options[:reflection].klass.reflect_on_all_associations.detect do |reflection|
161
+ (reflection.macro == options[:macro]) && (reflection.association_foreign_key.to_s == options[:primary_key_name])
162
+ end.try(:name)
163
+
164
+ self.send(options[:association]).collect do |obj|
165
+ obj.send(reverse_association_name).target << options[:copy]
166
+ obj
167
+ end
168
+ end
169
+
145
170
  class AssociationNotFoundException < StandardError; end
146
171
  end
147
172
 
data/test/models.rb CHANGED
@@ -62,3 +62,23 @@ class ParentWithValidation < ActiveRecord::Base
62
62
  has_many :children, :class_name => 'ChildWithValidation'
63
63
  validates :name, :presence => true
64
64
  end
65
+
66
+ class Part < ActiveRecord::Base
67
+ # belongs_to :parent_part, :class_name => 'Part'
68
+ has_many :child_parts, :class_name => 'Part', :foreign_key => 'parent_part_id'
69
+ end
70
+
71
+ class Student < ActiveRecord::Base
72
+ has_many :student_assignments, :dependent => :destroy
73
+ has_many :subjects, :through => :student_assignments
74
+ end
75
+
76
+ class Subject < ActiveRecord::Base
77
+ has_many :student_assignments, :dependent => :destroy
78
+ has_many :students, :through => :student_assignments
79
+ end
80
+
81
+ class StudentAssignment < ActiveRecord::Base
82
+ belongs_to :subject
83
+ belongs_to :student
84
+ end
data/test/schema.rb CHANGED
@@ -71,4 +71,21 @@ ActiveRecord::Schema.define(:version => 1) do
71
71
  t.column :parent_with_validation_id, :integer
72
72
  end
73
73
 
74
+ create_table :parts, :force => true do |t|
75
+ t.column :name, :string
76
+ t.column :parent_part_id, :integer
77
+ end
78
+
79
+ create_table :students, :force => true do |t|
80
+ t.column :name, :string
81
+ end
82
+
83
+ create_table :subjects, :force => true do |t|
84
+ t.column :name, :string
85
+ end
86
+
87
+ create_table :student_assignments, :force => true do |t|
88
+ t.column :student_id, :integer
89
+ t.column :subject_id, :integer
90
+ end
74
91
  end
@@ -3,8 +3,6 @@ require File.dirname(__FILE__) + '/test_helper'
3
3
  class TestDeepCloneable < Test::Unit::TestCase
4
4
  load_schema
5
5
 
6
- @@clone_method = ActiveRecord::VERSION::MAJOR >= 3 && ActiveRecord::VERSION::MINOR > 0 ? :dup : :clone
7
-
8
6
  def setup
9
7
  @jack = Pirate.create(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
10
8
  @polly = Parrot.create(:name => 'Polly', :pirate => @jack)
@@ -15,16 +13,16 @@ class TestDeepCloneable < Test::Unit::TestCase
15
13
  end
16
14
 
17
15
  def test_single_dup_exception
18
- dup = @jack.send(@@clone_method, :except => :name)
16
+ dup = @jack.dup(:except => :name)
19
17
  assert dup.new_record?
20
18
  assert dup.save
21
- assert_equal @jack.name, @jack.send(@@clone_method).name # Old behaviour
19
+ assert_equal @jack.name, @jack.dup.name
22
20
  assert_nil dup.name
23
21
  assert_equal @jack.nick_name, dup.nick_name
24
22
  end
25
23
 
26
24
  def test_multiple_dup_exception
27
- dup = @jack.send(@@clone_method, :except => [:name, :nick_name])
25
+ dup = @jack.dup(:except => [:name, :nick_name])
28
26
  assert dup.new_record?
29
27
  assert dup.save
30
28
  assert_nil dup.name
@@ -33,14 +31,14 @@ class TestDeepCloneable < Test::Unit::TestCase
33
31
  end
34
32
 
35
33
  def test_single_include_association
36
- dup = @jack.send(@@clone_method, :include => :mateys)
34
+ dup = @jack.dup(:include => :mateys)
37
35
  assert dup.new_record?
38
36
  assert dup.save
39
37
  assert_equal 1, dup.mateys.size
40
38
  end
41
39
 
42
40
  def test_single_include_belongs_to_polymorphic_association
43
- dup = @jack.send(@@clone_method, :include => :ship)
41
+ dup = @jack.dup(:include => :ship)
44
42
  assert dup.new_record?
45
43
  assert dup.save
46
44
  assert_not_nil dup.ship
@@ -48,14 +46,14 @@ class TestDeepCloneable < Test::Unit::TestCase
48
46
  end
49
47
 
50
48
  def test_single_include_has_many_polymorphic_association
51
- dup = @ship.send(@@clone_method, :include => :pirates)
49
+ dup = @ship.dup(:include => :pirates)
52
50
  assert dup.new_record?
53
51
  assert dup.save
54
52
  assert dup.pirates.any?
55
53
  end
56
54
 
57
55
  def test_multiple_include_association
58
- dup = @jack.send(@@clone_method, :include => [:mateys, :treasures])
56
+ dup = @jack.dup(:include => [:mateys, :treasures])
59
57
  assert dup.new_record?
60
58
  assert dup.save
61
59
  assert_equal 1, dup.mateys.size
@@ -63,7 +61,7 @@ class TestDeepCloneable < Test::Unit::TestCase
63
61
  end
64
62
 
65
63
  def test_deep_include_association
66
- dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces})
64
+ dup = @jack.dup(:include => {:treasures => :gold_pieces})
67
65
  assert dup.new_record?
68
66
  assert dup.save
69
67
  assert_equal 1, dup.treasures.size
@@ -71,7 +69,7 @@ class TestDeepCloneable < Test::Unit::TestCase
71
69
  end
72
70
 
73
71
  def test_include_association_assignments
74
- dup = @jack.send(@@clone_method, :include => :treasures)
72
+ dup = @jack.dup(:include => :treasures)
75
73
  assert dup.new_record?
76
74
 
77
75
  dup.treasures.each do |treasure|
@@ -80,7 +78,7 @@ class TestDeepCloneable < Test::Unit::TestCase
80
78
  end
81
79
 
82
80
  def test_multiple_and_deep_include_association
83
- dup = @jack.send(@@clone_method, :include => {:treasures => :gold_pieces, :mateys => {}})
81
+ dup = @jack.dup(:include => {:treasures => :gold_pieces, :mateys => {}})
84
82
  assert dup.new_record?
85
83
  assert dup.save
86
84
  assert_equal 1, dup.treasures.size
@@ -89,7 +87,7 @@ class TestDeepCloneable < Test::Unit::TestCase
89
87
  end
90
88
 
91
89
  def test_multiple_and_deep_include_association_with_array
92
- dup = @jack.send(@@clone_method, :include => [{:treasures => :gold_pieces}, :mateys])
90
+ dup = @jack.dup(:include => [{:treasures => :gold_pieces}, :mateys])
93
91
  assert dup.new_record?
94
92
  assert dup.save
95
93
  assert_equal 1, dup.treasures.size
@@ -98,14 +96,14 @@ class TestDeepCloneable < Test::Unit::TestCase
98
96
  end
99
97
 
100
98
  def test_with_belongs_to_relation
101
- dup = @jack.send(@@clone_method, :include => :parrot)
99
+ dup = @jack.dup(:include => :parrot)
102
100
  assert dup.new_record?
103
101
  assert dup.save
104
102
  assert_not_equal dup.parrot, @jack.parrot
105
103
  end
106
104
 
107
105
  def test_should_pass_nested_exceptions
108
- dup = @jack.send(@@clone_method, :include => :parrot, :except => [:name, { :parrot => [:name] }])
106
+ dup = @jack.dup(:include => :parrot, :except => [:name, { :parrot => [:name] }])
109
107
  assert dup.new_record?
110
108
  assert dup.save
111
109
  assert_not_equal dup.parrot, @jack.parrot
@@ -115,7 +113,7 @@ class TestDeepCloneable < Test::Unit::TestCase
115
113
 
116
114
  def test_should_not_double_dup_when_using_dictionary
117
115
  current_matey_count = Matey.count
118
- dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
116
+ dup = @jack.dup(:include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
119
117
  assert dup.new_record?
120
118
  dup.save!
121
119
 
@@ -126,9 +124,9 @@ class TestDeepCloneable < Test::Unit::TestCase
126
124
  current_matey_count = Matey.count
127
125
 
128
126
  dict = { :mateys => {} }
129
- @jack.mateys.each{|m| dict[:mateys][m] = m.send(@@clone_method) }
127
+ @jack.mateys.each{|m| dict[:mateys][m] = m.dup }
130
128
 
131
- dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :dictionary => dict)
129
+ dup = @jack.dup(:include => [:mateys, { :treasures => :matey }], :dictionary => dict)
132
130
  assert dup.new_record?
133
131
  dup.save!
134
132
 
@@ -139,7 +137,7 @@ class TestDeepCloneable < Test::Unit::TestCase
139
137
  @human = Animal::Human.create :name => "Michael"
140
138
  @pig = Animal::Pig.create :human => @human, :name => 'big pig'
141
139
 
142
- dup_human = @human.send(@@clone_method, :include => [:pigs])
140
+ dup_human = @human.dup(:include => [:pigs])
143
141
  assert dup_human.new_record?
144
142
  assert dup_human.save
145
143
  assert_equal 1, dup_human.pigs.count
@@ -147,7 +145,7 @@ class TestDeepCloneable < Test::Unit::TestCase
147
145
  @human2 = Animal::Human.create :name => "John"
148
146
  @pig2 = @human2.pigs.create :name => 'small pig'
149
147
 
150
- dup_human_2 = @human.send(@@clone_method, :include => [:pigs])
148
+ dup_human_2 = @human.dup(:include => [:pigs])
151
149
  assert dup_human_2.new_record?
152
150
  assert dup_human_2.save
153
151
  assert_equal 1, dup_human_2.pigs.count
@@ -161,14 +159,14 @@ class TestDeepCloneable < Test::Unit::TestCase
161
159
  @human.chickens << [@chicken1, @chicken2]
162
160
  @human2.chickens << [@chicken1, @chicken2]
163
161
 
164
- dup_human = @human.send(@@clone_method, :include => :ownerships)
162
+ dup_human = @human.dup(:include => :ownerships)
165
163
  assert dup_human.new_record?
166
164
  assert dup_human.save
167
165
  assert_equal 2, dup_human.chickens.count
168
166
  end
169
167
 
170
168
  def test_should_dup_with_block
171
- dup = @jack.send(@@clone_method, :include => :parrot) do |original, kopy|
169
+ dup = @jack.dup(:include => :parrot) do |original, kopy|
172
170
  kopy.cloned_from_id = original.id
173
171
  end
174
172
 
@@ -258,4 +256,24 @@ class TestDeepCloneable < Test::Unit::TestCase
258
256
  assert_equal dup_parent.errors.messages, :children => ["is invalid"]
259
257
  end
260
258
 
259
+ def test_self_join_has_many
260
+ parent_part = Part.create(:name => 'Parent')
261
+ child1 = Part.create(:name => 'Child 1', :parent_part_id => parent_part.id)
262
+ child2 = Part.create(:name => 'Child 2', :parent_part_id => parent_part.id)
263
+
264
+ dup_part = parent_part.dup :include => :child_parts
265
+ assert dup_part.save
266
+ assert_equal 2, dup_part.child_parts.size
267
+ end
268
+
269
+ def test_should_include_has_many_through_associations
270
+ subject1 = Subject.create(:name => 'subject 1')
271
+ subject2 = Subject.create(:name => 'subject 2')
272
+ student = Student.create(:name => 'Parent', :subjects => [subject1, subject2])
273
+
274
+ dup = student.dup :include => :subjects
275
+ assert_equal 2, dup.subjects.size
276
+ assert_equal [[student, dup],[student, dup]], dup.subjects.map{|subject| subject.students }
277
+ end
278
+
261
279
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'pp'
4
+ # require 'debugger'
4
5
 
5
6
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
7
  $LOAD_PATH.unshift(File.dirname(__FILE__))
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.5.1
4
+ version: 1.5.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-06 00:00:00.000000000 Z
12
+ date: 2013-06-10 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: appraisal
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'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: activerecord
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -18,7 +34,7 @@ dependencies:
18
34
  requirements:
19
35
  - - ! '>='
20
36
  - !ruby/object:Gem::Version
21
- version: '3.1'
37
+ version: '3.2'
22
38
  type: :runtime
23
39
  prerelease: false
24
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +42,7 @@ dependencies:
26
42
  requirements:
27
43
  - - ! '>='
28
44
  - !ruby/object:Gem::Version
29
- version: '3.1'
45
+ version: '3.2'
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: jeweler
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -35,7 +51,23 @@ dependencies:
35
51
  - - ! '>='
36
52
  - !ruby/object:Gem::Version
37
53
  version: '0'
38
- type: :development
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: sqlite3
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
39
71
  prerelease: false
40
72
  version_requirements: !ruby/object:Gem::Requirement
41
73
  none: false
@@ -53,6 +85,8 @@ extra_rdoc_files:
53
85
  - README.rdoc
54
86
  files:
55
87
  - .document
88
+ - .travis.yml
89
+ - Appraisals
56
90
  - Gemfile
57
91
  - Gemfile.lock
58
92
  - LICENSE
@@ -60,6 +94,12 @@ files:
60
94
  - Rakefile
61
95
  - VERSION
62
96
  - deep_cloneable.gemspec
97
+ - gemfiles/3.0.gemfile
98
+ - gemfiles/3.0.gemfile.lock
99
+ - gemfiles/3.1.gemfile
100
+ - gemfiles/3.1.gemfile.lock
101
+ - gemfiles/3.2.gemfile
102
+ - gemfiles/3.2.gemfile.lock
63
103
  - init.rb
64
104
  - lib/deep_cloneable.rb
65
105
  - test/database.yml
@@ -81,7 +121,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
121
  version: '0'
82
122
  segments:
83
123
  - 0
84
- hash: 250465939979745511
124
+ hash: -3147244194353225191
85
125
  required_rubygems_version: !ruby/object:Gem::Requirement
86
126
  none: false
87
127
  requirements:
@@ -90,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
130
  version: '0'
91
131
  requirements: []
92
132
  rubyforge_project:
93
- rubygems_version: 1.8.24
133
+ rubygems_version: 1.8.25
94
134
  signing_key:
95
135
  specification_version: 3
96
136
  summary: This gem gives every ActiveRecord::Base object the possibility to do a deep