cicphash 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/cicphash.rb +288 -0
- data/test/test_cicphash.rb +401 -0
- metadata +46 -0
data/cicphash.rb
ADDED
@@ -0,0 +1,288 @@
|
|
1
|
+
# Copyright (c) 2007 Jeremy Evans
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
# SOFTWARE.
|
20
|
+
|
21
|
+
# Case Insensitive, Case Preserving Hash
|
22
|
+
#
|
23
|
+
# CICPHash has the exact same interface as Hash, but is case insensitive
|
24
|
+
# and case preserving. Any value can be used as a key. However, you
|
25
|
+
# cannot have two keys in the same CICPHash that would be the same if when
|
26
|
+
# converted to strings would be equal or differing only in case.
|
27
|
+
#
|
28
|
+
# For example, all of the following keys would be considered equalivalent:
|
29
|
+
# 'ab', 'Ab', 'AB', 'aB', :ab, :Ab, :AB, :aB, ['A', :b], [nil, :A, nil, 'b'].
|
30
|
+
#
|
31
|
+
# CICPHash uses a last match wins policy. If an key-value pair is added to
|
32
|
+
# a CICPHash and a case insensitive variant of the key is already in the hash
|
33
|
+
# the instance of the key in the hash becomes the same the most recently added
|
34
|
+
# key (and obviously the value is updated to reflect the new value).
|
35
|
+
#
|
36
|
+
# You can change the rules determining which keys are equal by modifying the
|
37
|
+
# private convert_key method. By default, it is set to key.to_s.downcase.
|
38
|
+
# This method should produce the same output for any keys that you want to
|
39
|
+
# consider equal. For example, if you want :a and :A to be equal but :a to be
|
40
|
+
# different than "a", maybe key.inspect.downcase would work for you.
|
41
|
+
class CICPHash
|
42
|
+
include Enumerable
|
43
|
+
|
44
|
+
def self.[](*items)
|
45
|
+
if items.length % 2 != 0
|
46
|
+
if items.length == 1 && items.first.is_a?(Hash)
|
47
|
+
new.merge(items.first)
|
48
|
+
else
|
49
|
+
raise ArgumentError, "odd number of arguments for CICPHash"
|
50
|
+
end
|
51
|
+
else
|
52
|
+
hash = new
|
53
|
+
loop do
|
54
|
+
break if items.length == 0
|
55
|
+
key = items.shift
|
56
|
+
value = items.shift
|
57
|
+
hash[key] = value
|
58
|
+
end
|
59
|
+
hash
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(*default, &block)
|
64
|
+
if default.length > 1 || default.length == 1 && block_given?
|
65
|
+
raise ArgumentError, "wrong number of arguments"
|
66
|
+
end
|
67
|
+
@name_hash = {}
|
68
|
+
@hash = {}
|
69
|
+
@default = default.first unless block_given?
|
70
|
+
@default_proc = Proc.new(&block) if block_given?
|
71
|
+
end
|
72
|
+
|
73
|
+
def ==(hash)
|
74
|
+
to_hash == hash.to_hash
|
75
|
+
end
|
76
|
+
|
77
|
+
def [](key)
|
78
|
+
new_key = convert_key(key)
|
79
|
+
if @hash.include?(new_key)
|
80
|
+
@hash[new_key]
|
81
|
+
elsif @default_proc
|
82
|
+
@default_proc.call(self, key)
|
83
|
+
else
|
84
|
+
@default
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def []=(key, value)
|
89
|
+
new_key = convert_key(key)
|
90
|
+
@name_hash[new_key] = key
|
91
|
+
@hash[new_key] = value
|
92
|
+
end
|
93
|
+
alias store :[]=
|
94
|
+
|
95
|
+
def clear
|
96
|
+
@name_hash.clear
|
97
|
+
@hash.clear
|
98
|
+
end
|
99
|
+
|
100
|
+
def default
|
101
|
+
@default
|
102
|
+
end
|
103
|
+
|
104
|
+
def default=(value)
|
105
|
+
@default = value
|
106
|
+
end
|
107
|
+
|
108
|
+
def default_proc
|
109
|
+
@default_proc
|
110
|
+
end
|
111
|
+
|
112
|
+
def delete(key)
|
113
|
+
new_key = convert_key(key)
|
114
|
+
@name_hash.delete(new_key)
|
115
|
+
@hash.delete(new_key)
|
116
|
+
end
|
117
|
+
|
118
|
+
def delete_if(&block)
|
119
|
+
hash = CICPHash.new
|
120
|
+
each{|key, value| block.call(key, value) ? delete(key) : (hash[key] = value)}
|
121
|
+
hash
|
122
|
+
end
|
123
|
+
|
124
|
+
def each
|
125
|
+
@hash.each{|key, value| yield @name_hash[key], value }
|
126
|
+
end
|
127
|
+
alias each_pair each
|
128
|
+
|
129
|
+
def each_key
|
130
|
+
@hash.each_key{|key| yield @name_hash[key] }
|
131
|
+
end
|
132
|
+
|
133
|
+
def each_value
|
134
|
+
@hash.each_value{|value| yield value }
|
135
|
+
end
|
136
|
+
|
137
|
+
def empty?
|
138
|
+
@hash.empty?
|
139
|
+
end
|
140
|
+
|
141
|
+
def fetch(key, *default, &block)
|
142
|
+
raise ArgumentError, "wrong number of arguments (#{default.length+1} for 2)" if default.length > 1
|
143
|
+
if include?(key)
|
144
|
+
self[key]
|
145
|
+
elsif block_given?
|
146
|
+
block.call(key)
|
147
|
+
elsif default.length == 1
|
148
|
+
default.first
|
149
|
+
else
|
150
|
+
raise IndexError, "key not found"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def has_key?(key)
|
155
|
+
@hash.has_key?(convert_key(key))
|
156
|
+
end
|
157
|
+
alias include? has_key?
|
158
|
+
alias key? has_key?
|
159
|
+
alias member? has_key?
|
160
|
+
|
161
|
+
def has_value?(value)
|
162
|
+
@hash.has_value?(value)
|
163
|
+
end
|
164
|
+
alias value? has_value?
|
165
|
+
|
166
|
+
def index(value)
|
167
|
+
@name_hash[@hash.index(value)]
|
168
|
+
end
|
169
|
+
|
170
|
+
def inspect
|
171
|
+
to_hash.inspect
|
172
|
+
end
|
173
|
+
|
174
|
+
def invert
|
175
|
+
hash = CICPHash.new
|
176
|
+
each{|key, value| hash[value] = key}
|
177
|
+
hash
|
178
|
+
end
|
179
|
+
|
180
|
+
def keys
|
181
|
+
@name_hash.values
|
182
|
+
end
|
183
|
+
|
184
|
+
def length
|
185
|
+
@hash.length
|
186
|
+
end
|
187
|
+
alias size length
|
188
|
+
|
189
|
+
def merge(hash, &block)
|
190
|
+
new_hash = CICPHash.new.merge!(self)
|
191
|
+
hash.each do |key, value|
|
192
|
+
new_hash[key] = if block_given? && new_hash.include?(key)
|
193
|
+
block.call(key, new_hash[key], hash[key])
|
194
|
+
else
|
195
|
+
value
|
196
|
+
end
|
197
|
+
end
|
198
|
+
new_hash
|
199
|
+
end
|
200
|
+
|
201
|
+
def rehash
|
202
|
+
@name_hash.keys.each do |key|
|
203
|
+
new_key = @name_hash[key].to_s.downcase
|
204
|
+
if new_key != key
|
205
|
+
@name_hash[new_key] = @name_hash.delete(key)
|
206
|
+
@hash[new_key] = @hash.delete(key)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
self
|
210
|
+
end
|
211
|
+
|
212
|
+
def reject(&block)
|
213
|
+
hash = CICPHash.new
|
214
|
+
each{|key, value| hash[key] = self[key] unless block.call(key, value)}
|
215
|
+
hash
|
216
|
+
end
|
217
|
+
|
218
|
+
def reject!(&block)
|
219
|
+
hash = CICPHash.new
|
220
|
+
changes = false
|
221
|
+
each{|key, value| block.call(key, value) ? (changes = true; delete(key)) : (hash[key] = value)}
|
222
|
+
changes ? hash : nil
|
223
|
+
end
|
224
|
+
|
225
|
+
def replace(hash)
|
226
|
+
clear
|
227
|
+
update(hash)
|
228
|
+
end
|
229
|
+
|
230
|
+
def select(&block)
|
231
|
+
array = []
|
232
|
+
each{|key, value| array << [key, value] if block.call(key, value)}
|
233
|
+
array
|
234
|
+
end
|
235
|
+
|
236
|
+
def shift
|
237
|
+
return nil if @name_hash.length == 0
|
238
|
+
key, value = @name_hash.shift
|
239
|
+
[value, @hash.delete(key)]
|
240
|
+
end
|
241
|
+
|
242
|
+
def sort(&block)
|
243
|
+
block_given? ? to_a.sort(&block) : to_a.sort
|
244
|
+
end
|
245
|
+
|
246
|
+
def to_a
|
247
|
+
array = []
|
248
|
+
each{|key, value| array << [key, value]}
|
249
|
+
array
|
250
|
+
end
|
251
|
+
|
252
|
+
def to_hash
|
253
|
+
hash = {}
|
254
|
+
each{|key, value| hash[key] = value}
|
255
|
+
hash
|
256
|
+
end
|
257
|
+
|
258
|
+
def to_s
|
259
|
+
to_a.join
|
260
|
+
end
|
261
|
+
|
262
|
+
def update(hash, &block)
|
263
|
+
hash.each do |key, value|
|
264
|
+
self[key] = if block_given? && include?(key)
|
265
|
+
block.call(key, self[key], hash[key])
|
266
|
+
else
|
267
|
+
value
|
268
|
+
end
|
269
|
+
end
|
270
|
+
self
|
271
|
+
end
|
272
|
+
alias merge! update
|
273
|
+
|
274
|
+
def values
|
275
|
+
@hash.values
|
276
|
+
end
|
277
|
+
|
278
|
+
def values_at(*keys)
|
279
|
+
keys.collect{|key| self[key]}
|
280
|
+
end
|
281
|
+
alias indexes values_at
|
282
|
+
alias indices values_at
|
283
|
+
|
284
|
+
private
|
285
|
+
def convert_key(key)
|
286
|
+
key.to_s.downcase
|
287
|
+
end
|
288
|
+
end
|
@@ -0,0 +1,401 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require 'cicphash'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
class CICPHashTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@h = CICPHash[]
|
9
|
+
@fh = CICPHash['AB'=>1, :cd=>2, 3=>4]
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_constructors_and_equality
|
13
|
+
# Test CICPHash.[]
|
14
|
+
assert_equal Hash[], CICPHash[]
|
15
|
+
assert_equal Hash[1=>2], CICPHash[1=>2]
|
16
|
+
assert_equal Hash[1=>2, 3=>4], CICPHash[1=>2, 3=>4]
|
17
|
+
assert_equal Hash[1,2,3,4], CICPHash[1,2,3,4]
|
18
|
+
assert_equal Hash[:ab,:c,:de,:f], CICPHash[:ab,:c,:de,:f]
|
19
|
+
assert_not_equal Hash[:AB,:c,:de,:f], CICPHash[:ab,:c,:de,:f]
|
20
|
+
assert_raises(ArgumentError){CICPHash[1]}
|
21
|
+
assert_raises(ArgumentError){CICPHash[1,2,3]}
|
22
|
+
|
23
|
+
# Test CICPHash.new
|
24
|
+
h, ch = Hash.new, CICPHash.new
|
25
|
+
assert_equal h, ch
|
26
|
+
h, ch = Hash.new(1), CICPHash.new(1)
|
27
|
+
assert_equal h, ch
|
28
|
+
assert_equal h[3], ch[3]
|
29
|
+
h[3], ch[3] = [2, 2]
|
30
|
+
assert_equal h[3], ch[3]
|
31
|
+
h, ch = Hash.new{|h,k| k*2}, CICPHash.new{|h,k| k*2}
|
32
|
+
assert_equal h[3], ch[3]
|
33
|
+
h[3], ch[3] = [2, 2]
|
34
|
+
assert_equal h[3], ch[3]
|
35
|
+
assert_raises(ArgumentError){CICPHash.new(1){|hash,k| key}}
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_latest_assignment_wins
|
39
|
+
assert_equal Hash[], @h
|
40
|
+
@h['a'] = 1
|
41
|
+
assert_equal Hash['a'=>1], @h
|
42
|
+
@h['A'] = 2
|
43
|
+
assert_equal Hash['A'=>2], @h
|
44
|
+
@h[:ab] = 3
|
45
|
+
assert_equal Hash['A'=>2, :ab=>3], @h
|
46
|
+
@h['AB'] = 4
|
47
|
+
assert_equal Hash['A'=>2, 'AB'=>4], @h
|
48
|
+
@h[1] = 5
|
49
|
+
assert_equal Hash['A'=>2, 'AB'=>4, 1=>5], @h
|
50
|
+
@h['1'] = 6
|
51
|
+
assert_equal Hash['A'=>2, 'AB'=>4, '1'=>6], @h
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_store_and_retrieve
|
55
|
+
assert_equal nil, @h[1]
|
56
|
+
@h[1] = 2
|
57
|
+
assert_equal 2, @h[1]
|
58
|
+
assert_equal 2, @h[:'1']
|
59
|
+
assert_equal 2, @h['1']
|
60
|
+
assert_equal 2, @h[[1]]
|
61
|
+
@h['a'] = 3
|
62
|
+
assert_equal 3, @h['a']
|
63
|
+
assert_equal 3, @h['A']
|
64
|
+
assert_equal 3, @h[:a]
|
65
|
+
assert_equal 3, @h[:A]
|
66
|
+
assert_equal 3, @h[[:A]]
|
67
|
+
@h['AB'] = 5
|
68
|
+
assert_equal 5, @h['ab']
|
69
|
+
assert_equal 5, @h['AB']
|
70
|
+
assert_equal 5, @h['aB']
|
71
|
+
assert_equal 5, @h['Ab']
|
72
|
+
assert_equal 5, @h[:ab]
|
73
|
+
assert_equal 5, @h[:AB]
|
74
|
+
assert_equal 5, @h[:aB]
|
75
|
+
assert_equal 5, @h[:Ab]
|
76
|
+
assert_equal 5, @h[[:ab]]
|
77
|
+
@h[[['A'],[:b],[[['cD']]]]] = 6
|
78
|
+
assert_equal 6, @h['abcd']
|
79
|
+
assert_equal 6, @h['ABCD']
|
80
|
+
assert_equal 6, @h[:AbCd]
|
81
|
+
assert_equal 6, @h[:aBcD]
|
82
|
+
assert_equal 6, @h[[[:A],['b'],:C,[[['d']]]]]
|
83
|
+
@h.store(7, 8)
|
84
|
+
assert_equal 8, @h[7]
|
85
|
+
assert_equal 8, @h[:'7']
|
86
|
+
assert_equal 8, @h['7']
|
87
|
+
assert_equal 8, @h[[7]]
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_clear
|
91
|
+
assert_equal 3, @fh.length
|
92
|
+
@fh.clear
|
93
|
+
assert_equal Hash[], @fh
|
94
|
+
assert_equal 0, @fh.length
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_defaults
|
98
|
+
assert_equal nil, @fh.default
|
99
|
+
assert_equal nil, @fh.default_proc
|
100
|
+
assert_equal nil, @fh[55]
|
101
|
+
assert_equal 3, CICPHash.new(3).default
|
102
|
+
assert_equal nil, CICPHash.new(3).default_proc
|
103
|
+
assert_equal 3, CICPHash.new(3)[1]
|
104
|
+
|
105
|
+
@fh.default = 4
|
106
|
+
assert_equal 4, @fh.default
|
107
|
+
assert_equal nil, @fh.default_proc
|
108
|
+
assert_equal 4, @fh[55]
|
109
|
+
|
110
|
+
h = CICPHash.new(5)
|
111
|
+
assert_equal 5, h.default
|
112
|
+
assert_equal nil, h.default_proc
|
113
|
+
assert_equal 5, h[55]
|
114
|
+
|
115
|
+
h = CICPHash.new{|hash, key| 1234}
|
116
|
+
assert_equal nil, h.default
|
117
|
+
assert_not_equal nil, h.default_proc
|
118
|
+
assert_equal 1234, h[55]
|
119
|
+
|
120
|
+
h = CICPHash.new{|hash, key| hash[key] = 1234; nil}
|
121
|
+
assert_equal nil, h.default
|
122
|
+
assert_not_equal nil, h.default_proc
|
123
|
+
assert_equal nil, h[55]
|
124
|
+
assert_equal 1234, h[55]
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_delete
|
128
|
+
assert_equal 3, @fh.length
|
129
|
+
assert_equal 1, @fh.delete(:ab)
|
130
|
+
assert_equal 2, @fh.length
|
131
|
+
assert_equal nil, @fh.delete(:ab)
|
132
|
+
assert_equal 2, @fh.length
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_delete_if_and_reject
|
136
|
+
assert_equal 3, @fh.length
|
137
|
+
hash = @fh.reject{|key, value| key.to_s.length >= 2}
|
138
|
+
assert_equal 1, hash.length
|
139
|
+
assert_equal Hash[3=>4], hash
|
140
|
+
assert_equal 3, @fh.length
|
141
|
+
hash = @fh.delete_if{|key, value| key.to_s.length >= 2}
|
142
|
+
assert_equal 1, hash.length
|
143
|
+
assert_equal Hash[3=>4], hash
|
144
|
+
assert_equal 1, @fh.length
|
145
|
+
assert_equal Hash[3=>4], @fh
|
146
|
+
assert_equal nil, @fh.reject!{|key, value| key.to_s.length >= 2}
|
147
|
+
hash = @fh.reject!{|key, value| key.to_s.length == 1}
|
148
|
+
assert_equal 0, hash.length
|
149
|
+
assert_equal Hash[], hash
|
150
|
+
assert_equal 0, @fh.length
|
151
|
+
assert_equal Hash[], @fh
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_each
|
155
|
+
i = 0
|
156
|
+
@h.each{i+=1}
|
157
|
+
assert_equal 0, i
|
158
|
+
items = [['AB',1], [:cd,2], [3,4]]
|
159
|
+
@fh.each do |k,v|
|
160
|
+
assert items.include?([k,v])
|
161
|
+
items -= [[k,v]]
|
162
|
+
end
|
163
|
+
assert_equal [], items
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_each_key
|
167
|
+
i = 0
|
168
|
+
@h.each{i+=1}
|
169
|
+
assert_equal 0, i
|
170
|
+
keys = ['AB', :cd, 3]
|
171
|
+
@fh.each_key do |k|
|
172
|
+
assert keys.include?(k)
|
173
|
+
keys -= [k]
|
174
|
+
end
|
175
|
+
assert_equal [], keys
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_each_value
|
179
|
+
i = 0
|
180
|
+
@h.each{i+=1}
|
181
|
+
assert_equal 0, i
|
182
|
+
values = [1, 2, 4]
|
183
|
+
@fh.each_value do |v|
|
184
|
+
assert values.include?(v)
|
185
|
+
values -= [v]
|
186
|
+
end
|
187
|
+
assert_equal [], values
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_empty
|
191
|
+
assert @h.empty?
|
192
|
+
assert !@fh.empty?
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_fetch
|
196
|
+
assert_raises(ArgumentError){@h.fetch(1,2,3)}
|
197
|
+
assert_raises(ArgumentError){@h.fetch(1,2,3){4}}
|
198
|
+
assert_raises(IndexError){@h.fetch(1)}
|
199
|
+
@h.default = 33
|
200
|
+
assert_raises(IndexError){@h.fetch(1)}
|
201
|
+
@h[1] = 2
|
202
|
+
assert_equal 2, @h.fetch(1)
|
203
|
+
assert_equal 3, @h.fetch(2, 3)
|
204
|
+
assert_equal 4, @h.fetch(2, 3){4}
|
205
|
+
assert_equal 6, @h.fetch(2, 3){|k| k*3}
|
206
|
+
assert_equal 1, @fh.fetch(:ab)
|
207
|
+
assert_equal 2, @fh.fetch(:CD, 3)
|
208
|
+
assert_equal 4, @fh.fetch([3], 3){8}
|
209
|
+
assert_equal 4, @fh.fetch([3], 3){|k| k*3}
|
210
|
+
assert_raises(IndexError){CICPHash.new{34}.fetch(1)}
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_has_key
|
214
|
+
'include? has_key? key? member?'.split.each do |meth|
|
215
|
+
assert !@h.send(meth,1)
|
216
|
+
assert @fh.send(meth,'AB')
|
217
|
+
assert @fh.send(meth,:cd)
|
218
|
+
assert @fh.send(meth,3)
|
219
|
+
assert @fh.send(meth,:ab)
|
220
|
+
assert @fh.send(meth,'CD')
|
221
|
+
assert @fh.send(meth,[[[3]]])
|
222
|
+
assert !@fh.send(meth,1)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_has_value
|
227
|
+
'value? has_value?'.split.each do |meth|
|
228
|
+
assert !@h.send(meth,1)
|
229
|
+
assert @fh.send(meth,1)
|
230
|
+
assert @fh.send(meth,2)
|
231
|
+
assert @fh.send(meth,4)
|
232
|
+
assert !@fh.send(meth,3)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_index
|
237
|
+
assert_equal nil, @h.index(1)
|
238
|
+
assert_equal 'AB', @fh.index(1)
|
239
|
+
assert_equal :cd, @fh.index(2)
|
240
|
+
assert_equal nil, @fh.index(3)
|
241
|
+
assert_equal 3, @fh.index(4)
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_inspect_and_to_s
|
245
|
+
assert_equal '{}', CICPHash[].inspect
|
246
|
+
assert_equal '', CICPHash[].to_s
|
247
|
+
assert_equal '{1=>2}', CICPHash[1=>2].inspect
|
248
|
+
assert_equal '12', CICPHash[1=>2].to_s
|
249
|
+
assert ['{:ab=>"CD", [:"3"]=>4}', '{[:"3"]=>4, :ab=>"CD"}'].include?(CICPHash[:ab=>'CD', [:'3']=>4].inspect)
|
250
|
+
assert ['abCD34', '34abCD'].include?(CICPHash[:ab=>'CD', [:'3']=>4].to_s)
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_invert
|
254
|
+
assert_equal Hash[].invert, CICPHash[].invert
|
255
|
+
assert_equal Hash[1=>2].invert, CICPHash[1=>2].invert
|
256
|
+
assert_equal Hash[1=>2, 3=>4].invert, CICPHash[1=>2, 3=>4].invert
|
257
|
+
assert_equal Hash[1,2,3,4].invert, CICPHash[1,2,3,4].invert
|
258
|
+
assert_equal Hash[:ab,:c,:de,:f].invert, CICPHash[:ab,:c,:de,:f].invert
|
259
|
+
assert_not_equal Hash[:ab,:c,:de,:f].invert, CICPHash[:aB,:c,:de,:f].invert
|
260
|
+
assert [{2=>1},{2=>3}].include?(CICPHash[1,2,3,2].invert)
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_keys
|
264
|
+
assert_equal [], @h.keys
|
265
|
+
assert [[:aB, 1],[1, :aB]].include?(CICPHash[:aB,:c,1,:f].keys)
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_length
|
269
|
+
assert_equal 0, @h.length
|
270
|
+
assert_equal 0, @h.size
|
271
|
+
assert_equal 3, @fh.length
|
272
|
+
assert_equal 3, @fh.size
|
273
|
+
@h[1] = 2
|
274
|
+
assert_equal 1, @h.length
|
275
|
+
assert_equal 1, @h.size
|
276
|
+
@fh.delete(:AB)
|
277
|
+
assert_equal 2, @fh.length
|
278
|
+
assert_equal 2, @fh.size
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_merge_and_update
|
282
|
+
assert_equal @h, @h.merge({})
|
283
|
+
assert_equal @fh, @fh.merge({})
|
284
|
+
assert_equal CICPHash[:ab=>55], @h.merge({:ab=>55})
|
285
|
+
assert_equal CICPHash[], @h
|
286
|
+
assert_equal CICPHash[:ab=>55], @h.update({:ab=>55})
|
287
|
+
assert_equal CICPHash[:ab=>55], @h
|
288
|
+
assert_equal CICPHash[:ab=>55, :cd=>2, 3=>4], @fh.merge({:ab=>55})
|
289
|
+
assert_equal CICPHash['AB'=>1, :cd=>2, 3=>4], @fh
|
290
|
+
assert_equal CICPHash[:ab=>55, :cd=>2, 3=>4], @fh.merge!({:ab=>55})
|
291
|
+
assert_equal CICPHash[:ab=>55, :cd=>2, 3=>4], @fh
|
292
|
+
assert_equal CICPHash[:ab=>'abss55', :cd=>2, 3=>4], @fh.merge({:ab=>'ss'}){|k,ov,nv| [k,nv,ov].join}
|
293
|
+
assert_equal CICPHash[:ab=>55, :cd=>2, 3=>4], @fh
|
294
|
+
assert_equal CICPHash[:ab=>'abss55', :cd=>2, 3=>4], @fh.update({:ab=>'ss'}){|k,ov,nv| [k,nv,ov].join}
|
295
|
+
assert_equal CICPHash[:ab=>'abss55', :cd=>2, 3=>4], @fh
|
296
|
+
assert_equal CICPHash[:ab=>'abssabss55', :cd=>2, 3=>4], @fh.merge!({:ab=>'ss'}){|k,ov,nv| [k,nv,ov].join}
|
297
|
+
assert_equal CICPHash[:ab=>'abssabss55', :cd=>2, 3=>4], @fh
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_update
|
301
|
+
assert_equal Hash[], @h.update({})
|
302
|
+
assert_equal Hash[:ab,2], @h.update({:ab=>2})
|
303
|
+
assert_equal Hash[:ab,2], @h
|
304
|
+
assert_equal Hash['AB',2], @h.update({'AB'=>2})
|
305
|
+
assert_equal Hash['AB',2], @h
|
306
|
+
assert_equal Hash[[:a,:B],3,4,5], @h.update([:a,:B]=>3, 4=>5) do |k,ov,nv|
|
307
|
+
asset_equal [:a,:B], k
|
308
|
+
asset_equal 2, ov
|
309
|
+
asset_equal 3, nv
|
310
|
+
end
|
311
|
+
assert_equal Hash[[:a,:B],3,4,5], @h
|
312
|
+
end
|
313
|
+
|
314
|
+
def test_rehash
|
315
|
+
assert_equal @h, @h.rehash
|
316
|
+
assert_equal @fh, @fh.rehash
|
317
|
+
x = 'BLAH'
|
318
|
+
@fh[x] = 23
|
319
|
+
assert_equal CICPHash['AB'=>1, :cd=>2, 3=>4, 'BLAH'=>23], @fh
|
320
|
+
assert_equal CICPHash['AB'=>1, :cd=>2, 3=>4, 'BLAH'=>23], @fh.rehash
|
321
|
+
x.downcase!
|
322
|
+
assert_equal CICPHash['AB'=>1, :cd=>2, 3=>4, 'blah'=>23], @fh
|
323
|
+
assert_equal CICPHash['AB'=>1, :cd=>2, 3=>4, 'blah'=>23], @fh.rehash
|
324
|
+
x.replace("DIFF")
|
325
|
+
assert_equal 23, @fh['blah']
|
326
|
+
assert_equal nil, @fh['DIFF']
|
327
|
+
assert_equal CICPHash['AB'=>1, :cd=>2, 3=>4, 'DIFF'=>23], @fh
|
328
|
+
assert_equal CICPHash['AB'=>1, :cd=>2, 3=>4, 'DIFF'=>23], @fh.rehash
|
329
|
+
assert_equal nil, @fh['blah']
|
330
|
+
assert_equal 23, @fh['DIFF']
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_replace
|
334
|
+
assert_equal @h, @h.replace(@h)
|
335
|
+
assert_equal @fh, @fh.replace(@fh)
|
336
|
+
assert_equal @fh, @h.replace(@fh)
|
337
|
+
assert_equal Hash[], @fh.replace(Hash[])
|
338
|
+
end
|
339
|
+
|
340
|
+
def test_select
|
341
|
+
assert_equal [], @h.select{true}
|
342
|
+
assert_equal [], @h.select{false}
|
343
|
+
assert_equal [[3,4], ['AB',1], [:cd,2]], @fh.select{true}.sort_by{|x| x.to_s}
|
344
|
+
assert_equal [], @fh.select{false}
|
345
|
+
assert_equal [[:cd,2]], @fh.select{|k,v| k.is_a?(Symbol)}
|
346
|
+
assert_equal [[3,4]], @fh.select{|k,v| v == 4}
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_shift
|
350
|
+
assert_equal nil, @h.shift
|
351
|
+
array = @fh.to_a
|
352
|
+
i = 3
|
353
|
+
loop do
|
354
|
+
assert i >= 0
|
355
|
+
kv = @fh.shift
|
356
|
+
if kv.nil?
|
357
|
+
assert_equal [], array
|
358
|
+
break
|
359
|
+
else
|
360
|
+
i -= 1
|
361
|
+
assert array.include?(kv)
|
362
|
+
array -= [kv]
|
363
|
+
end
|
364
|
+
end
|
365
|
+
assert_equal [], array
|
366
|
+
assert_equal 0, i
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_sort
|
370
|
+
assert_equal [], @h.sort
|
371
|
+
assert_equal [], @h.sort{|a,b| a.to_s<=>b.to_s}
|
372
|
+
assert_equal [['AB',1], ['CD',4], ['EF',2]], CICPHash['CD',4,'AB',1,'EF',2].sort
|
373
|
+
assert_equal [[3,4], ['AB',1], [:cd,2]], @fh.sort{|a,b| a.to_s<=>b.to_s}
|
374
|
+
end
|
375
|
+
|
376
|
+
def test_to_a
|
377
|
+
assert_equal [], @h.to_a
|
378
|
+
assert_equal [[3,4], ['AB',1], [:cd,2]], @fh.to_a.sort{|a,b| a.to_s<=>b.to_s}
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_to_hash
|
382
|
+
assert_equal Hash[], @h.to_hash
|
383
|
+
assert_equal Hash[3,4,'AB',1,:cd,2], @fh.to_hash
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_values
|
387
|
+
assert_equal [], @h.values
|
388
|
+
assert_equal [:c, :f], CICPHash[:aB,:f,1,:c].values.sort_by{|x|x.to_s}
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_values_at
|
392
|
+
assert_equal [], @h.values_at()
|
393
|
+
assert_equal [nil], @h.values_at(1)
|
394
|
+
assert_equal [nil, nil], @h.values_at(1, 1)
|
395
|
+
assert_equal [], @fh.values_at()
|
396
|
+
assert_equal [1], @fh.values_at(:ab)
|
397
|
+
assert_equal [2, 1], @fh.values_at('CD', :ab)
|
398
|
+
assert_equal [2, nil, 1], @fh.values_at('CD', 32, :ab)
|
399
|
+
assert_equal [4, 2, nil, 1], @fh.values_at([[[3]],''], 'CD', 32, :ab)
|
400
|
+
end
|
401
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: cicphash
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2007-08-12 00:00:00 -07:00
|
8
|
+
summary: Case Insensitive Cash Preserving Hash
|
9
|
+
require_paths:
|
10
|
+
- .
|
11
|
+
email: code@jeremyevans.net
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: cicphash
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Jeremy Evans
|
31
|
+
files:
|
32
|
+
- cicphash.rb
|
33
|
+
test_files:
|
34
|
+
- test/test_cicphash.rb
|
35
|
+
rdoc_options: []
|
36
|
+
|
37
|
+
extra_rdoc_files: []
|
38
|
+
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
requirements: []
|
44
|
+
|
45
|
+
dependencies: []
|
46
|
+
|