deep_cloneable 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +9 -5
- data/VERSION +1 -1
- data/deep_cloneable.gemspec +2 -2
- data/lib/deep_cloneable.rb +33 -17
- data/test/test_deep_cloneable.rb +8 -0
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -25,12 +25,7 @@ And include the gem in your apps config
|
|
25
25
|
./script/plugin install git://github.com/moiristo/deep_cloneable.git
|
26
26
|
|
27
27
|
== Example
|
28
|
-
|
29
|
-
=== Cloning a model without an attribute
|
30
|
-
pirate.clone :except => :name
|
31
28
|
|
32
|
-
=== Cloning a model without multiple attributes
|
33
|
-
pirate.clone :except => [:name, :nick_name]
|
34
29
|
=== Cloning one single association
|
35
30
|
pirate.clone :include => :mateys
|
36
31
|
|
@@ -42,6 +37,15 @@ And include the gem in your apps config
|
|
42
37
|
|
43
38
|
=== Cloning really deep with multiple associations
|
44
39
|
pirate.clone :include => [:mateys, {:treasures => :gold_pieces}]
|
40
|
+
|
41
|
+
=== Cloning a model without an attribute
|
42
|
+
pirate.clone :except => :name
|
43
|
+
|
44
|
+
=== Cloning a model without multiple attributes
|
45
|
+
pirate.clone :except => [:name, :nick_name]
|
46
|
+
|
47
|
+
=== Cloning a model without an attribute or nested multiple attributes
|
48
|
+
pirate.clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
|
45
49
|
|
46
50
|
== Note on Patches/Pull Requests
|
47
51
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.1.0
|
data/deep_cloneable.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{deep_cloneable}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.1.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{2010-10-
|
12
|
+
s.date = %q{2010-10-19}
|
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 = [
|
data/lib/deep_cloneable.rb
CHANGED
@@ -6,30 +6,37 @@ class ActiveRecord::Base
|
|
6
6
|
#
|
7
7
|
# === Usage:
|
8
8
|
#
|
9
|
-
# ==== Cloning a model without an attribute
|
10
|
-
# pirate.clone :except => :name
|
11
|
-
#
|
12
|
-
# ==== Cloning a model without multiple attributes
|
13
|
-
# pirate.clone :except => [:name, :nick_name]
|
14
9
|
# ==== Cloning one single association
|
15
|
-
#
|
16
|
-
#
|
10
|
+
# pirate.clone :include => :mateys
|
11
|
+
#
|
17
12
|
# ==== Cloning multiple associations
|
18
|
-
#
|
19
|
-
#
|
13
|
+
# pirate.clone :include => [:mateys, :treasures]
|
14
|
+
#
|
20
15
|
# ==== Cloning really deep
|
21
|
-
#
|
22
|
-
#
|
16
|
+
# pirate.clone :include => {:treasures => :gold_pieces}
|
17
|
+
#
|
23
18
|
# ==== Cloning really deep with multiple associations
|
24
|
-
#
|
19
|
+
# pirate.clone :include => [:mateys, {:treasures => :gold_pieces}]
|
20
|
+
#
|
21
|
+
# ==== Cloning a model without an attribute
|
22
|
+
# pirate.clone :except => :name
|
23
|
+
#
|
24
|
+
# ==== Cloning a model without multiple attributes
|
25
|
+
# pirate.clone :except => [:name, :nick_name]
|
26
|
+
#
|
27
|
+
# ==== Cloning a model without an attribute or nested multiple attributes
|
28
|
+
# pirate.clone :include => :parrot, :except => [:name, { :parrot => [:name] }]
|
25
29
|
#
|
26
30
|
def clone(options = {})
|
27
31
|
kopy = super()
|
28
|
-
|
32
|
+
|
33
|
+
deep_exceptions = {}
|
29
34
|
if options[:except]
|
30
|
-
|
31
|
-
|
35
|
+
exceptions = options[:except].nil? ? [] : [options[:except]].flatten
|
36
|
+
exceptions.each do |attribute|
|
37
|
+
kopy.send(:write_attribute, attribute, attributes_from_column_definition[attribute.to_s]) unless attribute.kind_of?(Hash)
|
32
38
|
end
|
39
|
+
deep_exceptions = exceptions.select{|e| e.kind_of?(Hash) }.inject({}){|m,h| m.merge(h) }
|
33
40
|
end
|
34
41
|
|
35
42
|
if options[:include]
|
@@ -38,12 +45,21 @@ class ActiveRecord::Base
|
|
38
45
|
deep_associations = association[association.keys.first]
|
39
46
|
association = association.keys.first
|
40
47
|
end
|
48
|
+
|
41
49
|
opts = deep_associations.blank? ? {} : {:include => deep_associations}
|
42
|
-
|
50
|
+
opts.merge!(:except => deep_exceptions[association]) if deep_exceptions[association]
|
51
|
+
|
52
|
+
association_reflection = self.class.reflect_on_association(association)
|
53
|
+
cloned_object = case association_reflection.macro
|
43
54
|
when :belongs_to, :has_one
|
44
55
|
self.send(association) && self.send(association).clone(opts)
|
45
56
|
when :has_many, :has_and_belongs_to_many
|
46
|
-
|
57
|
+
fk = association_reflection.options[:foreign_key] || self.class.to_s.underscore
|
58
|
+
self.send(association).collect do |obj|
|
59
|
+
tmp = obj.clone(opts)
|
60
|
+
tmp.send("#{fk}=", kopy)
|
61
|
+
tmp
|
62
|
+
end
|
47
63
|
end
|
48
64
|
kopy.send("#{association}=", cloned_object)
|
49
65
|
end
|
data/test/test_deep_cloneable.rb
CHANGED
@@ -68,4 +68,12 @@ class TestDeepCloneable < Test::Unit::TestCase
|
|
68
68
|
assert clone.save
|
69
69
|
assert_not_equal clone.parrot, @jack.parrot
|
70
70
|
end
|
71
|
+
|
72
|
+
def test_should_pass_nested_exceptions
|
73
|
+
clone = @jack.clone(:include => :parrot, :except => [:name, { :parrot => [:name] }])
|
74
|
+
assert clone.save
|
75
|
+
assert_not_equal clone.parrot, @jack.parrot
|
76
|
+
assert_not_nil @jack.parrot.name
|
77
|
+
assert_nil clone.parrot.name
|
78
|
+
end
|
71
79
|
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:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.0
|
10
|
+
version: 1.1.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: 2010-10-
|
18
|
+
date: 2010-10-19 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|