deep_dup 0.0.1 → 0.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d00f8bfe1ee27f10defaf6f00fd1da009bac911
4
- data.tar.gz: 8f6c8f10cd798bf95e47df1bd5798caaee00d696
3
+ metadata.gz: ceac246a3817ea4e391592dbd51e7e56548d7eca
4
+ data.tar.gz: 41519b1a8812200f74a25706452c1155d9b1a8f5
5
5
  SHA512:
6
- metadata.gz: 2f090c0109e6ab2fe5b7c2d5570de9aeed3cb0470b72e0584d3e9b000fc23c733a325efe3ce4f14dd82e448869bdbfc518d10db3c7eb9e2c1248a5a13410efc7
7
- data.tar.gz: 9e73b27787434ee36d1504f0d8f1c49b317f6fd1ff87c8d1d53fce14f38b19f35403e59f90d16aad11a6e25ba8b035db70b2ecb6ed77839118932e7c3aa5408f
6
+ metadata.gz: 4b10b7fd154bf2490d69cb5944d1acf6f6865cf3c8fc4b9e4ed2c2ffd79ccab35c29e0d425fe55d11315450bc3088068f56294f0ea0b602b99256a986e40f0e7
7
+ data.tar.gz: a3bdef85413b1d39034d7e7c46e5b7e7c8086a7a112bbebc14cbc734aad9f691fdd65b513faff93bc1d7129ebd33aed6c97aa8479c9da523153caa9cf8130bfb
data/README.md CHANGED
@@ -13,6 +13,10 @@ dupped = DeepDup.deep_dup('chunky')
13
13
  dupped = DeepDup.deep_dup(['chunky', [:bacon, { hi: 5 }]])
14
14
  dupped = DeepDup.deep_dup(['a', :a, 1, { bacon: { chunky: 'yeah' } }])
15
15
  dupped = DeepDup.deep_dup(SomeClass.new)
16
+
17
+ array = [1, 2]
18
+ array << array
19
+ dupped = DeepDup.deep_dup(array)
16
20
  ```
17
21
 
18
22
  With monkey patching
@@ -24,6 +28,10 @@ dupped = 'chunky'.deep_dup
24
28
  dupped = ['chunky', [:bacon, { hi: 5 }]].deep_dup
25
29
  dupped = ['a', :a, 1, { bacon: { chunky: 'yeah' } }].deep_dup
26
30
  dupped = SomeClass.new.deep_dup
31
+
32
+ array = [1, 2]
33
+ array << array
34
+ dupped = array.deep_dup
27
35
  ```
28
36
  ## Installation
29
37
 
@@ -54,3 +62,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/ollie/
54
62
  ## License
55
63
 
