full_clone 0.0.1
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 +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +47 -0
- data/Rakefile +13 -0
- data/deep_clone.gemspec +25 -0
- data/lib/full_clone/array.rb +21 -0
- data/lib/full_clone/hash.rb +21 -0
- data/lib/full_clone/object.rb +26 -0
- data/lib/full_clone/struct.rb +21 -0
- data/lib/full_clone/version.rb +3 -0
- data/lib/full_clone.rb +35 -0
- data/test/array_tests.rb +83 -0
- data/test/deep_clone_tests.rb +43 -0
- data/test/hash_tests.rb +83 -0
- data/test/object_tests.rb +93 -0
- data/test/struct_tests.rb +85 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MWI0NTg2ZTJkZTk0NTRmYzFiNTY1OGI1MGY2ODM3YjMyODRmNTFmNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MmExOWRiMTNkMGY0ZmUzMDYzOTk3NTgxOTQ5MzNkZmVhYjhhNmI0ZA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NTc0MGJlNWYyYmZkZWZmMjRiMDFkMTMyYjVjNjk4YTAxOTdhNzQ2Y2M2ZWE3
|
10
|
+
Zjc2MmQyYjhhMDExYWVjYzkyOWNiZTk4Y2FkZTRhY2NhZjRmMTM4OGI5ZThj
|
11
|
+
YjYyOGM3YTRlNDQ3YmYxMmQyZDIyNWE0ZGViOWVkNWM3MzcwNDM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODQ2NTdhN2FlNGIzMDk5MzczNzkzNjU4NDFjOTA1OTcyZTVmNDY5NmI3OWM3
|
14
|
+
ODk4OTIxOTIzYTlhZTRjMWZkNGVhMjAwNTFiZWY4YWQyZDM1MDQ5ZmE4YzY3
|
15
|
+
M2Y5YjIyZWJmYTc1ZGRiMDg3NmYzZTMzZWUwNDc4OTFiYjhhOGY=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Peter Camilleri
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# DeepClone
|
2
|
+
|
3
|
+
The standard clone method creates a fresh instance of most (non-scalar) objects
|
4
|
+
but does not clone internal state. This internal state remains aliased in the
|
5
|
+
cloned copy. The full_clone method digs deep and makes copies of these internal
|
6
|
+
variables. It also allows classes to specify an exclusion list of variable that
|
7
|
+
are not to be processed.
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'full_clone'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install full_clone
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
require 'full_clone'
|
24
|
+
|
25
|
+
then, in those places where regular clone was problematic, use:
|
26
|
+
|
27
|
+
foo = my_object.full_clone
|
28
|
+
|
29
|
+
instead of
|
30
|
+
|
31
|
+
foo = my_object.clone
|
32
|
+
|
33
|
+
To exclude some instance variables from the deep cloning process, define a
|
34
|
+
full_clone_exclude method in the required class:
|
35
|
+
|
36
|
+
def full_clone_exclude
|
37
|
+
[:@bad_var1, :@bad_var2, :@bad_var_etc]
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
## Contributing
|
42
|
+
|
43
|
+
1. Fork it
|
44
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
45
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
46
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
47
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
#Run the unit test suite.
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
#List out all the test files.
|
7
|
+
t.test_files = ["test/deep_clone_tests.rb",
|
8
|
+
"test/object_tests.rb",
|
9
|
+
"test/array_tests.rb",
|
10
|
+
"test/hash_tests.rb",
|
11
|
+
"test/struct_tests.rb"]
|
12
|
+
t.verbose = false
|
13
|
+
end
|
data/deep_clone.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'full_clone/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "full_clone"
|
8
|
+
spec.version = DeepClone::VERSION
|
9
|
+
spec.authors = ["Peter Camilleri"]
|
10
|
+
spec.email = ["peter.c.camilleri@gmail.com"]
|
11
|
+
spec.description = "A (safe/no exceptions) clone variant that performs a deep, recursive copy."
|
12
|
+
spec.summary = "A clone variant that performs a deep copy."
|
13
|
+
spec.homepage = "http://teuthida-technologies.com/"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
# spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency 'minitest'
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Array
|
2
|
+
|
3
|
+
#The full_clone method for arrays.
|
4
|
+
def full_clone(progress={})
|
5
|
+
progress[object_id] = result = clone
|
6
|
+
exclude = full_clone_exclude
|
7
|
+
|
8
|
+
each_index.each do |name|
|
9
|
+
|
10
|
+
unless exclude.include?(name)
|
11
|
+
value = result[name]
|
12
|
+
value = progress[value.object_id] || value.full_clone(progress)
|
13
|
+
result[name] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
#The full_clone method for structs.
|
4
|
+
def full_clone(progress={})
|
5
|
+
progress[object_id] = result = clone
|
6
|
+
exclude = full_clone_exclude
|
7
|
+
|
8
|
+
each_key do |name|
|
9
|
+
|
10
|
+
unless exclude.include?(name)
|
11
|
+
value = result[name]
|
12
|
+
value = progress[value.object_id] || value.full_clone(progress)
|
13
|
+
result[name] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
#By default, no instance variables are excluded.
|
4
|
+
def full_clone_exclude
|
5
|
+
[]
|
6
|
+
end
|
7
|
+
|
8
|
+
#The full_clone method for most objects.
|
9
|
+
def full_clone(progress={})
|
10
|
+
progress[object_id] = result = clone
|
11
|
+
exclude = full_clone_exclude
|
12
|
+
|
13
|
+
instance_variables.each do |name|
|
14
|
+
|
15
|
+
unless exclude.include?(name)
|
16
|
+
value = result.instance_variable_get(name)
|
17
|
+
value = progress[value.object_id] || value.full_clone(progress)
|
18
|
+
result.instance_variable_set(name, value)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Struct
|
2
|
+
|
3
|
+
#The full_clone method for structs.
|
4
|
+
def full_clone(progress={})
|
5
|
+
progress[object_id] = result = clone
|
6
|
+
exclude = full_clone_exclude
|
7
|
+
|
8
|
+
members.each do |name|
|
9
|
+
|
10
|
+
unless exclude.include?(name)
|
11
|
+
value = result[name]
|
12
|
+
value = progress[value.object_id] || value.full_clone(progress)
|
13
|
+
result[name] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/full_clone.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'full_clone/version'
|
2
|
+
require_relative 'full_clone/object'
|
3
|
+
require_relative 'full_clone/array'
|
4
|
+
require_relative 'full_clone/hash'
|
5
|
+
require_relative 'full_clone/struct'
|
6
|
+
|
7
|
+
module DeepClone
|
8
|
+
def full_clone(_progress={})
|
9
|
+
self
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Numeric
|
14
|
+
include DeepClone
|
15
|
+
end
|
16
|
+
|
17
|
+
class NilClass
|
18
|
+
include DeepClone
|
19
|
+
end
|
20
|
+
|
21
|
+
class TrueClass
|
22
|
+
include DeepClone
|
23
|
+
end
|
24
|
+
|
25
|
+
class FalseClass
|
26
|
+
include DeepClone
|
27
|
+
end
|
28
|
+
|
29
|
+
class Symbol
|
30
|
+
include DeepClone
|
31
|
+
end
|
32
|
+
|
33
|
+
class Regexp
|
34
|
+
include DeepClone
|
35
|
+
end
|
data/test/array_tests.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative '../lib/full_clone'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
#Test the monkey patches applied to the Object class.
|
7
|
+
class ArrayDeepCloneTester < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
#Special initialize to track rake progress.
|
10
|
+
def initialize(*all)
|
11
|
+
$do_this_only_one_time = "" unless defined? $do_this_only_one_time
|
12
|
+
|
13
|
+
if $do_this_only_one_time != __FILE__
|
14
|
+
puts
|
15
|
+
puts "Running test file: #{File.split(__FILE__)[1]}"
|
16
|
+
$do_this_only_one_time = __FILE__
|
17
|
+
end
|
18
|
+
|
19
|
+
super(*all)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_basic_deep_cloning
|
23
|
+
sa = "North"
|
24
|
+
simple1 = [sa, 5, nil]
|
25
|
+
simple2 = simple1.full_clone
|
26
|
+
|
27
|
+
assert_equal(simple1[0], simple2[0])
|
28
|
+
assert_equal(simple1[1], 5)
|
29
|
+
assert_equal(simple1[2], nil)
|
30
|
+
refute_equal(simple1[0].object_id, simple2[0].object_id)
|
31
|
+
|
32
|
+
sa << "West"
|
33
|
+
|
34
|
+
assert_equal(sa, "NorthWest")
|
35
|
+
assert_equal(simple1[0], "NorthWest")
|
36
|
+
assert_equal(simple2[0], "North")
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_with_exclusion
|
40
|
+
sa = "North"
|
41
|
+
simple1 = [sa, 5, nil]
|
42
|
+
simple1.define_singleton_method(:full_clone_exclude) {[0]}
|
43
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
44
|
+
simple2 = simple1.full_clone
|
45
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
46
|
+
|
47
|
+
assert_equal(simple1[0], simple2[0])
|
48
|
+
assert_equal(simple1[1], 5)
|
49
|
+
assert_equal(simple1[2], nil)
|
50
|
+
assert_equal(simple1[0].object_id, simple2[0].object_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_with_direct_looping
|
54
|
+
simple1 = ['East', 5, nil]
|
55
|
+
simple1[2] = simple1
|
56
|
+
simple2 = simple1.full_clone
|
57
|
+
|
58
|
+
assert_equal(simple2.object_id, simple2[2].object_id)
|
59
|
+
refute_equal(simple1.object_id, simple2[2].object_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_with_direct_looping_and_exclusion
|
63
|
+
simple1 = ['East', 5, nil]
|
64
|
+
simple1.define_singleton_method(:full_clone_exclude) {[2]}
|
65
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
66
|
+
simple1[2] = simple1
|
67
|
+
simple2 = simple1.full_clone
|
68
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
69
|
+
|
70
|
+
refute_equal(simple2.object_id, simple2[2].object_id)
|
71
|
+
assert_equal(simple1.object_id, simple2[2].object_id)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_with_indirect_looping
|
75
|
+
simple1 = ['East', 5, nil]
|
76
|
+
simple3 = ['West', 6, simple1]
|
77
|
+
simple1[2] = simple3
|
78
|
+
simple2 = simple1.full_clone
|
79
|
+
|
80
|
+
assert_equal(simple2.object_id, simple2[2][2].object_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative '../lib/full_clone'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
#Test the monkey patches applied to the Object class.
|
7
|
+
class DeepCloneTester < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
#Special initialize to track rake progress.
|
10
|
+
def initialize(*all)
|
11
|
+
$do_this_only_one_time = "" unless defined? $do_this_only_one_time
|
12
|
+
|
13
|
+
if $do_this_only_one_time != __FILE__
|
14
|
+
puts
|
15
|
+
puts "Running test file: #{File.split(__FILE__)[1]}"
|
16
|
+
$do_this_only_one_time = __FILE__
|
17
|
+
end
|
18
|
+
|
19
|
+
super(*all)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_for_safe_value_cloning
|
23
|
+
assert_equal((6).full_clone, 6)
|
24
|
+
assert_equal((6).full_clone.object_id, (6).object_id)
|
25
|
+
|
26
|
+
assert_equal((:foo).full_clone, :foo)
|
27
|
+
assert_equal((:foo).full_clone.object_id, (:foo).object_id)
|
28
|
+
|
29
|
+
assert_equal((true).full_clone, true)
|
30
|
+
assert_equal((true).full_clone.object_id, (true).object_id)
|
31
|
+
|
32
|
+
assert_equal((false).full_clone, false)
|
33
|
+
assert_equal((false).full_clone.object_id, (false).object_id)
|
34
|
+
|
35
|
+
assert_equal((nil).full_clone, nil)
|
36
|
+
assert_equal((nil).full_clone.object_id, (nil).object_id)
|
37
|
+
|
38
|
+
rex = /ABC/
|
39
|
+
assert_equal(rex.full_clone, rex)
|
40
|
+
assert_equal(rex.full_clone.object_id, rex.object_id)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/test/hash_tests.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative '../lib/full_clone'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
#Test the monkey patches applied to the Object class.
|
7
|
+
class HashDeepCloneTester < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
#Special initialize to track rake progress.
|
10
|
+
def initialize(*all)
|
11
|
+
$do_this_only_one_time = "" unless defined? $do_this_only_one_time
|
12
|
+
|
13
|
+
if $do_this_only_one_time != __FILE__
|
14
|
+
puts
|
15
|
+
puts "Running test file: #{File.split(__FILE__)[1]}"
|
16
|
+
$do_this_only_one_time = __FILE__
|
17
|
+
end
|
18
|
+
|
19
|
+
super(*all)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_basic_deep_cloning
|
23
|
+
sa = "North"
|
24
|
+
simple1 = {iva: sa, ivb: 5, ivc: nil}
|
25
|
+
simple2 = simple1.full_clone
|
26
|
+
|
27
|
+
assert_equal(simple1[:iva], simple2[:iva])
|
28
|
+
assert_equal(simple1[:ivb], 5)
|
29
|
+
assert_equal(simple1[:ivc], nil)
|
30
|
+
refute_equal(simple1[:iva].object_id, simple2[:iva].object_id)
|
31
|
+
|
32
|
+
sa << "West"
|
33
|
+
|
34
|
+
assert_equal(sa, "NorthWest")
|
35
|
+
assert_equal(simple1[:iva], "NorthWest")
|
36
|
+
assert_equal(simple2[:iva], "North")
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_with_exclusion
|
40
|
+
sa = "North"
|
41
|
+
simple1 = {iva: sa, ivb: 5, ivc: nil}
|
42
|
+
simple1.define_singleton_method(:full_clone_exclude) {[:iva]}
|
43
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
44
|
+
simple2 = simple1.full_clone
|
45
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
46
|
+
|
47
|
+
assert_equal(simple1[:iva], simple2[:iva])
|
48
|
+
assert_equal(simple1[:ivb], 5)
|
49
|
+
assert_equal(simple1[:ivc], nil)
|
50
|
+
assert_equal(simple1[:iva].object_id, simple2[:iva].object_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_with_direct_looping
|
54
|
+
simple1 = {iva: 'East', ivb: 5, ivc: nil}
|
55
|
+
simple1[:ivc] = simple1
|
56
|
+
simple2 = simple1.full_clone
|
57
|
+
|
58
|
+
assert_equal(simple2.object_id, simple2[:ivc].object_id)
|
59
|
+
refute_equal(simple1.object_id, simple2[:ivc].object_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_with_direct_looping_and_exclusion
|
63
|
+
simple1 = {iva: 'East', ivb: 5, ivc: nil}
|
64
|
+
simple1.define_singleton_method(:full_clone_exclude) {[:ivc]}
|
65
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
66
|
+
simple1[:ivc] = simple1
|
67
|
+
simple2 = simple1.full_clone
|
68
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
69
|
+
|
70
|
+
refute_equal(simple2.object_id, simple2[:ivc].object_id)
|
71
|
+
assert_equal(simple1.object_id, simple2[:ivc].object_id)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_with_indirect_looping
|
75
|
+
simple1 = {iva: 'East', ivb: 5, ivc: nil}
|
76
|
+
simple3 = {iva: 'West', ivb: 6, ivc: simple1}
|
77
|
+
simple1[:ivc] = simple3
|
78
|
+
simple2 = simple1.full_clone
|
79
|
+
|
80
|
+
assert_equal(simple2.object_id, simple2[:ivc][:ivc].object_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative '../lib/full_clone'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
#Test the monkey patches applied to the Object class.
|
7
|
+
class ObjectDeepCloneTester < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
class SimpleClass
|
10
|
+
attr_accessor :iva
|
11
|
+
attr_accessor :ivb
|
12
|
+
attr_accessor :ivc
|
13
|
+
|
14
|
+
def initialize(iva, ivb, ivc)
|
15
|
+
@iva, @ivb, @ivc = iva, ivb, ivc
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#Special initialize to track rake progress.
|
20
|
+
def initialize(*all)
|
21
|
+
$do_this_only_one_time = "" unless defined? $do_this_only_one_time
|
22
|
+
|
23
|
+
if $do_this_only_one_time != __FILE__
|
24
|
+
puts
|
25
|
+
puts "Running test file: #{File.split(__FILE__)[1]}"
|
26
|
+
$do_this_only_one_time = __FILE__
|
27
|
+
end
|
28
|
+
|
29
|
+
super(*all)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_basic_deep_cloning
|
33
|
+
sa = "North"
|
34
|
+
simple1 = SimpleClass.new(sa, 5, nil)
|
35
|
+
simple2 = simple1.full_clone
|
36
|
+
|
37
|
+
assert_equal(simple1.iva, simple2.iva)
|
38
|
+
assert_equal(simple1.ivb, 5)
|
39
|
+
assert_equal(simple1.ivc, nil)
|
40
|
+
refute_equal(simple1.iva.object_id, simple2.iva.object_id)
|
41
|
+
|
42
|
+
sa << "West"
|
43
|
+
|
44
|
+
assert_equal(sa, "NorthWest")
|
45
|
+
assert_equal(simple1.iva, "NorthWest")
|
46
|
+
assert_equal(simple2.iva, "North")
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_with_exclusion
|
50
|
+
sa = "North"
|
51
|
+
simple1 = SimpleClass.new(sa, 5, nil)
|
52
|
+
simple1.define_singleton_method(:full_clone_exclude) {[:@iva]}
|
53
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
54
|
+
simple2 = simple1.full_clone
|
55
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
56
|
+
|
57
|
+
assert_equal(simple1.iva, simple2.iva)
|
58
|
+
assert_equal(simple1.ivb, 5)
|
59
|
+
assert_equal(simple1.ivc, nil)
|
60
|
+
assert_equal(simple1.iva.object_id, simple2.iva.object_id)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_with_direct_looping
|
64
|
+
simple1 = SimpleClass.new('East', 5, nil)
|
65
|
+
simple1.ivc = simple1
|
66
|
+
simple2 = simple1.full_clone
|
67
|
+
|
68
|
+
assert_equal(simple2.object_id, simple2.ivc.object_id)
|
69
|
+
refute_equal(simple1.object_id, simple2.ivc.object_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_with_direct_looping_and_exclusion
|
73
|
+
simple1 = SimpleClass.new('East', 5, nil)
|
74
|
+
simple1.define_singleton_method(:full_clone_exclude) {[:@ivc]}
|
75
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
76
|
+
simple1.ivc = simple1
|
77
|
+
simple2 = simple1.full_clone
|
78
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
79
|
+
|
80
|
+
refute_equal(simple2.object_id, simple2.ivc.object_id)
|
81
|
+
assert_equal(simple1.object_id, simple2.ivc.object_id)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_with_indirect_looping
|
85
|
+
simple1 = SimpleClass.new('East', 5, nil)
|
86
|
+
simple3 = SimpleClass.new('West', 6, simple1)
|
87
|
+
simple1.ivc = simple3
|
88
|
+
simple2 = simple1.full_clone
|
89
|
+
|
90
|
+
assert_equal(simple2.object_id, simple2.ivc.ivc.object_id)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative '../lib/full_clone'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
#Test the monkey patches applied to the Object class.
|
7
|
+
class StructDeepCloneTester < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
SimpleStruct = Struct.new(:iva, :ivb, :ivc)
|
10
|
+
|
11
|
+
#Special initialize to track rake progress.
|
12
|
+
def initialize(*all)
|
13
|
+
$do_this_only_one_time = "" unless defined? $do_this_only_one_time
|
14
|
+
|
15
|
+
if $do_this_only_one_time != __FILE__
|
16
|
+
puts
|
17
|
+
puts "Running test file: #{File.split(__FILE__)[1]}"
|
18
|
+
$do_this_only_one_time = __FILE__
|
19
|
+
end
|
20
|
+
|
21
|
+
super(*all)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_basic_deep_cloning
|
25
|
+
sa = "North"
|
26
|
+
simple1 = SimpleStruct.new(sa, 5, nil)
|
27
|
+
simple2 = simple1.full_clone
|
28
|
+
|
29
|
+
assert_equal(simple1.iva, simple2.iva)
|
30
|
+
assert_equal(simple1.ivb, 5)
|
31
|
+
assert_equal(simple1.ivc, nil)
|
32
|
+
refute_equal(simple1.iva.object_id, simple2.iva.object_id)
|
33
|
+
|
34
|
+
sa << "West"
|
35
|
+
|
36
|
+
assert_equal(sa, "NorthWest")
|
37
|
+
assert_equal(simple1.iva, "NorthWest")
|
38
|
+
assert_equal(simple2.iva, "North")
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_with_exclusion
|
42
|
+
sa = "North"
|
43
|
+
simple1 = SimpleStruct.new(sa, 5, nil)
|
44
|
+
simple1.define_singleton_method(:full_clone_exclude) {[:iva]}
|
45
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
46
|
+
simple2 = simple1.full_clone
|
47
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
48
|
+
|
49
|
+
assert_equal(simple1.iva, simple2.iva)
|
50
|
+
assert_equal(simple1.ivb, 5)
|
51
|
+
assert_equal(simple1.ivc, nil)
|
52
|
+
assert_equal(simple1.iva.object_id, simple2.iva.object_id)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_with_direct_looping
|
56
|
+
simple1 = SimpleStruct.new('East', 5, nil)
|
57
|
+
simple1.ivc = simple1
|
58
|
+
simple2 = simple1.full_clone
|
59
|
+
|
60
|
+
assert_equal(simple2.object_id, simple2.ivc.object_id)
|
61
|
+
refute_equal(simple1.object_id, simple2.ivc.object_id)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_with_direct_looping_and_exclusion
|
65
|
+
simple1 = SimpleStruct.new('East', 5, nil)
|
66
|
+
simple1.define_singleton_method(:full_clone_exclude) {[:ivc]}
|
67
|
+
assert_equal(simple1.singleton_methods, [:full_clone_exclude])
|
68
|
+
simple1.ivc = simple1
|
69
|
+
simple2 = simple1.full_clone
|
70
|
+
assert_equal(simple2.singleton_methods, [:full_clone_exclude])
|
71
|
+
|
72
|
+
refute_equal(simple2.object_id, simple2.ivc.object_id)
|
73
|
+
assert_equal(simple1.object_id, simple2.ivc.object_id)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_with_indirect_looping
|
77
|
+
simple1 = SimpleStruct.new('East', 5, nil)
|
78
|
+
simple3 = SimpleStruct.new('West', 6, simple1)
|
79
|
+
simple1.ivc = simple3
|
80
|
+
simple2 = simple1.full_clone
|
81
|
+
|
82
|
+
assert_equal(simple2.object_id, simple2.ivc.ivc.object_id)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: full_clone
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Peter Camilleri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A (safe/no exceptions) clone variant that performs a deep, recursive
|
56
|
+
copy.
|
57
|
+
email:
|
58
|
+
- peter.c.camilleri@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- deep_clone.gemspec
|
69
|
+
- lib/full_clone.rb
|
70
|
+
- lib/full_clone/array.rb
|
71
|
+
- lib/full_clone/hash.rb
|
72
|
+
- lib/full_clone/object.rb
|
73
|
+
- lib/full_clone/struct.rb
|
74
|
+
- lib/full_clone/version.rb
|
75
|
+
- test/array_tests.rb
|
76
|
+
- test/deep_clone_tests.rb
|
77
|
+
- test/hash_tests.rb
|
78
|
+
- test/object_tests.rb
|
79
|
+
- test/struct_tests.rb
|
80
|
+
homepage: http://teuthida-technologies.com/
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.1.4
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: A clone variant that performs a deep copy.
|
104
|
+
test_files:
|
105
|
+
- test/array_tests.rb
|
106
|
+
- test/deep_clone_tests.rb
|
107
|
+
- test/hash_tests.rb
|
108
|
+
- test/object_tests.rb
|
109
|
+
- test/struct_tests.rb
|
110
|
+
has_rdoc:
|