deep_cloneable 1.2.4 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -4,7 +4,7 @@ This gem gives every ActiveRecord::Base object the possibility to do a deep clon
4
4
 
5
5
  == Requirements
6
6
 
7
- * Activerecord, tested with Rails 3.
7
+ * Activerecord, tested with AR 3 & 3.1.
8
8
 
9
9
  == Installation
10
10
 
@@ -60,6 +60,12 @@ If this is not an option for you, it is also possible to populate the dictionary
60
60
  === Cloning a model without an attribute or nested multiple attributes
61
61
  pirate.clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
62
62
 
63
+ == Contributors
64
+
65
+ * Michael He
66
+ * Indrek Juhkam
67
+ * Mart Karu
68
+
63
69
  == Note on Patches/Pull Requests
64
70
 
65
71
  * Fork the project.
@@ -72,4 +78,4 @@ If this is not an option for you, it is also possible to populate the dictionary
72
78
 
73
79
  == Copyright
74
80
 
75
- Copyright (c) 2010 Reinier de Lange. See LICENSE for details.
81
+ Copyright (c) 2011 Reinier de Lange. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.4
1
+ 1.3.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{deep_cloneable}
8
- s.version = "1.2.4"
8
+ s.version = "1.3.0"
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 = %q{2011-06-15}
12
+ s.date = %q{2011-07-11}
13
13
  s.description = %q{Extends the functionality of ActiveRecord::Base#clone to perform a deep clone that includes user specified associations. }
14
14
  s.email = %q{r.j.delange@nedforce.nl}
15
15
  s.extra_rdoc_files = [
@@ -1,5 +1,7 @@
1
1
  class ActiveRecord::Base
2
2
  module DeepCloneable
3
+ @@rails31 = ActiveRecord::VERSION::MAJOR >= 3 && ActiveRecord::VERSION::MINOR > 0
4
+
3
5
  # clones an ActiveRecord model.
4
6
  # if passed the :include option, it will deep clone the given associations
5
7
  # if passed the :except option, it won't clone the given attributes
@@ -40,7 +42,9 @@ class ActiveRecord::Base
40
42
  # ==== Cloning a model without an attribute or nested multiple attributes
41
43
  # pirate.clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
42
44
  #
43
- def clone(options = {})
45
+ define_method (@@rails31 ? :dup : :clone) do |*args|
46
+ options = args[0] || {}
47
+
44
48
  dict = options[:dictionary]
45
49
  dict ||= {} if options.delete(:use_dictionary)
46
50
 
@@ -77,15 +81,17 @@ class ActiveRecord::Base
77
81
 
78
82
  cloned_object = case association_reflection.macro
79
83
  when :belongs_to, :has_one
80
- self.send(association) && self.send(association).clone(opts)
84
+ self.send(association) && self.send(association).send(__method__, opts)
81
85
  when :has_many, :has_and_belongs_to_many
82
- reverse_association_name = association_reflection.klass.reflect_on_all_associations.detect do |a|
83
- a.primary_key_name.to_s == association_reflection.primary_key_name.to_s
86
+ primary_key_name = (@@rails31 ? association_reflection.foreign_key : association_reflection.primary_key_name).to_s
87
+
88
+ reverse_association_name = association_reflection.klass.reflect_on_all_associations.detect do |a|
89
+ a.send(@@rails31 ? :foreign_key : :primary_key_name).to_s == primary_key_name
84
90
  end.try(:name)
85
91
 
86
92
  self.send(association).collect do |obj|
87
- tmp = obj.clone(opts)
88
- tmp.send("#{association_reflection.primary_key_name.to_s}=", nil)
93
+ tmp = obj.send(__method__, opts)
94
+ tmp.send("#{primary_key_name}=", nil)
89
95
  tmp.send("#{reverse_association_name.to_s}=", kopy) if reverse_association_name
90
96
  tmp
91
97
  end
@@ -2,8 +2,10 @@ require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
3
  class TestDeepCloneable < Test::Unit::TestCase
4
4
  load_schema
5
+
6
+ @@clone_method = ActiveRecord::VERSION::MAJOR >= 3 && ActiveRecord::VERSION::MINOR > 0 ? :dup : :clone
5
7
 
6
- def setup
8
+ def setup
7
9
  @jack = Pirate.create(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
8
10
  @polly = Parrot.create(:name => 'Polly', :pirate => @jack)
9
11
  @john = Matey.create(:name => 'John', :pirate => @jack)
@@ -12,109 +14,109 @@ class TestDeepCloneable < Test::Unit::TestCase
12
14
  @ship = BattleShip.create(:name => 'Black Pearl', :pirates => [@jack])
13
15
  end
14
16
 
15
- def test_single_clone_exception
16
- clone = @jack.clone(:except => :name)
17
- assert clone.save
18
- assert_equal @jack.name, @jack.clone.name # Old behaviour
19
- assert_nil clone.name
20
- assert_equal @jack.nick_name, clone.nick_name
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
21
23
  end
22
24
 
23
- def test_multiple_clone_exception
24
- clone = @jack.clone(:except => [:name, :nick_name])
25
- assert clone.save
26
- assert_nil clone.name
27
- assert_equal 'no nickname', clone.nick_name
28
- assert_equal @jack.age, clone.age
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
29
31
  end
30
32
 
31
33
  def test_single_include_association
32
- clone = @jack.clone(:include => :mateys)
33
- assert clone.save
34
- assert_equal 1, clone.mateys.size
34
+ dup = @jack.send(@@clone_method, :include => :mateys)
35
+ assert dup.save
36
+ assert_equal 1, dup.mateys.size
35
37
  end
36
38
 
37
39
  def test_single_include_belongs_to_polymorphic_association
38
- clone = @jack.clone(:include => :ship)
39
- assert clone.save
40
- assert_not_nil clone.ship
41
- assert_not_equal @jack.ship, clone.ship
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
42
44
  end
43
45
 
44
46
  def test_single_include_has_many_polymorphic_association
45
- clone = @ship.clone(:include => :pirates)
46
- assert clone.save
47
- assert clone.pirates.any?
47
+ dup = @ship.send(@@clone_method, :include => :pirates)
48
+ assert dup.save
49
+ assert dup.pirates.any?
48
50
  end
49
51
 
50
52
  def test_multiple_include_association
51
- clone = @jack.clone(:include => [:mateys, :treasures])
52
- assert clone.save
53
- assert_equal 1, clone.mateys.size
54
- assert_equal 1, clone.treasures.size
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
55
57
  end
56
58
 
57
59
  def test_deep_include_association
58
- clone = @jack.clone(:include => {:treasures => :gold_pieces})
59
- assert clone.save
60
- assert_equal 1, clone.treasures.size
61
- assert_equal 1, clone.gold_pieces.size
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
62
64
  end
63
65
 
64
66
  def test_include_association_assignments
65
- clone = @jack.clone(:include => :treasures)
67
+ dup = @jack.send(@@clone_method, :include => :treasures)
66
68
 
67
- clone.treasures.each do |treasure|
68
- assert_equal clone, treasure.pirate
69
+ dup.treasures.each do |treasure|
70
+ assert_equal dup, treasure.pirate
69
71
  end
70
72
  end
71
73
 
72
74
  def test_multiple_and_deep_include_association
73
- clone = @jack.clone(:include => {:treasures => :gold_pieces, :mateys => {}})
74
- assert clone.save
75
- assert_equal 1, clone.treasures.size
76
- assert_equal 1, clone.gold_pieces.size
77
- assert_equal 1, clone.mateys.size
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
78
80
  end
79
81
 
80
82
  def test_multiple_and_deep_include_association_with_array
81
- clone = @jack.clone(:include => [{:treasures => :gold_pieces}, :mateys])
82
- assert clone.save
83
- assert_equal 1, clone.treasures.size
84
- assert_equal 1, clone.gold_pieces.size
85
- assert_equal 1, clone.mateys.size
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
86
88
  end
87
89
 
88
90
  def test_with_belongs_to_relation
89
- clone = @jack.clone(:include => :parrot)
90
- assert clone.save
91
- assert_not_equal clone.parrot, @jack.parrot
91
+ dup = @jack.send(@@clone_method, :include => :parrot)
92
+ assert dup.save
93
+ assert_not_equal dup.parrot, @jack.parrot
92
94
  end
93
95
 
94
96
  def test_should_pass_nested_exceptions
95
- clone = @jack.clone(:include => :parrot, :except => [:name, { :parrot => [:name] }])
96
- assert clone.save
97
- assert_not_equal clone.parrot, @jack.parrot
97
+ dup = @jack.send(@@clone_method, :include => :parrot, :except => [:name, { :parrot => [:name] }])
98
+ assert dup.save
99
+ assert_not_equal dup.parrot, @jack.parrot
98
100
  assert_not_nil @jack.parrot.name
99
- assert_nil clone.parrot.name
101
+ assert_nil dup.parrot.name
100
102
  end
101
103
 
102
- def test_should_not_double_clone_when_using_dictionary
104
+ def test_should_not_double_dup_when_using_dictionary
103
105
  current_matey_count = Matey.count
104
- clone = @jack.clone(:include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
105
- clone.save!
106
+ dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
107
+ dup.save!
106
108
 
107
109
  assert_equal current_matey_count + 1, Matey.count
108
110
  end
109
111
 
110
- def test_should_not_double_clone_when_using_manual_dictionary
112
+ def test_should_not_double_dup_when_using_manual_dictionary
111
113
  current_matey_count = Matey.count
112
114
 
113
115
  dict = { :mateys => {} }
114
- @jack.mateys.each{|m| dict[:mateys][m] = m.clone }
116
+ @jack.mateys.each{|m| dict[:mateys][m] = m.send(@@clone_method) }
115
117
 
116
- clone = @jack.clone(:include => [:mateys, { :treasures => :matey }], :dictionary => dict)
117
- clone.save!
118
+ dup = @jack.send(@@clone_method, :include => [:mateys, { :treasures => :matey }], :dictionary => dict)
119
+ dup.save!
118
120
 
119
121
  assert_equal current_matey_count + 1, Matey.count
120
122
  end
@@ -123,19 +125,19 @@ class TestDeepCloneable < Test::Unit::TestCase
123
125
  @human = Animal::Human.create :name => "Michael"
124
126
  @pig = Animal::Pig.create :human => @human, :name => 'big pig'
125
127
 
126
- clone_human = @human.clone :include => [:pigs]
127
- assert clone_human.save
128
- assert_equal 1, clone_human.pigs.count
128
+ dup_human = @human.send(@@clone_method, :include => [:pigs])
129
+ assert dup_human.save
130
+ assert_equal 1, dup_human.pigs.count
129
131
 
130
132
  @human2 = Animal::Human.create :name => "John"
131
133
  @pig2 = @human2.pigs.create :name => 'small pig'
132
134
 
133
- clone_human_2 = @human.clone :include => [:pigs]
134
- assert clone_human_2.save
135
- assert_equal 1, clone_human_2.pigs.count
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
136
138
  end
137
139
 
138
- def test_should_clone_many_to_many_associations
140
+ def test_should_dup_many_to_many_associations
139
141
  @human = Animal::Human.create :name => "Michael"
140
142
  @human2 = Animal::Human.create :name => "Jack"
141
143
  @chicken1 = Animal::Chicken.create :name => 'Chick1'
@@ -143,9 +145,9 @@ class TestDeepCloneable < Test::Unit::TestCase
143
145
  @human.chickens << [@chicken1, @chicken2]
144
146
  @human2.chickens << [@chicken1, @chicken2]
145
147
 
146
- clone_human = @human.clone :include => :ownerships
147
- assert clone_human.save
148
- assert_equal 2, clone_human.chickens.count
148
+ dup_human = @human.send(@@clone_method, :include => :ownerships)
149
+ assert dup_human.save
150
+ assert_equal 2, dup_human.chickens.count
149
151
  end
150
152
 
151
153
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deep_cloneable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 2
9
- - 4
10
- version: 1.2.4
8
+ - 3
9
+ - 0
10
+ version: 1.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Reinier de Lange
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-15 00:00:00 +02:00
18
+ date: 2011-07-11 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21