56
64
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
65
+
66
+ ## Credits
67
+
68
+ Thanks [Ice Nine](https://github.com/dkubb/ice_nine) and [Rails](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/object/duplicable.rb) for inspiration.
@@ -10,6 +10,10 @@ require 'deep_dup/version'
10
10
  # dupped = DeepDup.deep_dup(['a', :a, 1, { bacon: { chunky: 'yeah' } }])
11
11
  # dupped = DeepDup.deep_dup(SomeClass.new)
12
12
  #
13
+ # array = [1, 2]
14
+ # array << array
15
+ # dupped = DeepDup.deep_dup(array)
16
+ #
13
17
  # @example With monkey patching
14
18
  # require 'deep_dup/core_ext/object'
15
19
  #
@@ -17,6 +21,10 @@ require 'deep_dup/version'
17
21
  # dupped = ['chunky', [:bacon, { hi: 5 }]].deep_dup
18
22
  # dupped = ['a', :a, 1, { bacon: { chunky: 'yeah' } }].deep_dup
19
23
  # dupped = SomeClass.new.deep_dup
24
+ #
25
+ # array = [1, 2]
26
+ # array << array
27
+ # dupped = array.deep_dup
20
28
  module DeepDup
21
29
  # Deep duplicate any object.
22
30
  #
@@ -26,23 +34,67 @@ module DeepDup
26
34
  # dupped = DeepDup.deep_dup(['a', :a, 1, { bacon: { chunky: 'yeah' } }])
27
35
  # dupped = DeepDup.deep_dup(SomeClass.new)
28
36
  #
37
+ # array = [1, 2]
38
+ # array << array
39
+ # dupped = DeepDup.deep_dup(array)
40
+ #
29
41
  # @param object [Object] Pretty much anything.
42
+ # @param cache [Hash] Cache +object_id+s to prevent stack overflow on
43
+ # recursive data structures.
30
44
  #
31
45
  # @return [Object] Dupped object if possible.
32
- def self.deep_dup(object) # rubocop:disable Metrics/MethodLength
46
+ def self.deep_dup(object, cache = {}) # rubocop:disable Metrics/MethodLength
33
47
  case object
34
48
  when String
35
49
  object.dup
36
50
  when nil, false, true, Numeric, Symbol, Method
37
51
  object
38
52
  when Array
39
- object.map { |item| deep_dup(item) }
53
+ cache_object(object, [], cache) do |new_object|
54
+ object.each do |item|
55
+ new_object << deep_dup(item, cache)
56
+ end
57
+ end
40
58
  when Hash
41
- object.each.with_object({}) do |(key, value), hash|
42
- hash[deep_dup(key)] = deep_dup(value)
59
+ cache_object(object, {}, cache) do |new_object|
60
+ object.each do |key, value|
61
+ new_object[deep_dup(key, cache)] = deep_dup(value, cache)
62
+ end
43
63
  end
44
64
  else # Object, Class
45
65
  object.dup
46
66
  end
47
67
  end
68
+
69
+ # Prevent infinite recursion on recursive data structures.
70
+ #
71
+ # Imagine an array that has only one item which is a reference to itself.
72
+ # When entering this method, the cache is empty so we create a new array
73
+ # and map the original object's id to this newly created object.
74
+ #
75
+ # We then give control back to +deep_dup+ so that it can go on and do the
76
+ # adding, which will call itself with the same array and enter this method
77
+ # again.
78
+ #
79
+ # But this time, since the object is the same, we know the duplicate object
80
+ # because we stored in in our little cache. So just go ahead and return it
81
+ # otherwise it would result in an infinite recursion.
82
+ #
83
+ # @param object [Array, Hash] Original object reference.
84
+ # @param new_object [Array, Hash] The dupped object reference.
85
+ # @param cache [Hash] Map from original object_id to dupped object.
86
+ #
87
+ # @yieldparam new_object [Array, Hash] The dupped object reference.
88
+ #
89
+ # @return [Array, Hash] The dupped object.
90
+ def self.cache_object(object, new_object, cache)
91
+ object_id = object.object_id
92
+ dupped_object = cache[object_id] # Did we already visit this object?
93
+
94
+ return dupped_object if dupped_object # Yes, return it, prevent overflow.
95
+
96
+ cache[object_id] = new_object # Map the original object id to the new object.
97
+ yield(new_object) # Let +deep_dup+ do the job.
98
+ new_object # Just return it to +deep_dup+.
99
+ end
48
100
  end
@@ -13,6 +13,10 @@ module DeepDup
13
13
  # dupped = ['a', :a, 1, { bacon: { chunky: 'yeah' } }].deep_dup
14
14
  # dupped = SomeClass.new.deep_dup
15
15
  #
16
+ # array = [1, 2]
17
+ # array << array
18
+ # dupped = array.deep_dup
19
+ #
16
20
  # @return [Object] Dupped object if possible.
17
21
  def deep_dup
18
22
  DeepDup.deep_dup(self)
@@ -1,4 +1,4 @@
1
1
  module DeepDup
2
2
  # Version number, happy now?
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.2'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deep_dup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oldrich Vetesnik