insensitive_hash 0.3.0 → 0.3.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/CHANGELOG.markdown +3 -0
- data/LICENSE.txt +1 -1
- data/README.markdown +53 -13
- data/insensitive_hash.gemspec +0 -2
- data/lib/insensitive_hash.rb +4 -0
- data/lib/insensitive_hash/insensitive_hash.rb +36 -10
- data/lib/insensitive_hash/version.rb +1 -1
- data/test/test_insensitive_hash.rb +48 -0
- metadata +3 -2
data/CHANGELOG.markdown
CHANGED
data/LICENSE.txt
CHANGED
data/README.markdown
CHANGED
@@ -8,10 +8,10 @@ Installation
|
|
8
8
|
gem install insensitive_hash
|
9
9
|
```
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
Instantiation
|
12
|
+
-------------
|
13
13
|
|
14
|
-
###
|
14
|
+
### Hash#insensitive
|
15
15
|
|
16
16
|
```ruby
|
17
17
|
require 'insensitive_hash'
|
@@ -24,7 +24,7 @@ ih['ABC'] # 1
|
|
24
24
|
ih[:Hello_World] # true
|
25
25
|
```
|
26
26
|
|
27
|
-
###
|
27
|
+
### Without monkey-patching Hash
|
28
28
|
|
29
29
|
If you don't like to have Hash#insensitive method, `require 'insensitive_hash/minimal'`
|
30
30
|
|
@@ -49,7 +49,9 @@ h = ih.sensitive
|
|
49
49
|
h = ih.to_hash
|
50
50
|
```
|
51
51
|
|
52
|
-
|
52
|
+
Basic usage
|
53
|
+
-----------
|
54
|
+
|
53
55
|
```ruby
|
54
56
|
ih = {:abc => 1, 'DEF' => 2}.insensitive
|
55
57
|
|
@@ -71,7 +73,8 @@ ih.delete :Abc # 10
|
|
71
73
|
ih.keys # ['DEF']
|
72
74
|
```
|
73
75
|
|
74
|
-
|
76
|
+
Inherited insensitivity
|
77
|
+
-----------------------
|
75
78
|
|
76
79
|
When InsensitiveHash is built from another Hash,
|
77
80
|
descendant Hash values are recursively converted to be insensitive
|
@@ -86,20 +89,24 @@ ih = {:one => [ [ [ { :a => { :b => { :c => 'd' } } } ] ] ]}.insensitive
|
|
86
89
|
ih['one'].first.first.first['A']['b'][:C] # 'd'
|
87
90
|
```
|
88
91
|
|
89
|
-
|
90
|
-
|
92
|
+
However, once InsensitiveHash is initialized,
|
93
|
+
descendant Hashes are not automatically converted.
|
91
94
|
|
92
95
|
```ruby
|
93
96
|
ih = {}.insensitive
|
94
97
|
ih[:abc] = { :def => true }
|
95
98
|
|
96
99
|
ih['ABC']['DEF'] # nil
|
100
|
+
```
|
101
|
+
|
102
|
+
Simply build a new InsensitiveHash again if you need recursive conversion.
|
97
103
|
|
104
|
+
```ruby
|
98
105
|
ih2 = ih.insensitive
|
99
106
|
ih2['ABC']['DEF'] # true
|
100
107
|
```
|
101
108
|
|
102
|
-
### Processing case-insensitive YAML input
|
109
|
+
### Example: Processing case-insensitive YAML input
|
103
110
|
```ruby
|
104
111
|
db = YAML.load(File.read 'database.yml').insensitive
|
105
112
|
|
@@ -108,7 +115,41 @@ db['Development']['ADAPTER']
|
|
108
115
|
db[:production][:adapter]
|
109
116
|
```
|
110
117
|
|
111
|
-
|
118
|
+
Customizing insensitivity
|
119
|
+
-------------------------
|
120
|
+
|
121
|
+
You can provide a Proc object as the key encoder which determines the level of insensitivity.
|
122
|
+
|
123
|
+
### Default encoder
|
124
|
+
|
125
|
+
The default encoder is as follows.
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
InsensitiveHash::DEFAULT_ENCODER =
|
129
|
+
proc { |key|
|
130
|
+
case key
|
131
|
+
when String, Symbol
|
132
|
+
key.to_s.downcase.gsub(' ', '_')
|
133
|
+
else
|
134
|
+
key
|
135
|
+
end
|
136
|
+
}
|
137
|
+
```
|
138
|
+
|
139
|
+
### Encoder examples
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
h1 = {}.insensitive(:encoder => proc { |key| key.to_s })
|
143
|
+
h2 = {}.insensitive(:encoder => proc { |key| key.to_s.downcase })
|
144
|
+
h3 = {}.insensitive(:encoder => proc { |key| key.to_s.downcase.gsub(/\s+/, '_') })
|
145
|
+
|
146
|
+
# Without `insensitive` method
|
147
|
+
h4 = InsensitiveHash.new
|
148
|
+
h4.encoder = proc { |key| key.to_s }
|
149
|
+
```
|
150
|
+
|
151
|
+
Enabling key-clash detection (Safe mode)
|
152
|
+
----------------------------------------
|
112
153
|
```ruby
|
113
154
|
ih = InsensitiveHash.new
|
114
155
|
ih.safe = true
|
@@ -123,7 +164,7 @@ h['Hello World'] # 2
|
|
123
164
|
```
|
124
165
|
|
125
166
|
## Contributing to insensitive_hash
|
126
|
-
|
167
|
+
|
127
168
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
128
169
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
129
170
|
* Fork the project
|
@@ -134,6 +175,5 @@ h['Hello World'] # 2
|
|
134
175
|
|
135
176
|
## Copyright
|
136
177
|
|
137
|
-
Copyright (c)
|
138
|
-
further details.
|
178
|
+
Copyright (c) 2013 Junegunn Choi. See LICENSE.txt for further details.
|
139
179
|
|
data/insensitive_hash.gemspec
CHANGED
@@ -19,7 +19,5 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
# specify any dependencies here; for example:
|
23
22
|
s.add_development_dependency "test-unit", ">= 2.3.0"
|
24
|
-
# s.add_runtime_dependency "rest-client"
|
25
23
|
end
|
data/lib/insensitive_hash.rb
CHANGED
@@ -2,10 +2,14 @@ require 'insensitive_hash/version'
|
|
2
2
|
require 'insensitive_hash/insensitive_hash'
|
3
3
|
|
4
4
|
class Hash
|
5
|
+
# @param [Hash] options Options
|
6
|
+
# @option options [Boolean] :safe Whether to detect key clash on merge
|
7
|
+
# @option options [Proc] :encoder Key encoding Proc
|
5
8
|
# @return [InsensitiveHash]
|
6
9
|
def insensitive options = {}
|
7
10
|
InsensitiveHash[self].tap do |ih|
|
8
11
|
ih.safe = options[:safe] if options.has_key?(:safe)
|
12
|
+
ih.encoder = options[:encoder] if options.has_key?(:encoder)
|
9
13
|
ih.default = self.default
|
10
14
|
ih.default_proc = self.default_proc if self.default_proc
|
11
15
|
end
|
@@ -1,7 +1,21 @@
|
|
1
|
+
# @author Junegunn Choi <junegunn.c@gmail.com>
|
2
|
+
# @!attribute [r] encoder
|
3
|
+
# @return [Proc] Key encoding Proc
|
1
4
|
class InsensitiveHash < Hash
|
5
|
+
attr_reader :encoder
|
6
|
+
|
2
7
|
class KeyClashError < Exception
|
3
8
|
end
|
4
9
|
|
10
|
+
DEFAULT_ENCODER = proc { |key|
|
11
|
+
case key
|
12
|
+
when String, Symbol
|
13
|
+
key.to_s.downcase.gsub(' ', '_')
|
14
|
+
else
|
15
|
+
key
|
16
|
+
end
|
17
|
+
}
|
18
|
+
|
5
19
|
def initialize default = nil, &block
|
6
20
|
if block_given?
|
7
21
|
raise ArgumentError.new('wrong number of arguments') unless default.nil?
|
@@ -10,12 +24,13 @@ class InsensitiveHash < Hash
|
|
10
24
|
super
|
11
25
|
end
|
12
26
|
|
13
|
-
@key_map
|
14
|
-
@safe
|
27
|
+
@key_map = {}
|
28
|
+
@safe = false
|
29
|
+
@encoder = DEFAULT_ENCODER
|
15
30
|
end
|
16
31
|
|
17
32
|
# Sets whether to detect key clashes
|
18
|
-
# @param [Boolean]
|
33
|
+
# @param [Boolean]
|
19
34
|
# @return [Boolean]
|
20
35
|
def safe= s
|
21
36
|
raise ArgumentError.new("Neither true nor false") unless [true, false].include?(s)
|
@@ -26,7 +41,22 @@ class InsensitiveHash < Hash
|
|
26
41
|
def safe?
|
27
42
|
@safe
|
28
43
|
end
|
29
|
-
|
44
|
+
|
45
|
+
# @param [Proc] prc Key encoding Proc
|
46
|
+
# @return [Proc]
|
47
|
+
def encoder= prc
|
48
|
+
raise ArgumentError, "Proc object required" unless prc.is_a?(Proc)
|
49
|
+
|
50
|
+
kvs = to_a
|
51
|
+
clear
|
52
|
+
@encoder = prc
|
53
|
+
kvs.each do |pair|
|
54
|
+
store *pair
|
55
|
+
end
|
56
|
+
|
57
|
+
prc
|
58
|
+
end
|
59
|
+
|
30
60
|
# Returns a normal, sensitive Hash
|
31
61
|
# @return [Hash]
|
32
62
|
def to_hash
|
@@ -87,6 +117,7 @@ class InsensitiveHash < Hash
|
|
87
117
|
super other
|
88
118
|
|
89
119
|
self.safe = other.respond_to?(:safe?) ? other.safe? : safe?
|
120
|
+
self.encoder = other.respond_to?(:encoder) ? other.encoder : DEFAULT_ENCODER
|
90
121
|
|
91
122
|
@key_map.clear
|
92
123
|
self.each do |k, v|
|
@@ -151,12 +182,7 @@ private
|
|
151
182
|
end
|
152
183
|
|
153
184
|
def encode key
|
154
|
-
|
155
|
-
when String, Symbol
|
156
|
-
key.to_s.downcase.gsub(' ', '_')
|
157
|
-
else
|
158
|
-
key
|
159
|
-
end
|
185
|
+
@encoder.call key
|
160
186
|
end
|
161
187
|
|
162
188
|
def detect_clash hash
|
@@ -528,5 +528,53 @@ class TestInsensitiveHash < Test::Unit::TestCase
|
|
528
528
|
|
529
529
|
assert_equal :value, a[:key]
|
530
530
|
end
|
531
|
+
|
532
|
+
def test_encoder
|
533
|
+
# With custom encoder
|
534
|
+
a = {}.insensitive(:encoder => prc = proc { |key| key.to_s.downcase })
|
535
|
+
a['1'] = 'one'
|
536
|
+
assert_equal 'one', a[1]
|
537
|
+
assert_equal prc, a.encoder
|
538
|
+
|
539
|
+
a['hello world'] = true
|
540
|
+
assert_equal true, a['HELLO WORLD']
|
541
|
+
assert_equal nil, a[:HELLO_WORLD]
|
542
|
+
|
543
|
+
# Update encoder
|
544
|
+
a.encoder = proc { |key| key.to_s.gsub(' ', '_').downcase }
|
545
|
+
assert_equal true, a[:HELLO_WORLD]
|
546
|
+
|
547
|
+
# Update again
|
548
|
+
a.encoder = proc { |key| key.to_s }
|
549
|
+
assert_equal true, a[:"hello world"]
|
550
|
+
assert_equal nil, a['HELLO WORLD']
|
551
|
+
assert_equal nil, a[:hello_world]
|
552
|
+
assert_equal nil, a[:HELLO_WORLD]
|
553
|
+
end
|
554
|
+
|
555
|
+
def test_encoder_invalid_type
|
556
|
+
assert_raise(ArgumentError) {
|
557
|
+
{}.insensitive(:encoder => 1)
|
558
|
+
}
|
559
|
+
assert_raise(ArgumentError) {
|
560
|
+
h = InsensitiveHash.new
|
561
|
+
h.encoder = 1
|
562
|
+
}
|
563
|
+
end
|
564
|
+
|
565
|
+
def test_encoder_replace
|
566
|
+
a = {}.insensitive(:encoder => proc { |key| key })
|
567
|
+
b = {}.insensitive(:encoder => proc { |key| key.to_s })
|
568
|
+
a[:key] = b[:key] = 1
|
569
|
+
assert_equal 1, a[:key]
|
570
|
+
assert_equal 1, b[:key]
|
571
|
+
assert_nil a['key']
|
572
|
+
assert_equal 1, b['key']
|
573
|
+
|
574
|
+
a.replace b
|
575
|
+
assert_equal 1, a['key']
|
576
|
+
a[:key2] = 2
|
577
|
+
assert_equal 2, a['key2']
|
578
|
+
end
|
531
579
|
end
|
532
580
|
|
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.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-02-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: test-unit
|
@@ -72,3 +72,4 @@ specification_version: 3
|
|
72
72
|
summary: Case-insensitive Ruby Hash
|
73
73
|
test_files:
|
74
74
|
- test/test_insensitive_hash.rb
|
75
|
+
has_rdoc:
|