init_copy 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/.rdoc_options +28 -0
- data/Gemfile +10 -1
- data/LICENSE.txt +1 -1
- data/README.md +162 -0
- data/Rakefile +9 -33
- data/init_copy.gemspec +31 -39
- data/lib/init_copy.rb +58 -106
- data/test/init_copy_test.rb +242 -0
- metadata +27 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1620d2aa498e981be870fd3e0d671595b0407e557b54e40cf7e32b38b95158a8
|
4
|
+
data.tar.gz: 1b08062be47d208e59ed5a70e548f726d55936ccc000a84bbda5b2ed47119360
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 17b1bc267564f9f49c5b699581f522690bc13a63addbab7708bbb6af227970f3701c0f259d00d0d42b4c898e5b349324672b416395d5d0d34be151cf48994db0
|
7
|
+
data.tar.gz: e2973b90f3bd28a061904a1db08435b2f2a5af11c2a7bc4d14ce1a40bfbc7837099b0c8c786ea39b064714b041d87994420890ff6f6ae30afb621dac6f31d89b
|
data/.rdoc_options
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
---
|
2
|
+
charset: UTF-8
|
3
|
+
encoding: UTF-8
|
4
|
+
|
5
|
+
op_dir: doc
|
6
|
+
title: InitCopy
|
7
|
+
main_page: README.md
|
8
|
+
|
9
|
+
apply_default_exclude: true
|
10
|
+
embed_mixins: true
|
11
|
+
force_update: true
|
12
|
+
hyperlink_all: true
|
13
|
+
line_numbers: true
|
14
|
+
show_hash: true
|
15
|
+
skip_tests: true
|
16
|
+
|
17
|
+
exclude:
|
18
|
+
- /.git/
|
19
|
+
- /.github/
|
20
|
+
- /.idea/
|
21
|
+
- /doc/
|
22
|
+
- /pkg/
|
23
|
+
- /spec/
|
24
|
+
- /stock/
|
25
|
+
- /test/
|
26
|
+
- Gemfile
|
27
|
+
- Gemfile.lock
|
28
|
+
- Rakefile
|
data/Gemfile
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
4
|
source 'https://rubygems.org'
|
6
5
|
|
7
6
|
gemspec
|
7
|
+
|
8
|
+
group :development,:test do
|
9
|
+
gem 'bundler' ,'~> 2.6'
|
10
|
+
gem 'rake' ,'~> 13.3'
|
11
|
+
gem 'rdoc' ,'~> 6.14'
|
12
|
+
end
|
13
|
+
|
14
|
+
group :test do
|
15
|
+
gem 'minitest' ,'~> 5.25'
|
16
|
+
end
|
data/LICENSE.txt
CHANGED
data/README.md
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
# InitCopy
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/init_copy)
|
4
|
+
[](https://github.com/esotericpig/init_copy/actions/workflows/ci.yml)
|
5
|
+
|
6
|
+
[](https://github.com/esotericpig/init_copy)
|
7
|
+
[](CHANGELOG.md)
|
8
|
+
[](LICENSE.txt)
|
9
|
+
|
10
|
+
🧬 Easily use the correct `clone` or `dup` method in `initialize_copy`.
|
11
|
+
|
12
|
+
If we only use either `clone` or `dup` or we use `Marshal`, then that does not produce the correct behavior according to the [standard documentation](https://docs.ruby-lang.org/en/master/Object.html#method-i-dup-label-on+dup+vs+clone). This is because `clone` should preserve the internal state (e.g., the frozen state and extended modules), while `dup` should not. For example:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
module SecretExt
|
16
|
+
def secret
|
17
|
+
'password'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
bob = 'Bob'
|
22
|
+
bob.extend(SecretExt)
|
23
|
+
bob.freeze
|
24
|
+
|
25
|
+
clone = bob.clone
|
26
|
+
dup = bob.dup
|
27
|
+
|
28
|
+
puts clone.frozen? #=> true
|
29
|
+
puts dup.frozen? #=> false
|
30
|
+
|
31
|
+
puts clone.secret #=> password
|
32
|
+
puts dup.secret #=> NoMethodError
|
33
|
+
```
|
34
|
+
|
35
|
+
To solve this issue in the past, we had to define both `initialize_clone` & `initialize_dup` and maintain two copies of all our deep-copy code. That sucks. 😞
|
36
|
+
|
37
|
+
🚀 Instead, *InitCopy* was created:
|
38
|
+
1. Install the gem `init_copy` ([RubyGems.org page](https://rubygems.org/gems/init_copy)).
|
39
|
+
2. Include `InitCopy` in your class/module.
|
40
|
+
3. Override the `init_copy(original)` method.
|
41
|
+
4. Use `ic_copy(var)`, instead of clone/dup.
|
42
|
+
|
43
|
+
Example usage:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
require 'init_copy'
|
47
|
+
|
48
|
+
class JangoFett
|
49
|
+
include InitCopy
|
50
|
+
|
51
|
+
attr_reader :gear,:order66
|
52
|
+
|
53
|
+
def initialize
|
54
|
+
super
|
55
|
+
|
56
|
+
@gear = ['blaster','jetpack']
|
57
|
+
|
58
|
+
@order66 = Class.new do
|
59
|
+
undef_method :clone
|
60
|
+
undef_method :dup
|
61
|
+
end.new
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
def init_copy(_orig)
|
67
|
+
super
|
68
|
+
|
69
|
+
@gear = ic_copy(@gear)
|
70
|
+
@order66 = ic_copy?(@order66) # Safe copy if no dup/clone.
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
jango = JangoFett.new
|
75
|
+
jango.freeze
|
76
|
+
|
77
|
+
boba1 = jango.clone
|
78
|
+
boba2 = jango.dup
|
79
|
+
|
80
|
+
jango.gear << 'vibroblade'
|
81
|
+
boba1.gear << 'implant'
|
82
|
+
|
83
|
+
puts jango.gear.inspect #=> ["blaster", "jetpack", "vibroblade"]
|
84
|
+
|
85
|
+
puts boba1.gear.inspect #=> ["blaster", "jetpack", "implant"]
|
86
|
+
puts boba2.gear.inspect #=> ["blaster", "jetpack"]
|
87
|
+
|
88
|
+
puts boba1.frozen? #=> true (clone)
|
89
|
+
puts boba2.frozen? #=> false (dup)
|
90
|
+
```
|
91
|
+
|
92
|
+
## // Contents
|
93
|
+
|
94
|
+
- [Setup](#-setup)
|
95
|
+
- [Hacking](#-hacking)
|
96
|
+
- [License](#-license)
|
97
|
+
|
98
|
+
## [//](#-contents) Setup
|
99
|
+
|
100
|
+
Pick your poison...
|
101
|
+
|
102
|
+
With the *RubyGems* CLI package manager:
|
103
|
+
|
104
|
+
```bash
|
105
|
+
gem install init_copy
|
106
|
+
```
|
107
|
+
|
108
|
+
In your *Gemspec*:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
spec.add_dependency 'init_copy', '~> X.X'
|
112
|
+
```
|
113
|
+
|
114
|
+
In your *Gemfile*:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
# Pick one...
|
118
|
+
gem 'init_copy', '~> X.X'
|
119
|
+
|
120
|
+
gem 'init_copy', git: 'https://github.com/esotericpig/init_copy.git', branch: 'main'
|
121
|
+
```
|
122
|
+
|
123
|
+
From source:
|
124
|
+
|
125
|
+
```bash
|
126
|
+
git clone 'https://github.com/esotericpig/init_copy.git'
|
127
|
+
cd init_copy
|
128
|
+
bundle install
|
129
|
+
bundle exec rake install:local
|
130
|
+
```
|
131
|
+
|
132
|
+
## [//](#-contents) Hacking
|
133
|
+
|
134
|
+
```bash
|
135
|
+
git clone 'https://github.com/esotericpig/init_copy.git'
|
136
|
+
cd init_copy
|
137
|
+
bundle install
|
138
|
+
bundle exec rake -T
|
139
|
+
```
|
140
|
+
|
141
|
+
Testing:
|
142
|
+
|
143
|
+
```bash
|
144
|
+
bundle exec rake test
|
145
|
+
```
|
146
|
+
|
147
|
+
Generating doc:
|
148
|
+
|
149
|
+
```bash
|
150
|
+
bundle exec rake clobber_doc doc
|
151
|
+
```
|
152
|
+
|
153
|
+
Installing:
|
154
|
+
|
155
|
+
```bash
|
156
|
+
bundle exec rake install:local
|
157
|
+
```
|
158
|
+
|
159
|
+
## [//](#-contents) License
|
160
|
+
|
161
|
+
Copyright (c) 2020-2025 Bradley Whited
|
162
|
+
[MIT License](LICENSE.txt)
|
data/Rakefile
CHANGED
@@ -1,51 +1,27 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
#--
|
5
|
-
# This file is part of InitCopy.
|
6
|
-
# Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
|
7
|
-
#
|
8
|
-
# InitCopy is free software: you can redistribute it and/or modify it under
|
9
|
-
# the terms of the MIT License.
|
10
|
-
#
|
11
|
-
# You should have received a copy of the MIT License along with InitCopy.
|
12
|
-
# If not, see <https://choosealicense.com/licenses/mit/>.
|
13
|
-
#++
|
14
|
-
|
15
|
-
|
16
4
|
require 'bundler/gem_tasks'
|
17
5
|
|
18
6
|
require 'init_copy'
|
19
7
|
require 'rake/clean'
|
20
8
|
require 'rake/testtask'
|
21
|
-
require '
|
22
|
-
|
9
|
+
require 'rdoc/task'
|
23
10
|
|
24
|
-
CLEAN.exclude('.git/','stock/')
|
11
|
+
CLEAN.exclude('.git/','.github/','.idea/','stock/')
|
25
12
|
CLOBBER.include('doc/')
|
26
13
|
|
14
|
+
task default: %i[test]
|
27
15
|
|
28
|
-
|
29
|
-
|
30
|
-
desc 'Generate doc (YARDoc)'
|
31
|
-
task :doc => [:yard] do |task|
|
32
|
-
end
|
33
|
-
|
34
|
-
Rake::TestTask.new() do |task|
|
16
|
+
Rake::TestTask.new do |task|
|
35
17
|
task.libs = ['lib','test']
|
36
|
-
task.pattern =
|
37
|
-
task.
|
18
|
+
task.pattern = 'test/**/*_test.rb'
|
19
|
+
task.options = '--pride'
|
38
20
|
task.verbose = false
|
39
21
|
task.warning = true
|
40
22
|
end
|
41
23
|
|
42
|
-
|
43
|
-
task.
|
44
|
-
|
45
|
-
task.options += ['--files','CHANGELOG.md,LICENSE.txt']
|
46
|
-
task.options += ['--readme','README.md']
|
47
|
-
|
48
|
-
task.options << '--protected' # Show protected methods
|
49
|
-
#task.options += ['--template-path',File.join('yard','templates')]
|
50
|
-
task.options += ['--title',"InitCopy v#{InitCopy::VERSION} Doc"]
|
24
|
+
RDoc::Task.new(:doc) do |task|
|
25
|
+
task.rdoc_dir = 'doc'
|
26
|
+
task.title = "InitCopy v#{InitCopy::VERSION}"
|
51
27
|
end
|
data/init_copy.gemspec
CHANGED
@@ -1,53 +1,45 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
# This file is part of InitCopy.
|
6
|
-
# Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
|
7
|
-
#
|
8
|
-
# InitCopy is free software: you can redistribute it and/or modify it under
|
9
|
-
# the terms of the MIT License.
|
10
|
-
#
|
11
|
-
# You should have received a copy of the MIT License along with InitCopy.
|
12
|
-
# If not, see <https://choosealicense.com/licenses/mit/>.
|
13
|
-
#++
|
4
|
+
require_relative 'lib/init_copy'
|
14
5
|
|
15
|
-
|
16
|
-
lib = File.expand_path(File.join('..','lib'),__FILE__)
|
17
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
18
|
-
|
19
|
-
require 'init_copy'
|
20
|
-
|
21
|
-
|
22
|
-
Gem::Specification.new() do |spec|
|
6
|
+
Gem::Specification.new do |spec|
|
23
7
|
spec.name = 'init_copy'
|
24
8
|
spec.version = InitCopy::VERSION
|
25
|
-
spec.authors = ['
|
26
|
-
spec.email = ['
|
9
|
+
spec.authors = ['Bradley Whited']
|
10
|
+
spec.email = ['code@esotericpig.com']
|
27
11
|
spec.licenses = ['MIT']
|
28
12
|
spec.homepage = 'https://github.com/esotericpig/init_copy'
|
29
|
-
spec.summary = 'Easily use the
|
13
|
+
spec.summary = 'Easily use the correct clone or dup method in initialize_copy.'
|
30
14
|
spec.description = spec.summary
|
31
|
-
|
15
|
+
|
32
16
|
spec.metadata = {
|
33
|
-
'
|
34
|
-
'
|
35
|
-
'
|
36
|
-
'
|
17
|
+
'rubygems_mfa_required' => 'true',
|
18
|
+
'homepage_uri' => 'https://github.com/esotericpig/init_copy',
|
19
|
+
'source_code_uri' => 'https://github.com/esotericpig/init_copy',
|
20
|
+
'bug_tracker_uri' => 'https://github.com/esotericpig/init_copy/issues',
|
21
|
+
'changelog_uri' => 'https://github.com/esotericpig/init_copy/blob/main/CHANGELOG.md',
|
37
22
|
}
|
38
|
-
|
39
|
-
spec.require_paths = ['lib']
|
40
|
-
|
41
|
-
spec.files = Dir.glob(File.join("{#{spec.require_paths.join(',')}}",'**','*.{rb}')) +
|
42
|
-
%W( Gemfile #{spec.name}.gemspec Rakefile ) +
|
43
|
-
%w( LICENSE.txt )
|
44
|
-
|
23
|
+
|
45
24
|
# Lowest version that isn't eol (end-of-life).
|
46
25
|
# - https://www.ruby-lang.org/en/downloads/branches/
|
47
|
-
spec.required_ruby_version = '>= 2
|
48
|
-
|
49
|
-
spec.
|
50
|
-
spec.
|
51
|
-
|
52
|
-
spec.
|
26
|
+
spec.required_ruby_version = '>= 3.2'
|
27
|
+
spec.require_paths = ['lib']
|
28
|
+
spec.bindir = 'bin'
|
29
|
+
spec.executables = []
|
30
|
+
|
31
|
+
spec.extra_rdoc_files = %w[LICENSE.txt README.md]
|
32
|
+
spec.rdoc_options = [
|
33
|
+
%w[--embed-mixins --hyperlink-all --line-numbers --show-hash],
|
34
|
+
'--main','README.md',
|
35
|
+
'--title',"InitCopy v#{InitCopy::VERSION}",
|
36
|
+
].flatten
|
37
|
+
|
38
|
+
spec.files = [
|
39
|
+
Dir.glob("{#{spec.require_paths.join(',')}}/**/*.{erb,rb}"),
|
40
|
+
Dir.glob("#{spec.bindir}/*"),
|
41
|
+
Dir.glob('{spec,test}/**/*.{erb,rb}'),
|
42
|
+
%W[Gemfile #{spec.name}.gemspec Rakefile .rdoc_options],
|
43
|
+
spec.extra_rdoc_files,
|
44
|
+
].flatten
|
53
45
|
end
|
data/lib/init_copy.rb
CHANGED
@@ -1,127 +1,79 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# encoding: UTF-8
|
3
2
|
# frozen_string_literal: true
|
4
3
|
|
5
4
|
#--
|
6
5
|
# This file is part of InitCopy.
|
7
|
-
# Copyright (c) 2020
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# the terms of the MIT License.
|
11
|
-
#
|
12
|
-
# You should have received a copy of the MIT License along with InitCopy.
|
13
|
-
# If not, see <https://choosealicense.com/licenses/mit/>.
|
6
|
+
# Copyright (c) 2020 Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: MIT
|
14
9
|
#++
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
#
|
20
|
-
|
11
|
+
# Example usage:
|
12
|
+
# require 'init_copy'
|
13
|
+
#
|
14
|
+
# class JangoFett
|
15
|
+
# include InitCopy
|
16
|
+
#
|
17
|
+
# protected
|
18
|
+
#
|
19
|
+
# def init_copy(_orig)
|
20
|
+
# super
|
21
|
+
#
|
22
|
+
# @gear = ic_copy(@gear)
|
23
|
+
# @order66 = ic_copy?(@order66) # Safe copy if no dup/clone.
|
24
|
+
# end
|
25
|
+
# end
|
21
26
|
module InitCopy
|
22
|
-
VERSION = '0.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
VERSION = '0.2.0'
|
28
|
+
|
29
|
+
def self.included(mod)
|
30
|
+
super
|
31
|
+
|
32
|
+
# NOTE: Can't use prepend(), else children's init_copy() won't call their parents', even with super().
|
33
|
+
mod.include(Copyable)
|
28
34
|
end
|
29
|
-
|
30
|
-
def self.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
if name.end_with?(%q(clone'))
|
35
|
-
copy_name = :clone
|
36
|
-
break
|
37
|
-
end
|
38
|
-
|
39
|
-
if name.end_with?(%q(dup'))
|
40
|
-
copy_name = :dup
|
41
|
-
break
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
return copy_name
|
35
|
+
|
36
|
+
def self.extended(mod)
|
37
|
+
super
|
38
|
+
|
39
|
+
mod.include(Copyable)
|
46
40
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
attr_accessor :default_name
|
54
|
-
attr_accessor :name
|
55
|
-
|
56
|
-
def initialize(default_name=DEFAULT_COPY_NAME)
|
57
|
-
super()
|
58
|
-
|
59
|
-
@default_name = default_name
|
60
|
-
|
61
|
-
update_name()
|
62
|
-
end
|
63
|
-
|
64
|
-
def copy(var)
|
65
|
-
return var.__send__(@name)
|
66
|
-
end
|
67
|
-
|
68
|
-
def safe_copy(var)
|
69
|
-
return var.respond_to?(@name) ? var.__send__(@name) : var
|
70
|
-
end
|
71
|
-
|
72
|
-
def update_name()
|
73
|
-
@name = InitCopy.find_copy_name(@default_name)
|
74
|
-
end
|
41
|
+
|
42
|
+
def self.prepended(mod)
|
43
|
+
super
|
44
|
+
|
45
|
+
# User specifically requested to prepend.
|
46
|
+
mod.prepend(Copyable)
|
75
47
|
end
|
76
|
-
|
77
|
-
Copyer = Copier # Alias
|
78
|
-
|
79
|
-
###
|
80
|
-
# The instance variable name is long and obnoxious to reduce conflicts.
|
81
|
-
#
|
82
|
-
# @author Jonathan Bradley Whited (@esotericpig)
|
83
|
-
# @since 0.1.0
|
84
|
-
###
|
48
|
+
|
85
49
|
module Copyable
|
86
|
-
|
87
|
-
def initialize(*)
|
88
|
-
super
|
89
|
-
@init_copy_method_name = DEFAULT_COPY_NAME
|
90
|
-
end
|
91
|
-
|
92
|
-
def initialize_clone(*)
|
93
|
-
@init_copy_method_name = :clone
|
94
|
-
super
|
95
|
-
end
|
96
|
-
|
97
|
-
def initialize_dup(*)
|
98
|
-
@init_copy_method_name = :dup
|
50
|
+
def initialize_clone(orig)
|
99
51
|
super
|
52
|
+
|
53
|
+
# The instance variable name is long & obnoxious to reduce conflicts.
|
54
|
+
@__init_copy_method_name = :clone
|
55
|
+
init_copy(orig)
|
100
56
|
end
|
101
|
-
|
102
|
-
def
|
103
|
-
@init_copy_method_name = :clone
|
57
|
+
|
58
|
+
def initialize_dup(orig)
|
104
59
|
super
|
60
|
+
|
61
|
+
@__init_copy_method_name = :dup
|
62
|
+
init_copy(orig)
|
105
63
|
end
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def init_copy(_orig)
|
110
68
|
end
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
def copy(var)
|
115
|
-
return var.__send__(@init_copy_method_name)
|
69
|
+
|
70
|
+
def ic_copy(var)
|
71
|
+
return var.__send__(@__init_copy_method_name)
|
116
72
|
end
|
117
|
-
|
118
|
-
def
|
119
|
-
@
|
120
|
-
|
121
|
-
return var.respond_to?(@init_copy_method_name) ?
|
122
|
-
var.__send__(@init_copy_method_name) : var
|
73
|
+
|
74
|
+
def ic_copy?(var)
|
75
|
+
return var.__send__(@__init_copy_method_name) if var.respond_to?(@__init_copy_method_name)
|
76
|
+
return var
|
123
77
|
end
|
124
78
|
end
|
125
|
-
|
126
|
-
Copiable = Copyable # Alias
|
127
79
|
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#--
|
5
|
+
# This file is part of InitCopy.
|
6
|
+
# Copyright (c) 2020 Bradley Whited
|
7
|
+
#
|
8
|
+
# SPDX-License-Identifier: MIT
|
9
|
+
#++
|
10
|
+
|
11
|
+
require 'minitest/autorun'
|
12
|
+
|
13
|
+
require 'init_copy'
|
14
|
+
|
15
|
+
class InitCopyTest < Minitest::Test
|
16
|
+
# def setup
|
17
|
+
# end
|
18
|
+
|
19
|
+
def test_include
|
20
|
+
%i[include extend prepend].each do |method|
|
21
|
+
sut_class = Class.new
|
22
|
+
sut_class.__send__(method,InitCopy)
|
23
|
+
|
24
|
+
assert_includes(sut_class.included_modules,InitCopy::Copyable,
|
25
|
+
"`#{method}` of InitCopy should include InitCopy::Copyable")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_no_copy
|
30
|
+
sut = TestBag.new
|
31
|
+
|
32
|
+
refute_deep_copy(sut,sut.clone,:clone)
|
33
|
+
refute_deep_copy(sut,sut.dup,:dup)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_clone
|
37
|
+
sut = TestBagWithCopy.new
|
38
|
+
|
39
|
+
assert_deep_copy(sut,sut.clone,:clone)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_dup
|
43
|
+
sut = TestBagWithCopy.new
|
44
|
+
|
45
|
+
assert_deep_copy(sut,sut.dup,:dup)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_correct_clone_and_dup_behavior
|
49
|
+
sut_ext = Module.new do
|
50
|
+
def bonus
|
51
|
+
return 100
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
sut = TestBagWithCopy.new
|
56
|
+
sut.extend(sut_ext)
|
57
|
+
|
58
|
+
assert_deep_copy(sut,sut.clone,:clone)
|
59
|
+
assert_deep_copy(sut,sut.dup,:dup)
|
60
|
+
|
61
|
+
sut.nums.freeze
|
62
|
+
sut_clone = sut.clone
|
63
|
+
sut_dup = sut.dup
|
64
|
+
|
65
|
+
assert_predicate(sut.nums,:frozen?,'SUT nums should be frozen')
|
66
|
+
assert_respond_to(sut,:bonus,'SUT should have the bonus extension')
|
67
|
+
assert_equal(100,sut.bonus)
|
68
|
+
|
69
|
+
assert_predicate(sut_clone.nums,:frozen?,'clone should keep the nums as frozen')
|
70
|
+
assert_respond_to(sut_clone,:bonus,'clone should keep the bonus extension')
|
71
|
+
assert_equal(100,sut_clone.bonus)
|
72
|
+
|
73
|
+
refute_predicate(sut_dup.nums,:frozen?,'dup should remove the internal frozen state of nums')
|
74
|
+
refute_respond_to(sut_dup,:bonus,'dup should remove the bonus extension')
|
75
|
+
assert_raises(NoMethodError) { sut_dup.bonus }
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_safe_copy
|
79
|
+
sut = TestBagWithSafeCopy.new
|
80
|
+
|
81
|
+
assert_respond_to(sut.nums,:clone)
|
82
|
+
assert_respond_to(sut.nums,:dup)
|
83
|
+
|
84
|
+
assert_deep_copy(sut,sut.clone,:clone)
|
85
|
+
assert_deep_copy(sut,sut.dup,:dup)
|
86
|
+
|
87
|
+
class << sut.nums
|
88
|
+
undef_method :clone
|
89
|
+
undef_method :dup
|
90
|
+
end
|
91
|
+
|
92
|
+
refute_respond_to(sut.nums,:clone)
|
93
|
+
refute_respond_to(sut.nums,:dup)
|
94
|
+
|
95
|
+
refute_deep_copy(sut,sut.clone,:clone,is_safe_copy: true)
|
96
|
+
refute_deep_copy(sut,sut.dup,:dup,is_safe_copy: true)
|
97
|
+
|
98
|
+
# Make sure we didn't remove clone()/dup() for all arrays.
|
99
|
+
assert_respond_to([1,2,3],:clone)
|
100
|
+
assert_respond_to([1,2,3],:dup)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_child_copy
|
104
|
+
sut_class = Class.new(TestBagWithCopy) do
|
105
|
+
attr_reader :strs
|
106
|
+
|
107
|
+
def initialize
|
108
|
+
super
|
109
|
+
|
110
|
+
@strs = %w[a b c]
|
111
|
+
end
|
112
|
+
|
113
|
+
def init_copy(*)
|
114
|
+
super
|
115
|
+
|
116
|
+
@strs = ic_copy(@strs)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
sut = sut_class.new
|
121
|
+
sut_clone = sut.clone
|
122
|
+
sut_dup = sut.dup
|
123
|
+
|
124
|
+
assert_deep_copy(sut,sut_clone,:clone)
|
125
|
+
assert_deep_copy(sut,sut_dup,:dup)
|
126
|
+
|
127
|
+
expected = %w[a b c]
|
128
|
+
|
129
|
+
refute_same(sut.strs,sut_clone.strs)
|
130
|
+
refute_same(sut.strs,sut_dup.strs)
|
131
|
+
assert_equal(expected,sut.strs)
|
132
|
+
assert_equal(expected,sut_clone.strs)
|
133
|
+
assert_equal(expected,sut_dup.strs)
|
134
|
+
|
135
|
+
sut.strs << 'd'
|
136
|
+
sut_clone.strs << 'e'
|
137
|
+
sut_dup.strs << 'f'
|
138
|
+
|
139
|
+
assert_equal(%w[a b c d],sut.strs)
|
140
|
+
assert_equal(%w[a b c e],sut_clone.strs)
|
141
|
+
assert_equal(%w[a b c f],sut_dup.strs)
|
142
|
+
end
|
143
|
+
|
144
|
+
def assert_deep_copy(sut,sut_copy,copy_method_name)
|
145
|
+
refute_same(sut,sut_copy)
|
146
|
+
|
147
|
+
assert_nil(sut.init_copy_method_name)
|
148
|
+
assert_equal(copy_method_name,sut_copy.init_copy_method_name)
|
149
|
+
|
150
|
+
assert_nil(sut.orig)
|
151
|
+
assert_same(sut,sut_copy.orig)
|
152
|
+
|
153
|
+
expected = [1,2,3]
|
154
|
+
|
155
|
+
refute_same(sut.nums,sut_copy.nums)
|
156
|
+
assert_equal(expected,sut.nums)
|
157
|
+
assert_equal(expected,sut_copy.nums)
|
158
|
+
|
159
|
+
sut.nums << 4
|
160
|
+
sut_copy.nums << 5
|
161
|
+
|
162
|
+
assert_equal([1,2,3,4],sut.nums)
|
163
|
+
assert_equal([1,2,3,5],sut_copy.nums)
|
164
|
+
|
165
|
+
# Reset.
|
166
|
+
sut.nums.pop
|
167
|
+
sut_copy.nums.pop
|
168
|
+
end
|
169
|
+
|
170
|
+
def refute_deep_copy(sut,sut_copy,copy_method_name,is_safe_copy: false)
|
171
|
+
refute_same(sut,sut_copy)
|
172
|
+
|
173
|
+
assert_nil(sut.init_copy_method_name)
|
174
|
+
assert_equal(copy_method_name,sut_copy.init_copy_method_name)
|
175
|
+
|
176
|
+
assert_nil(sut.orig)
|
177
|
+
|
178
|
+
if is_safe_copy
|
179
|
+
assert_same(sut,sut_copy.orig)
|
180
|
+
else
|
181
|
+
assert_nil(sut_copy.orig)
|
182
|
+
end
|
183
|
+
|
184
|
+
expected = [1,2,3]
|
185
|
+
|
186
|
+
assert_same(sut.nums,sut_copy.nums)
|
187
|
+
assert_equal(expected,sut.nums)
|
188
|
+
assert_equal(expected,sut_copy.nums)
|
189
|
+
|
190
|
+
sut.nums << 4
|
191
|
+
sut_copy.nums << 5
|
192
|
+
|
193
|
+
expected = [1,2,3,4,5]
|
194
|
+
|
195
|
+
assert_equal(expected,sut.nums)
|
196
|
+
assert_equal(expected,sut_copy.nums)
|
197
|
+
|
198
|
+
# Reset.
|
199
|
+
sut.nums.pop(2)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class TestBag
|
204
|
+
include InitCopy
|
205
|
+
|
206
|
+
attr_reader :orig
|
207
|
+
attr_reader :nums
|
208
|
+
|
209
|
+
def initialize
|
210
|
+
super
|
211
|
+
|
212
|
+
@__init_copy_method_name = nil
|
213
|
+
@orig = nil
|
214
|
+
@nums = [1,2,3]
|
215
|
+
end
|
216
|
+
|
217
|
+
def init_copy_method_name
|
218
|
+
return @__init_copy_method_name
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
class TestBagWithCopy < TestBag
|
223
|
+
protected
|
224
|
+
|
225
|
+
def init_copy(orig)
|
226
|
+
super
|
227
|
+
|
228
|
+
@orig = orig
|
229
|
+
@nums = ic_copy(@nums)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
class TestBagWithSafeCopy < TestBag
|
234
|
+
protected
|
235
|
+
|
236
|
+
def init_copy(orig)
|
237
|
+
super
|
238
|
+
|
239
|
+
@orig = orig
|
240
|
+
@nums = ic_copy?(@nums)
|
241
|
+
end
|
242
|
+
end
|
metadata
CHANGED
@@ -1,108 +1,66 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: init_copy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Bradley Whited
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '2.1'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '2.1'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: minitest
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '5.14'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '5.14'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '13.0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '13.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: yard
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.9'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0.9'
|
69
|
-
description: Easily use the appropriate clone/dup method in initialize_copy.
|
11
|
+
date: 2025-06-06 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Easily use the correct clone or dup method in initialize_copy.
|
70
14
|
email:
|
71
|
-
-
|
15
|
+
- code@esotericpig.com
|
72
16
|
executables: []
|
73
17
|
extensions: []
|
74
|
-
extra_rdoc_files:
|
18
|
+
extra_rdoc_files:
|
19
|
+
- LICENSE.txt
|
20
|
+
- README.md
|
75
21
|
files:
|
22
|
+
- ".rdoc_options"
|
76
23
|
- Gemfile
|
77
24
|
- LICENSE.txt
|
25
|
+
- README.md
|
78
26
|
- Rakefile
|
79
27
|
- init_copy.gemspec
|
80
28
|
- lib/init_copy.rb
|
29
|
+
- test/init_copy_test.rb
|
81
30
|
homepage: https://github.com/esotericpig/init_copy
|
82
31
|
licenses:
|
83
32
|
- MIT
|
84
33
|
metadata:
|
85
|
-
|
86
|
-
changelog_uri: https://github.com/esotericpig/init_copy/blob/master/CHANGELOG.md
|
34
|
+
rubygems_mfa_required: 'true'
|
87
35
|
homepage_uri: https://github.com/esotericpig/init_copy
|
88
36
|
source_code_uri: https://github.com/esotericpig/init_copy
|
37
|
+
bug_tracker_uri: https://github.com/esotericpig/init_copy/issues
|
38
|
+
changelog_uri: https://github.com/esotericpig/init_copy/blob/main/CHANGELOG.md
|
89
39
|
post_install_message:
|
90
|
-
rdoc_options:
|
40
|
+
rdoc_options:
|
41
|
+
- "--embed-mixins"
|
42
|
+
- "--hyperlink-all"
|
43
|
+
- "--line-numbers"
|
44
|
+
- "--show-hash"
|
45
|
+
- "--main"
|
46
|
+
- README.md
|
47
|
+
- "--title"
|
48
|
+
- InitCopy v0.2.0
|
91
49
|
require_paths:
|
92
50
|
- lib
|
93
51
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
52
|
requirements:
|
95
53
|
- - ">="
|
96
54
|
- !ruby/object:Gem::Version
|
97
|
-
version: '2
|
55
|
+
version: '3.2'
|
98
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
57
|
requirements:
|
100
58
|
- - ">="
|
101
59
|
- !ruby/object:Gem::Version
|
102
60
|
version: '0'
|
103
61
|
requirements: []
|
104
|
-
rubygems_version: 3.
|
62
|
+
rubygems_version: 3.5.21
|
105
63
|
signing_key:
|
106
64
|
specification_version: 4
|
107
|
-
summary: Easily use the
|
65
|
+
summary: Easily use the correct clone or dup method in initialize_copy.
|
108
66
|
test_files: []
|