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.
@@ -1,3 +1,6 @@
1
+ ### 0.3.1
2
+ * Supports custom key encoder
3
+
1
4
  ### 0.3.0
2
5
  * "Inherited insensitivity" had been a great source of confusion,
3
6
  as it stores transformed version of the given Array of Hash.
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Junegunn Choi
1
+ Copyright (c) 2013 Junegunn Choi
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -8,10 +8,10 @@ Installation
8
8
  gem install insensitive_hash
9
9
  ```
10
10
 
11
- Examples
12
- --------
11
+ Instantiation
12
+ -------------
13
13
 
14
- ### Instantiation
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
- ### Instantiation without monkey-patching Hash
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
- ### Basic usage
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
- ### "Inherited insensitivity"
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
- Once InsensitiveHash is initialized, you can convert its descendant Hash values by
90
- building a new InsensitiveHash from it.
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
- ### Enabling key-clash detection (Safe mode)
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) 2012 Junegunn Choi. See LICENSE.txt for
138
- further details.
178
+ Copyright (c) 2013 Junegunn Choi. See LICENSE.txt for further details.
139
179
 
@@ -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
@@ -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 = false
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
- case key
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
@@ -1,3 +1,3 @@
1
1
  class InsensitiveHash < Hash
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -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.0
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: 2012-07-28 00:00:00.000000000 Z
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: