Skip to content
This repository was archived by the owner on Mar 15, 2022. It is now read-only.

Commit 72e2c12

Browse files
committed
Merge pull request #34 from ruby-concurrency/map-merge
Added a #merge method to the map classes.
2 parents c0130de + bcd5fb5 commit 72e2c12

File tree

5 files changed

+199
-44
lines changed

5 files changed

+199
-44
lines changed

lib/ref/abstract_reference_key_map.rb

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ def to_a
7272
array
7373
end
7474

75+
# Returns a hash containing the names and values for the struct’s members.
76+
def to_h
77+
hash = {}
78+
each{|k,v| hash[k] = v}
79+
hash
80+
end
81+
7582
# Iterate through all the key/value pairs in the map that have not been reclaimed
7683
# by the garbage collector.
7784
def each
@@ -89,6 +96,18 @@ def clear
8996
end
9097
end
9198

99+
# Returns a new struct containing the contents of `other` and the contents
100+
# of `self`. If no block is specified, the value for entries with duplicate
101+
# keys will be that of `other`. Otherwise the value for each duplicate key
102+
# is determined by calling the block with the key, its value in `self` and
103+
# its value in `other`.
104+
def merge(other_hash, &block)
105+
to_h.merge(other_hash, &block).reduce(self.class.new) do |map, pair|
106+
map[pair.first] = pair.last
107+
map
108+
end
109+
end
110+
92111
# Merge the values from another hash into this map.
93112
def merge!(other_hash)
94113
@lock.synchronize do
@@ -123,20 +142,20 @@ def inspect
123142

124143
private
125144

126-
def ref_key (key)
127-
ref = @references_to_keys_map[key.__id__]
128-
if ref && ref.object
129-
ref.referenced_object_id
130-
else
131-
nil
132-
end
145+
def ref_key (key)
146+
ref = @references_to_keys_map[key.__id__]
147+
if ref && ref.object
148+
ref.referenced_object_id
149+
else
150+
nil
133151
end
152+
end
134153

135-
def remove_reference_to(object_id)
136-
@lock.synchronize do
137-
@references_to_keys_map.delete(object_id)
138-
@values.delete(object_id)
139-
end
154+
def remove_reference_to(object_id)
155+
@lock.synchronize do
156+
@references_to_keys_map.delete(object_id)
157+
@values.delete(object_id)
140158
end
159+
end
141160
end
142161
end

lib/ref/abstract_reference_value_map.rb

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ def to_a
8484
array
8585
end
8686

87+
# Returns a hash containing the names and values for the struct’s members.
88+
def to_h
89+
hash = {}
90+
each{|k,v| hash[k] = v}
91+
hash
92+
end
93+
8794
# Iterate through all the key/value pairs in the map that have not been reclaimed
8895
# by the garbage collector.
8996
def each
@@ -101,6 +108,18 @@ def clear
101108
end
102109
end
103110

111+
# Returns a new struct containing the contents of `other` and the contents
112+
# of `self`. If no block is specified, the value for entries with duplicate
113+
# keys will be that of `other`. Otherwise the value for each duplicate key
114+
# is determined by calling the block with the key, its value in `self` and
115+
# its value in `other`.
116+
def merge(other_hash, &block)
117+
to_h.merge(other_hash, &block).reduce(self.class.new) do |map, pair|
118+
map[pair.first] = pair.last
119+
map
120+
end
121+
end
122+
104123
# Merge the values from another hash into this map.
105124
def merge!(other_hash)
106125
@lock.synchronize do
@@ -136,16 +155,16 @@ def inspect
136155

137156
private
138157

139-
def remove_reference_to(object_id)
140-
@lock.synchronize do
141-
keys = @references_to_keys_map[object_id]
142-
if keys
143-
keys.each do |key|
144-
@references.delete(key)
145-
end
146-
@references_to_keys_map.delete(object_id)
158+
def remove_reference_to(object_id)
159+
@lock.synchronize do
160+
keys = @references_to_keys_map[object_id]
161+
if keys
162+
keys.each do |key|
163+
@references.delete(key)
147164
end
165+
@references_to_keys_map.delete(object_id)
148166
end
149167
end
168+
end
150169
end
151170
end

spec/ref/soft_value_map_spec.rb

100755100644
File mode changed.

spec/shared/reference_key_map_shared.rb

100755100644
Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
let(:key_3) { Object.new }
1010
let(:hash) { map_class.new }
1111

