ruby_ext 0.4.25 → 0.5.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.
- data/Rakefile +2 -0
- data/lib/rake_ext/project.rb +19 -19
- data/lib/rake_ext.rb +18 -18
- data/lib/rspec_ext/xhtml.rb +6 -6
- data/lib/rspec_ext.rb +40 -25
- data/lib/ruby_ext/core/array.rb +7 -7
- data/lib/ruby_ext/core/basic_object.rb +1 -1
- data/lib/ruby_ext/core/deep_clone.rb +2 -2
- data/lib/ruby_ext/core/enumerable.rb +1 -1
- data/lib/ruby_ext/core/hash.rb +4 -4
- data/lib/ruby_ext/core/module.rb +20 -30
- data/lib/ruby_ext/core/multiple_inheritance.rb +24 -24
- data/lib/ruby_ext/core/must.rb +39 -39
- data/lib/ruby_ext/core/object.rb +15 -3
- data/lib/ruby_ext/core/open_object.rb +22 -20
- data/lib/ruby_ext/core/string.rb +19 -19
- data/lib/ruby_ext/core/symbol.rb +1 -13
- data/lib/ruby_ext/core.rb +4 -8
- data/lib/ruby_ext/more/callbacks.rb +172 -0
- data/lib/ruby_ext/more/declarative_cache.rb +20 -22
- data/lib/ruby_ext/more/miscellaneous.rb +1 -46
- data/lib/ruby_ext/more/{observable2.rb → observable.rb} +8 -8
- data/lib/ruby_ext/more/open_constructor.rb +10 -10
- data/lib/ruby_ext/more/tuple.rb +1 -1
- data/lib/ruby_ext/more.rb +5 -3
- data/lib/ruby_ext.rb +0 -3
- data/lib/yaml_fix.rb +2 -2
- data/readme.md +51 -50
- data/spec/core/deep_clone_spec.rb +8 -8
- data/spec/core/module_spec.rb +29 -36
- data/spec/core/multiple_inheritance_spec.rb +32 -32
- data/spec/core/must_spec.rb +6 -6
- data/spec/core/object_spec.rb +15 -0
- data/spec/core/open_object_spec.rb +6 -6
- data/spec/more/callbacks_spec.rb +155 -0
- data/spec/more/declarative_cache_spec.rb +33 -33
- data/spec/more/{observable2_spec.rb → observable_spec.rb} +7 -7
- data/spec/more/open_constructor_spec.rb +5 -5
- metadata +7 -15
- data/lib/ruby_ext/core/class.rb +0 -0
- data/lib/ruby_ext/core/file.rb +0 -23
- data/lib/ruby_ext/core/kernel.rb +0 -69
- data/lib/ruby_ext/core/miscellaneous.rb +0 -14
- data/lib/ruby_ext/more/synchronize.rb +0 -26
- data/spec/core/kernel_spec/TheNamespace/ClassA.rb +0 -7
- data/spec/core/kernel_spec/another_class.rb +0 -5
- data/spec/core/kernel_spec/the_namespace/class_b.rb +0 -11
- data/spec/core/kernel_spec.rb +0 -51
- data/spec/more/miscellaneous_spec.rb +0 -14
- data/spec/more/synchronize_spec.rb +0 -79
@@ -0,0 +1,172 @@
|
|
1
|
+
module RubyExt::Callbacks
|
2
|
+
class AbstractCallback
|
3
|
+
attr_accessor :terminator
|
4
|
+
|
5
|
+
attr_reader :executor
|
6
|
+
def executor= executor
|
7
|
+
@executor = executor.must_be.a Symbol, Proc
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :conditions
|
11
|
+
def conditions= conditions
|
12
|
+
@conditions = {}
|
13
|
+
conditions.each do |k, v|
|
14
|
+
@conditions[k.to_sym] = if v.is_a? Symbol
|
15
|
+
v.to_s
|
16
|
+
elsif v.is_a? Array
|
17
|
+
v.collect{|e| e.to_s}
|
18
|
+
else
|
19
|
+
v
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@conditions
|
23
|
+
end
|
24
|
+
|
25
|
+
def terminate? target, result
|
26
|
+
unless terminator.nil?
|
27
|
+
if terminator.is_a? Proc
|
28
|
+
terminator.call target, result
|
29
|
+
else
|
30
|
+
result == terminator
|
31
|
+
end
|
32
|
+
else
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run? target, inf
|
38
|
+
if cond = conditions[:if]
|
39
|
+
evaluate_if(cond, target, inf)
|
40
|
+
elsif cond = conditions[:unless]
|
41
|
+
!evaluate_if(cond, target, inf)
|
42
|
+
elsif cond = conditions[:only]
|
43
|
+
evaluate_only(cond, inf)
|
44
|
+
elsif cond = conditions[:except]
|
45
|
+
!evaluate_only(cond, inf)
|
46
|
+
else
|
47
|
+
true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_to_chain target, inf, &the_next
|
52
|
+
if run? target, inf
|
53
|
+
build_block target, &the_next
|
54
|
+
else
|
55
|
+
the_next
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
alias_method :deep_clone, :clone
|
60
|
+
|
61
|
+
protected
|
62
|
+
def evaluate_if cond, target, inf
|
63
|
+
if cond.is_a? String
|
64
|
+
target.send cond
|
65
|
+
elsif cond.is_a? Proc
|
66
|
+
cond.call target, inf
|
67
|
+
else
|
68
|
+
must_be.never_called
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def evaluate_only cond, inf
|
73
|
+
method = inf[:method].to_s
|
74
|
+
if cond.is_a? String
|
75
|
+
cond == method
|
76
|
+
elsif cond.is_a? Array
|
77
|
+
cond.include? method
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class BeforeCallback < AbstractCallback
|
83
|
+
def build_block target, &the_next
|
84
|
+
lambda do
|
85
|
+
result = if executor.is_a? Symbol
|
86
|
+
target.send executor
|
87
|
+
elsif executor.is_a? Proc
|
88
|
+
executor.call target
|
89
|
+
else
|
90
|
+
must_be.never_called
|
91
|
+
end
|
92
|
+
|
93
|
+
the_next.call unless terminate? target, result
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class AroundCallback < AbstractCallback
|
99
|
+
def build_block target, &the_next
|
100
|
+
lambda do
|
101
|
+
if executor.is_a? Symbol
|
102
|
+
target.send executor, &the_next
|
103
|
+
elsif executor.is_a? Proc
|
104
|
+
executor.call target, the_next
|
105
|
+
else
|
106
|
+
must_be.never_called
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class AfterCallback < AbstractCallback
|
113
|
+
def build_block target, &the_next
|
114
|
+
lambda do
|
115
|
+
result = if executor.is_a? Symbol
|
116
|
+
target.send executor
|
117
|
+
elsif executor.is_a? Proc
|
118
|
+
executor.call target
|
119
|
+
else
|
120
|
+
must_be.never_called
|
121
|
+
end
|
122
|
+
|
123
|
+
the_next.call unless terminate? target, result
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def run_callbacks callback_name, additional_information = {}, &block
|
129
|
+
callback_name = callback_name.to_s
|
130
|
+
block.must_be.defined
|
131
|
+
|
132
|
+
callbacks = self.class.callbacks[callback_name]
|
133
|
+
chain_head = block
|
134
|
+
if callbacks and !callbacks.empty?
|
135
|
+
callbacks.reverse_each do |callback|
|
136
|
+
block = callback.add_to_chain self, additional_information, &chain_head
|
137
|
+
chain_head = block if block
|
138
|
+
end
|
139
|
+
end
|
140
|
+
chain_head.call
|
141
|
+
end
|
142
|
+
|
143
|
+
module ClassMethods
|
144
|
+
inheritable_accessor :callbacks, {}
|
145
|
+
|
146
|
+
def set_callback callback_name, type, *executor_or_options, &block
|
147
|
+
# parsing arguments
|
148
|
+
type, callback_name = type.to_s, callback_name.to_s
|
149
|
+
opt = executor_or_options.extract_options!
|
150
|
+
"You can't provide both method name and block for filter!" if block and !executor_or_options.empty?
|
151
|
+
executor = block || executor_or_options.first
|
152
|
+
|
153
|
+
type.must_be.in %w{before around after}
|
154
|
+
executor.must_be.defined
|
155
|
+
|
156
|
+
# creating callback
|
157
|
+
callback = case type
|
158
|
+
when 'before' then BeforeCallback.new
|
159
|
+
when 'around' then AroundCallback.new
|
160
|
+
when 'after' then AfterCallback.new
|
161
|
+
end
|
162
|
+
|
163
|
+
callback.executor = executor
|
164
|
+
callback.terminator = opt.delete :terminator
|
165
|
+
callback.conditions = opt
|
166
|
+
|
167
|
+
callbacks[callback_name] ||= []
|
168
|
+
callbacks[callback_name] << callback
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
@@ -4,27 +4,25 @@ Module.class_eval do
|
|
4
4
|
def cache_method *methods
|
5
5
|
DeclarativeCache.cache_method self, *methods
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def cache_method_with_params *methods
|
9
9
|
DeclarativeCache.cache_method_with_params self, *methods
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
instance_variables.each do |iv|
|
16
|
-
remove_instance_variable iv if iv =~ /_cache$/ or iv =~ /_cache_check$/
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear_cache obj
|
13
|
+
obj.instance_variables.each do |iv|
|
14
|
+
obj.send :remove_instance_variable, iv if iv =~ /_cache$/ or iv =~ /_cache_check$/
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
20
18
|
|
21
|
-
module DeclarativeCache
|
19
|
+
module DeclarativeCache
|
22
20
|
DISABLED = false
|
23
21
|
|
24
22
|
warn "CASHE DISABLED" if DISABLED
|
25
|
-
unless DISABLED
|
23
|
+
unless DISABLED
|
26
24
|
class << self
|
27
|
-
|
25
|
+
|
28
26
|
def cache_method klass, *methods
|
29
27
|
methods.each do |method|
|
30
28
|
klass.class_eval do
|
@@ -32,9 +30,9 @@ module DeclarativeCache
|
|
32
30
|
method_with_cache, method_without_cache = "#{escaped_method}_with_cache".to_sym, "#{escaped_method}_without_cache".to_sym
|
33
31
|
iv_check = "@#{escaped_method}_cache_check"
|
34
32
|
iv = "@#{escaped_method}_cache"
|
35
|
-
|
33
|
+
|
36
34
|
if instance_methods.include?(method_with_cache) or instance_methods.include?(method_without_cache)
|
37
|
-
warn "can't cache the :#{method} twice!"
|
35
|
+
warn "can't cache the :#{method} twice!"
|
38
36
|
else
|
39
37
|
alias_method method_without_cache, method
|
40
38
|
|
@@ -55,21 +53,21 @@ module DeclarativeCache
|
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
58
|
-
|
59
|
-
def cache_method_with_params klass, *methods
|
60
|
-
methods.each do |method|
|
61
|
-
klass.class_eval do
|
56
|
+
|
57
|
+
def cache_method_with_params klass, *methods
|
58
|
+
methods.each do |method|
|
59
|
+
klass.class_eval do
|
62
60
|
escaped_method = escape_method(method)
|
63
61
|
method_with_cache, method_without_cache = "#{escaped_method}_with_cache".to_sym, "#{escaped_method}_without_cache".to_sym
|
64
62
|
iv_check = "@#{escaped_method}_cache_check"
|
65
63
|
iv = "@#{escaped_method}_cache"
|
66
|
-
|
64
|
+
|
67
65
|
if instance_methods.include?(method_with_cache) or instance_methods.include?(method_without_cache)
|
68
|
-
warn "can't cache the :#{method} twice!"
|
66
|
+
warn "can't cache the :#{method} twice!"
|
69
67
|
else
|
70
68
|
alias_method method_without_cache, method
|
71
69
|
|
72
|
-
define_method method_with_cache do |*args|
|
70
|
+
define_method method_with_cache do |*args|
|
73
71
|
unless results = instance_variable_get(iv)
|
74
72
|
results = Hash.new(NotDefined)
|
75
73
|
instance_variable_set iv, results
|
@@ -77,7 +75,7 @@ module DeclarativeCache
|
|
77
75
|
|
78
76
|
result = results[args]
|
79
77
|
|
80
|
-
if result.equal? NotDefined
|
78
|
+
if result.equal? NotDefined
|
81
79
|
result = send method_without_cache, *args
|
82
80
|
results[args] = result
|
83
81
|
end
|
@@ -90,7 +88,7 @@ module DeclarativeCache
|
|
90
88
|
end
|
91
89
|
end
|
92
90
|
end
|
93
|
-
|
91
|
+
|
94
92
|
end
|
95
93
|
end
|
96
94
|
end
|
@@ -1,52 +1,7 @@
|
|
1
1
|
Kernel.class_eval do
|
2
2
|
alias_method :old_p, :p
|
3
|
-
def p *args
|
3
|
+
def p *args
|
4
4
|
puts args.collect{|a| a.inspect}.join(' ')
|
5
5
|
return *args
|
6
6
|
end
|
7
|
-
end
|
8
|
-
|
9
|
-
|
10
|
-
#
|
11
|
-
# Parsing command line
|
12
|
-
#
|
13
|
-
module RubyExt
|
14
|
-
def self.argv input = ARGV
|
15
|
-
# don't want to modify original input and can't use :clone (it may be not an array)
|
16
|
-
input = input.collect{|v| v}
|
17
|
-
|
18
|
-
list, options = [], {}
|
19
|
-
until input.empty? do
|
20
|
-
arg = input.shift.strip
|
21
|
-
if arg =~ /.+:$/ and !input.empty?
|
22
|
-
k = arg[0..-2].to_sym
|
23
|
-
v = input.shift
|
24
|
-
v = v.sub(/\s*,$/, '') if v
|
25
|
-
options[k] = simple_cast(v)
|
26
|
-
else
|
27
|
-
v = arg.gsub(/^['"]|['"]$/, '')
|
28
|
-
v = v.sub(/\s*,$/, '')
|
29
|
-
list << simple_cast(v)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
list << options
|
33
|
-
list
|
34
|
-
end
|
35
|
-
|
36
|
-
protected
|
37
|
-
def self.simple_cast v
|
38
|
-
if v =~ /^:[a-z_0-9]+$/i
|
39
|
-
v[1..-1].to_sym
|
40
|
-
elsif v =~ /^[0-9]+$/
|
41
|
-
v.to_i
|
42
|
-
elsif v =~ /^[0-9]*\.[0-9]+$/
|
43
|
-
v.to_f
|
44
|
-
elsif v =~ /^\/.+\/$/
|
45
|
-
Regexp.new v[1..-2]
|
46
|
-
elsif v == 'nil'
|
47
|
-
nil
|
48
|
-
else
|
49
|
-
v
|
50
|
-
end
|
51
|
-
end
|
52
7
|
end
|
@@ -1,22 +1,22 @@
|
|
1
|
-
module
|
1
|
+
module RubyExt::Observable
|
2
2
|
def add_observer observer
|
3
3
|
@observable_observers ||= []
|
4
|
-
@observable_observers << observer unless @observable_observers.include? observer
|
4
|
+
@observable_observers << observer unless @observable_observers.include? observer
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
def notify_observers method, *args
|
8
8
|
raise "Invalid usage, method must be Symbol or String!" unless method.is_a?(Symbol) or method.is_a?(String)
|
9
|
-
@observable_observers.each{|observer| observer.respond_to method, *args} if @observable_observers
|
9
|
+
@observable_observers.each{|observer| observer.respond_to method, *args} if @observable_observers
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def delete_observer observer
|
13
13
|
@observable_observers.delete observer if @observable_observers
|
14
14
|
end
|
15
|
-
|
16
|
-
def delete_observers
|
15
|
+
|
16
|
+
def delete_observers
|
17
17
|
@observable_observers.clear if @observable_observers
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def observers_count
|
21
21
|
@observable_observers ? @observable_observers.size : 0
|
22
22
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
module OpenConstructor
|
1
|
+
module RubyExt::OpenConstructor
|
2
2
|
def set values, list = nil
|
3
3
|
unless list
|
4
4
|
if values.is_a? Hash
|
5
|
-
values.each do |k, v|
|
5
|
+
values.each do |k, v|
|
6
6
|
self.respond_to "#{k}=", v
|
7
7
|
end
|
8
8
|
else
|
@@ -15,32 +15,32 @@ module OpenConstructor
|
|
15
15
|
end
|
16
16
|
else
|
17
17
|
if values.is_a? Hash
|
18
|
-
values.each do |k, v|
|
18
|
+
values.each do |k, v|
|
19
19
|
self.respond_to "#{k}=", v if list.include? k
|
20
20
|
end
|
21
21
|
else
|
22
22
|
values.instance_variables.each do |name|
|
23
23
|
accessor = name[1..name.size]
|
24
|
-
if list.include?(accessor.to_sym)
|
24
|
+
if list.include?(accessor.to_sym)
|
25
25
|
accessor = "#{accessor}="
|
26
26
|
if self.respond_to?(accessor)
|
27
27
|
self.send accessor, values.instance_variable_get(name)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
32
32
|
end
|
33
|
-
return self
|
34
|
-
end
|
35
|
-
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
36
|
def set! values
|
37
37
|
values.each do |k, v|
|
38
|
-
self.send "#{k}=", v
|
38
|
+
self.send "#{k}=", v
|
39
39
|
end
|
40
40
|
return self
|
41
41
|
end
|
42
42
|
# alias_method :set! #, :set_with_check
|
43
|
-
|
43
|
+
|
44
44
|
def to_hash
|
45
45
|
hash = {}
|
46
46
|
instance_variables.each do |name|
|
data/lib/ruby_ext/more/tuple.rb
CHANGED
data/lib/ruby_ext/more.rb
CHANGED
data/lib/ruby_ext.rb
CHANGED
data/lib/yaml_fix.rb
CHANGED
data/readme.md
CHANGED
@@ -1,55 +1,56 @@
|
|
1
|
-
|
2
|
-
**ruby_ext** is a collection of various utility classes and standard library extensions for the Ruby language.
|
1
|
+
Collection of various utility classes and standard library extensions for Ruby language.
|
3
2
|
|
4
3
|
## must - assertion tool, kind of RSpec assertions in runtime code
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
``` ruby
|
6
|
+
1.must_be.in 1..2
|
7
|
+
"a".must_be.in 'a', 'b', 'c'
|
8
|
+
key.must_be.a String
|
9
|
+
value.must_not_be.nil
|
10
|
+
must_be.never_called
|
11
|
+
a.must_be == b
|
12
|
+
```
|
12
13
|
|
13
14
|
## inherit - combines include & extend in one
|
14
15
|
Do you remember this *def self.included(base) ... end* hack? You don't need it anymore.
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
-
synchronize_method :money_transfer
|
17
|
+
``` ruby
|
18
|
+
module Feature
|
19
|
+
def cool_method; end
|
20
|
+
class_methods do
|
21
|
+
def cool_class_method; end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class TheClass
|
26
|
+
inherit Feature
|
27
|
+
end
|
28
|
+
|
29
|
+
TheClass.new.cool_method
|
30
|
+
TheClass.cool_class_method
|
31
|
+
```
|
32
|
+
|
33
|
+
## cache_method
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
def complex_calculation
|
37
|
+
2 * 2
|
38
|
+
end
|
39
|
+
cache_method :complex_calculation
|
40
|
+
```
|
42
41
|
|
43
42
|
## OpenConstructor - adds mass assignment to any class
|
44
|
-
|
45
|
-
class TheClass
|
46
|
-
include OpenConstructor
|
47
|
-
attr_accessor :a, :b
|
48
|
-
end
|
49
43
|
|
50
|
-
|
51
|
-
|
52
|
-
|
44
|
+
``` ruby
|
45
|
+
class TheClass
|
46
|
+
include RubyExt::OpenConstructor
|
47
|
+
attr_accessor :a, :b
|
48
|
+
end
|
49
|
+
|
50
|
+
o = TheClass.new.set a: 'a', b: 'b'
|
51
|
+
o.a => 'a'
|
52
|
+
o.to_hash => {a: 'a', b: 'b'}
|
53
|
+
```
|
53
54
|
|
54
55
|
## More
|
55
56
|
|
@@ -57,14 +58,14 @@ These are just a small part of all handy methods and extensions, for more detail
|
|
57
58
|
|
58
59
|
# Usage
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
Copyright (c) Alexey Petrushin, http://petrush.in, released under the MIT license.
|
61
|
+
``` bash
|
62
|
+
gem install ruby_ext
|
63
|
+
```
|
65
64
|
|
66
|
-
|
65
|
+
``` ruby
|
66
|
+
require 'ruby_ext'
|
67
|
+
```
|
67
68
|
|
68
|
-
|
69
|
+
## License
|
69
70
|
|
70
|
-
|
71
|
+
Copyright (c) Alexey Petrushin, http://petrush.in, released under the MIT license.
|
@@ -4,33 +4,33 @@ describe 'deep_clone' do
|
|
4
4
|
it "basic" do
|
5
5
|
hash, array = {}, ['value']
|
6
6
|
hash['key'] = array
|
7
|
-
|
7
|
+
|
8
8
|
hash2 = hash.deep_clone
|
9
9
|
array2 = hash2['key']
|
10
|
-
|
10
|
+
|
11
11
|
hash2.should == hash
|
12
12
|
hash2.object_id.should_not == hash.object_id
|
13
|
-
|
13
|
+
|
14
14
|
array2.should == array
|
15
15
|
array2.object_id.should_not == array.object_id
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
it do
|
19
19
|
class Metadata
|
20
20
|
attr_accessor :registry
|
21
|
-
|
21
|
+
|
22
22
|
def initialize
|
23
23
|
@registry = {}
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
m = Metadata.new
|
28
28
|
m.registry[:a] = 1
|
29
|
-
|
29
|
+
|
30
30
|
m2 = m.deep_clone
|
31
31
|
m2.registry.should include(:a)
|
32
32
|
m2.registry[:b] = 2
|
33
|
-
|
33
|
+
|
34
34
|
m.registry.should == {a: 1}
|
35
35
|
end
|
36
36
|
end
|