insensitive_hash 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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