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.
@@ -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.0.0
1
+ 1.1.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.0.0"
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-18}
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 = [
@@ -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
- # pirate.clone :include => :mateys
16
- #
10
+ # pirate.clone :include => :mateys
11
+ #
17
12
  # ==== Cloning multiple associations
18
- # pirate.clone :include => [:mateys, :treasures]
19
- #
13
+ # pirate.clone :include => [:mateys, :treasures]
14
+ #
20
15
  # ==== Cloning really deep
21
- # pirate.clone :include => {:treasures => :gold_pieces}
22
- #
16
+ # pirate.clone :include => {:treasures => :gold_pieces}
17
+ #
23
18
  # ==== Cloning really deep with multiple associations
24
- # pirate.clone :include => [:mateys, {:treasures => :gold_pieces}]
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
- Array(options[:except]).each do |attribute|
31
- kopy.send(:write_attribute, attribute, attributes_from_column_definition[attribute.to_s])
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
- cloned_object = case self.class.reflect_on_association(association).macro
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
- self.send(association).collect { |obj| obj.clone(opts) }
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
@@ -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: 23
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 0
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 00:00:00 +02:00
18
+ date: 2010-10-19 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21