insensitive_hash 0.2.2 → 0.2.3

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/CHANGELOG.markdown CHANGED
@@ -1,3 +1,7 @@
1
+ ### 0.2.3 / 2012/02/18
2
+ * Key-clash detection made optional with `Insensitive#safe=`
3
+ * Ruby 1.8 compatibility
4
+
1
5
  ### 0.2.2 / 2012/02/13
2
6
  * :underscore option added
3
7
  * `Insensitive::KeyClashError` added for safer operations
@@ -11,6 +11,7 @@ class InsensitiveHash < Hash
11
11
 
12
12
  @key_map = {}
13
13
  @underscore = false
14
+ @safe = false
14
15
  end
15
16
 
16
17
  # Sets whether to replace spaces in String keys to underscores
@@ -35,6 +36,19 @@ class InsensitiveHash < Hash
35
36
  def underscore?
36
37
  @underscore
37
38
  end
39
+
40
+ # Sets whether to detect key clashes
41
+ # @param [Boolean]
42
+ # @return [Boolean]
43
+ def safe= s
44
+ raise ArgumentError.new("Not true or false") unless [true, false].include?(s)
45
+ @safe = s
46
+ end
47
+
48
+ # @return [Boolean] Key-clash detection enabled?
49
+ def safe?
50
+ @safe
51
+ end
38
52
 
39
53
  # Returns a normal, sensitive Hash
40
54
  # @return [Hash]
@@ -95,19 +109,18 @@ class InsensitiveHash < Hash
95
109
  end
96
110
 
97
111
  def replace other
112
+ super other
113
+
98
114
  # TODO
99
115
  # What is the correct behavior of replace when the other hash is not an InsensitiveHash?
100
116
  # underscore property precedence: other => self (FIXME)
101
- us = other.respond_to?(:underscore?) ? other.underscore? : self.underscore?
102
- detect_clash other, us
117
+ self.underscore = other.respond_to?(:underscore?) ? other.underscore? : self.underscore?
118
+ self.safe = other.safe? if other.respond_to?(:safe?)
103
119
 
104
- self.default = other.default
105
- self.default_proc = other.default_proc if other.default_proc
106
- self.underscore = us
107
-
108
- clear
109
- other.each do |k, v|
110
- self[k] = v
120
+ @key_map.clear
121
+ self.each do |k, v|
122
+ ekey = encode k, @underscore
123
+ @key_map[ekey] = k
111
124
  end
112
125
  end
113
126
 
@@ -166,7 +179,7 @@ private
166
179
  def detect_clash hash, us
167
180
  hash.keys.map { |k| encode k, us }.tap { |ekeys|
168
181
  raise KeyClashError.new("Key clash detected") if ekeys != ekeys.uniq
169
- }
182
+ } if @safe
170
183
  end
171
184
  end
172
185
 
@@ -1,3 +1,3 @@
1
1
  class InsensitiveHash < Hash
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -6,6 +6,20 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
6
  require 'insensitive_hash/minimal'
7
7
 
8
8
  class TestInsensitiveHash < Test::Unit::TestCase
9
+ def eight?
10
+ RUBY_VERSION =~ /^1\.8\./
11
+ end
12
+
13
+ def assert_keys set1, set2
14
+ if eight?
15
+ assert_equal set1.sort { |a, b| a.to_s <=> b.to_s },
16
+ set2.sort { |a, b| a.to_s <=> b.to_s }
17
+ else
18
+ assert_equal set1, set2
19
+ end
20
+
21
+ end
22
+
9
23
  def test_has_key_set
10
24
  ih = InsensitiveHash.new
11
25
  ih['a'] = 1
@@ -19,12 +33,11 @@ class TestInsensitiveHash < Test::Unit::TestCase
19
33
  assert_equal 2, ih[a]
20
34
  end
21
35
 
22
- assert_equal ['A'], ih.keys
36
+ assert_keys ['A'], ih.keys
23
37
  assert_equal [2], ih.values
24
38
 
25
39
  ih[:A] = 4
26
- assert_equal ih.keys, [:A]
27
- assert_equal [:A], ih.keys
40
+ assert_keys [:A], ih.keys
28
41
  assert_equal [4], ih.values
29
42
 
30
43
  ih[:b] = { :c => 5 }
@@ -91,14 +104,16 @@ class TestInsensitiveHash < Test::Unit::TestCase
91
104
  end
92
105
 
93
106
  # Preserving default_proc