12-
describe 'keeps entries with strong references' do
12+
context 'keeps entries with strong references' do
1313
specify do
1414
Ref::Mock.use do
1515
hash[key_1] = "value 1"
@@ -20,7 +20,7 @@
2020
end
2121
end
2222

23-
describe 'removes entries that have been garbage collected' do
23+
context 'removes entries that have been garbage collected' do
2424
specify do
2525
Ref::Mock.use do
2626
hash[key_1] = value_1
@@ -34,7 +34,7 @@
3434
end
3535
end
3636

37-
describe 'can clear the map' do
37+
context 'can clear the map' do
3838
specify do
3939
Ref::Mock.use do
4040
hash[key_1] = value_1
@@ -46,7 +46,7 @@
4646
end
4747
end
4848

49-
describe 'can delete entries' do
49+
context 'can delete entries' do
5050
specify do
5151
Ref::Mock.use do
5252
hash[key_1] = value_1
@@ -59,7 +59,7 @@
5959
end
6060
end
6161

62-
describe 'can merge in another hash' do
62+
context 'can merge in another hash' do
6363
specify do
6464
Ref::Mock.use do
6565
hash[key_1] = value_1
@@ -78,7 +78,7 @@
7878
end
7979
end
8080

81-
describe 'can get all keys' do
81+
context 'can get all keys' do
8282
specify do
8383
Ref::Mock.use do
8484
hash[key_1] = value_1
@@ -91,7 +91,7 @@
9191
end
9292
end
9393

94-
describe 'can turn into an array' do
94+
context 'can turn into an array' do
9595
specify do
9696
Ref::Mock.use do
9797
hash[key_1] = value_1
@@ -105,7 +105,21 @@
105105
end
106106
end
107107

108-
describe 'can interate over all entries' do
108+
context 'can turn into a hash' do
109+
specify do
110+
Ref::Mock.use do
111+
hash[key_1] = value_1
112+
hash[key_2] = value_2
113+
hash[key_3] = value_3
114+
order = lambda{|a,b| a.last <=> b.last}
115+
expect({key_1 => "value 1", key_2 => "value 2", key_3 => "value 3"}.sort(&order)).to eq hash.to_h.sort(&order)
116+
Ref::Mock.gc(key_2)
117+
expect({key_1 => "value 1", key_3 => "value 3"}.sort(&order)).to eq hash.to_h.sort(&order)
118+
end
119+
end
120+
end
121+
122+
context 'can interate over all entries' do
109123
specify do
110124
Ref::Mock.use do
111125
hash[key_1] = value_1
@@ -126,7 +140,7 @@
126140
end
127141
end
128142

129-
describe 'size' do
143+
context 'size' do
130144
specify do
131145
Ref::Mock.use do
132146
hash = map_class.new
@@ -144,12 +158,55 @@
144158
end
145159
end
146160

147-
describe 'inspect' do
161+
context 'inspect' do
148162
specify do
149163
Ref::Mock.use do
150164
hash[Object.new] = "value 1"
151165
expect(hash.inspect).to_not be_nil
152166
end
153167
end
154168
end
169+
170+
context '#merge' do
171+
172+
let(:new_value){ Object.new }
173+
let(:values){ {key_1 => value_1, key_2 => value_2, key_3 => value_3} }
174+
let(:this) do
175+
values.each{|k, v| hash[k] = v }
176+
hash
177+
end
178+
let(:other){ {key_3 => new_value} }
179+
180+
it 'updates all members with the new values from a given hash' do
181+
expect(this.merge(other)[key_3]).to eq new_value
182+
end
183+
184+
it 'calls the given block for each key in `other`' do
185+
actual = 0
186+
this.merge(key_2 => 'yes', key_3 => 'no'){|member, thisval, otherval| actual += 1; Object.new }
187+
expect(actual).to eq 2
188+
end
189+
190+
it 'retains the value for all members without values in the given hash' do
191+
expect(this.merge(other)[key_1]).to eq value_1
192+
end
193+
194+
it 'adds members not in the original hash' do
195+
new_key = Object.new
196+
new_value = 'life, the universe, and everything'
197+
expect(this.merge(new_key => new_value)[new_key]).to eq new_value
198+
end
199+
200+
it 'returns a deep copy when merging an empty hash' do
201+
other = this.merge({})
202+
values.each do |key, value|
203+
expect(other[key]).to eq value
204+
end
205+
end
206+
207+
it 'returns a new object' do
208+
expect(this.merge(other).object_id).to_not eq this.object_id
209+
expect(this.merge(other).object_id).to_not eq other.object_id
210+
end
211+
end
155212
end

0 commit comments

Comments
 (0)