deep_cloneable 1.0.0 → 1.1.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.
@@ -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