94
- hash2 = {}
95
- hash2.replace hash
96
- hash2.default_proc = proc { |h, k| h[k] = :default }
97
-
98
- ihash2 = hash2.insensitive.insensitive.insensitive
99
- assert !ihash2.has_key?(:anything)
100
- assert_equal :default, ihash2[:anything]
101
- assert ihash2.has_key?(:anything)
107
+ unless eight?
108
+ hash2 = {}
109
+ hash2.replace hash
110
+ hash2.default_proc = proc { |h, k| h[k] = :default }
111
+
112
+ ihash2 = hash2.insensitive.insensitive.insensitive
113
+ assert !ihash2.has_key?(:anything)
114
+ assert_equal :default, ihash2[:anything]
115
+ assert ihash2.has_key?(:anything)
116
+ end
102
117
 
103
118
  # FIXME: test insensitive call with encoder
104
119
  h = InsensitiveHash[{'Key with spaces' => 1}]
@@ -145,8 +160,8 @@ class TestInsensitiveHash < Test::Unit::TestCase
145
160
  ih = InsensitiveHash[:a => 1, 'hello world' => 2]
146
161
  ih2 = ih.send(method, :b => 2)
147
162
 
148
- assert_equal [:a, 'hello world'], ih.keys
149
- assert_equal [:a, 'hello world', :b], ih2.keys
163
+ assert_keys [:a, 'hello world'], ih.keys
164
+ assert_keys [:a, 'hello world', :b], ih2.keys
150
165
  assert ih2.has_key?('B'), 'correctly merged another hash'
151
166
 
152
167
  assert_nil ih[:hello_world]
@@ -166,11 +181,13 @@ class TestInsensitiveHash < Test::Unit::TestCase
166
181
  ih.default = nil
167
182
  assert_nil ih.send(method, :b => 2)[:anything]
168
183
 
169
- ih.default_proc = proc { |h, k| h[k] = :default }
170
- mh = ih.send(method, :b => 2)
171
- assert !mh.has_key?(:anything)
172
- assert_equal :default, mh[:anything]
173
- assert mh.has_key?(:anything)
184
+ unless eight?
185
+ ih.default_proc = proc { |h, k| h[k] = :default }
186
+ mh = ih.send(method, :b => 2)
187
+ assert !mh.has_key?(:anything)
188
+ assert_equal :default, mh[:anything]
189
+ assert mh.has_key?(:anything)
190
+ end
174
191
 
175
192
  ih2.delete 'b'
176
193
  assert ih2.has_key?('B') == false
@@ -182,8 +199,8 @@ class TestInsensitiveHash < Test::Unit::TestCase
182
199
  ih = InsensitiveHash[:a => 1]
183
200
  ih2 = ih.send(method, :b => 2)
184
201
 
185
- assert_equal [:a, :b], ih.keys
186
- assert_equal [:a, :b], ih2.keys
202
+ assert_keys [:a, :b], ih.keys
203
+ assert_keys [:a, :b], ih2.keys
187
204
  assert ih2.has_key?('B'), 'correctly merged another hash'
188
205
 
189
206
  ih2.delete 'b'
@@ -191,13 +208,46 @@ class TestInsensitiveHash < Test::Unit::TestCase
191
208
  end
192
209
  end
193
210
 
211
+ def test_merge_clash_overwritten
212
+ ih = InsensitiveHash.new
213
+
214
+ ih = ih.merge(:a => 1, :A =>2)
215
+ # No guarantee in order in 1.8
216
+ unless eight?
217
+ assert_equal 2, ih.values.first
218
+ assert_equal 2, ih['A']
219
+ end
220
+ assert_equal 1, ih.length
221
+
222
+ ih = InsensitiveHash.new
223
+ ih.underscore = true
224
+ ih.merge!(:hello_world => 1, 'hello world' =>2)
225
+ unless eight?
226
+ assert_equal 2, ih.values.first
227
+ assert_equal 2, ih[:Hello_World]
228
+ end
229
+ assert_equal 1, ih.length
230
+ end
231
+
194
232
  def test_merge_clash
195
233
  ih = InsensitiveHash.new
196
234
  ih2 = InsensitiveHash.new
197
235
  ih2.underscore = true
198
236
 
237
+ sih = InsensitiveHash.new
238
+ sih.safe = true
239
+ sih2 = InsensitiveHash.new
240
+ sih2.safe = true
241
+ sih2.underscore = true
242
+
199
243
  [:merge, :merge!, :update, :update!].each do |method|
244
+ # No problem
200
245
  [ih, ih2].each do |h|
246
+ h.send(method, { :a => 1, :A => 1, 'A' => 1})
247
+ h.send(method, { 'a' => 1, 'A' => 1 })
248
+ end
249
+
250
+ [sih, sih2].each do |h|
201
251
  assert_raise(InsensitiveHash::KeyClashError) {
202
252
  h.send(method, { :a => 1, :A => 1, 'A' => 1})
203
253
  }
@@ -206,18 +256,22 @@ class TestInsensitiveHash < Test::Unit::TestCase
206
256
  }
207
257
  end
208
258
 
209
- ih.send(method, { :hello_world => 1, 'hello world' => 2})
259
+ sih.send(method, { :hello_world => 1, 'hello world' => 2})
210
260
  assert_raise(InsensitiveHash::KeyClashError) {
211
- ih2.send(method, { :hello_world => 1, 'hello world' => 2})
261
+ sih2.send(method, { :hello_world => 1, 'hello world' => 2})
212
262
  }
263
+ ih2.send(method, { :hello_world => 1, 'hello world' => 2})
213
264
  end
214
265
 
266
+ ih.merge({ :a => 1, :A => 1, 'A' => 1})
215
267
  assert_raise(InsensitiveHash::KeyClashError) {
216
- ih.merge({ :a => 1, :A => 1, 'A' => 1})
268
+ sih.merge({ :a => 1, :A => 1, 'A' => 1})
217
269
  }
218
270
  end
219
271
 
220
272
  def test_assoc
273
+ pend "1.8" if eight?
274
+
221
275
  h = InsensitiveHash[{
222
276
  "colors" => ["red", "blue", "green"],
223
277
  :Letters => ["a", "b", "c" ]
@@ -308,7 +362,7 @@ class TestInsensitiveHash < Test::Unit::TestCase
308
362
  # FIXME: Test passes, but key_map not updated
309
363
  h = InsensitiveHash[ :a => 100, :tmp_a => 200, :c => 300 ]
310
364
  h.delete_if.each { |k, v| k == :tmp_a }
311
- assert_equal [:a, :c], h.keys
365
+ assert_keys [:a, :c], h.keys
312
366
  end
313
367
 
314
368
  def test_has_key_after_delete
@@ -316,7 +370,7 @@ class TestInsensitiveHash < Test::Unit::TestCase
316
370
  h = InsensitiveHash[ :a => 1, :b => 2 ]
317
371
 
318
372
  set.each { |s| assert h.has_key?(s) }
319
- h.delete_if { |e| true }
373
+ h.delete_if { |k, v| true }
320
374
  set.each { |s| assert !h.has_key?(s) }
321
375
  end
322
376
 
@@ -368,11 +422,6 @@ class TestInsensitiveHash < Test::Unit::TestCase
368
422
  assert h.underscore?
369
423
  assert_equal 1, h[:hello_world]
370
424
 
371
- h = InsensitiveHash.new
372
- assert_raise(InsensitiveHash::KeyClashError) {
373
- h.replace({ 'a' => 1, :A => 2 })
374
- }
375
-
376
425
  # TODO: FIXME
377
426
  # underscore property of other
378
427
  h = InsensitiveHash.new
@@ -389,6 +438,8 @@ class TestInsensitiveHash < Test::Unit::TestCase
389
438
  end
390
439
 
391
440
  def test_rassoc
441
+ pend "1.8" if eight?
442
+
392
443
  a = InsensitiveHash[{1=> "one", 2 => "two", 3 => "three", "ii" => "two"}]
393
444
  assert_equal [2, "two"], a.rassoc("two")
394
445
  assert_nil a.rassoc("four")
@@ -414,7 +465,7 @@ class TestInsensitiveHash < Test::Unit::TestCase
414
465
  end
415
466
  assert_equal 3, h.fetch(:c, 3)
416
467
  assert_equal 3, h.fetch(:c) { 3 }
417
- assert_raise(KeyError) { h.fetch('D') }
468
+ assert_raise(eight? ? IndexError : KeyError) { h.fetch('D') }
418
469
  end
419
470
 
420
471
  def test_underscore
@@ -506,6 +557,8 @@ class TestInsensitiveHash < Test::Unit::TestCase
506
557
 
507
558
  def test_underscore_clash
508
559
  h = InsensitiveHash.new
560
+ h.safe = true
561
+
509
562
  h['hello world'] = 1
510
563
  h['HELLO_world'] = 2
511
564
  assert_equal 1, h['HELLO WORLD']
@@ -528,7 +581,7 @@ class TestInsensitiveHash < Test::Unit::TestCase
528
581
  h.underscore = false
529
582
  h['hello world'] = 2
530
583
 
531
- assert_equal [:hello_world, 'hello world'], h.keys
584
+ assert_keys [:hello_world, 'hello world'], h.keys
532
585
  assert_equal 2, h['Hello World']
533
586
  end
534
587
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: insensitive_hash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-13 00:00:00.000000000 Z
12
+ date: 2012-02-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: test-unit
16
- requirement: &2152875840 !ruby/object:Gem::Requirement
16
+ requirement: &2160341260 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 2.3.0
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2152875840
24
+ version_requirements: *2160341260
25
25
  description: Hash with case-insensitive, Symbol/String-indifferent key access
26
26
  email:
27
27
  - junegunn.c@gmail.com