insensitive_hash_bxf 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.markdown +65 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +149 -0
- data/Rakefile +13 -0
- data/insensitive_hash.gemspec +23 -0
- data/lib/insensitive_hash.rb +20 -0
- data/lib/insensitive_hash/insensitive_hash.rb +200 -0
- data/lib/insensitive_hash/minimal.rb +4 -0
- data/lib/insensitive_hash/version.rb +6 -0
- data/test/test_insensitive_hash.rb +572 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 280229258001084e66fcc3b09e9f8691759dd9b2f1dff3d93b8e0346720edf9a
|
4
|
+
data.tar.gz: 67b834f76f1158d9bd11cca3c9a3364a262eacd77d3532df7c7f242416760157
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9486c4192d63d6ce5f8b07aa980ac9aea15d23e9225d723c08945254bd0e28bf85101c8174995ab8822cf739d58f9376fbd3d67ce8088d28100b6ad78f09c7df
|
7
|
+
data.tar.gz: 8c5212705169beb3e7cc8f6cde8074fe29118b1d814578500bb9d173b5e8dce1cba20a404e4c756e6e581676a25c0191bda1b6a6da6fd5a95db6c7e35fdc06fd
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.markdown
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
### 0.3.3
|
2
|
+
|
3
|
+
- Code refactoring
|
4
|
+
- List new contributors
|
5
|
+
|
6
|
+
### 0.3.2
|
7
|
+
|
8
|
+
- Supports custom key encoder
|
9
|
+
- Added `InsensitiveHash#merge_recursive!`
|
10
|
+
|
11
|
+
### 0.3.0
|
12
|
+
|
13
|
+
- Now allowing underscores for spaces is by default on, and cannot be turned off.
|
14
|
+
- "Inherited insensitivity" had been a great source of confusion,
|
15
|
+
as it stores transformed version of the given Array of Hash.
|
16
|
+
From 0.3.0, Hash values and descendant Hashes are converted to be insensitive
|
17
|
+
only on the initialization of InsensitiveHash.
|
18
|
+
Refer to the following code
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
ih = {}.insensitive
|
22
|
+
ih[:a] = { :b => :c }
|
23
|
+
|
24
|
+
ih[:a]['B'] # nil
|
25
|
+
|
26
|
+
# Initialize another InsensitiveHash
|
27
|
+
ih2 = ih.insensitive
|
28
|
+
ih2[:a]['B'] # :c
|
29
|
+
```
|
30
|
+
|
31
|
+
### 0.2.4
|
32
|
+
|
33
|
+
- Bug fix: Invalid `dup`, `clone` behavior
|
34
|
+
- :safe setting from `Hash#insensitive`
|
35
|
+
|
36
|
+
### 0.2.3 / 2012/02/18
|
37
|
+
|
38
|
+
- Key-clash detection made optional with `InsensitiveHash#safe=`
|
39
|
+
- Ruby 1.8 compatibility
|
40
|
+
|
41
|
+
### 0.2.2 / 2012/02/13
|
42
|
+
|
43
|
+
- :underscore option added
|
44
|
+
- `InsensitiveHash::KeyClashError` added for safer operations
|
45
|
+
- Bug fix: Preserve default/default_proc on merge/replace/insensitive
|
46
|
+
- Subtle behavioral change in `InsensitiveHash#replace` when called with an ordinary Hash
|
47
|
+
|
48
|
+
### 0.2.1 / 2012/02/10
|
49
|
+
|
50
|
+
- Bug fix: Insensitive `fetch`
|
51
|
+
|
52
|
+
### 0.2.0 / 2012/02/01
|
53
|
+
|
54
|
+
- Major rewrite
|
55
|
+
- Constructor syntaxes have been changed to match those of standard Hash (not backward-compatible)
|
56
|
+
- (Almost) Complete implementation of standard Hash spec.
|
57
|
+
|
58
|
+
### 0.1.0 / 2011/12/20
|
59
|
+
|
60
|
+
- Can opt-out of monkey-patching Hash with `require 'insensitive_hash/minimal'`
|
61
|
+
|
62
|
+
### 0.0.2-3 / 2011/10/28
|
63
|
+
|
64
|
+
- Removed duplicated code in the constructor
|
65
|
+
- More tests
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2013 Junegunn Choi
|
2
|
+
Copyright (c) 2018-2020 Box Factura
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# insensitive_hash_bxf
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/BoxFactura/insensitive_hash.svg?branch=master)](https://travis-ci.org/BoxFactura/insensitive_hash)
|
4
|
+
|
5
|
+
Hash with case-insensitive, Symbol/String-indifferent key access.
|
6
|
+
|
7
|
+
> This project is a fork from [https://github.com/junegunn/insensitive_hash](https://github.com/junegunn/insensitive_hash) and it was made to continue its maintenance.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
```
|
12
|
+
gem install insensitive_hash_bxf
|
13
|
+
```
|
14
|
+
|
15
|
+
## Instantiation
|
16
|
+
|
17
|
+
### Hash#insensitive
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'insensitive_hash'
|
21
|
+
|
22
|
+
ih = {}.insensitive
|
23
|
+
|
24
|
+
ih = { :abc => 1, 'hello world' => true }.insensitive
|
25
|
+
|
26
|
+
ih['ABC'] # 1
|
27
|
+
ih[:Hello_World] # true
|
28
|
+
```
|
29
|
+
|
30
|
+
### Without monkey-patching Hash
|
31
|
+
|
32
|
+
If you don't like to have Hash#insensitive method, `require 'insensitive_hash/minimal'`
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
require 'insensitive_hash/minimal'
|
36
|
+
|
37
|
+
ih = InsensitiveHash.new
|
38
|
+
ih = InsensitiveHash.new(:default_value)
|
39
|
+
ih = InsensitiveHash.new { |ih, k| ih[k] = InsensitiveHash.new }
|
40
|
+
|
41
|
+
ih = InsensitiveHash[ 'abc' => 1, :def => 2 ]
|
42
|
+
ih = InsensitiveHash[ 'abc', 1, :def, 2 ]
|
43
|
+
ih = InsensitiveHash[ [['abc', 1], [:def, 2]] ]
|
44
|
+
|
45
|
+
ih = InsensitiveHash[ 'hello world' => true ]
|
46
|
+
```
|
47
|
+
|
48
|
+
### Revert to normal Hash
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
h = ih.sensitive
|
52
|
+
h = ih.to_hash
|
53
|
+
```
|
54
|
+
|
55
|
+
## Basic usage
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
ih = {:abc => 1, 'DEF' => 2}.insensitive
|
59
|
+
|
60
|
+
# Case-insensitive, Symbol/String-indifferent access.
|
61
|
+
ih['Abc'] # 1
|
62
|
+
ih[:ABC] # 1
|
63
|
+
ih['abc'] # 1
|
64
|
+
ih[:abc] # 1
|
65
|
+
ih.has_key?(:DeF) # true
|
66
|
+
|
67
|
+
ih['ABC'] = 10
|
68
|
+
|
69
|
+
# keys and values
|
70
|
+
ih.keys # ['DEF', 'ABC']
|
71
|
+
ih.values # [2, 10]
|
72
|
+
|
73
|
+
# delete
|
74
|
+
ih.delete :Abc # 10
|
75
|
+
ih.keys # ['DEF']
|
76
|
+
```
|
77
|
+
|
78
|
+
## Inherited insensitivity
|
79
|
+
|
80
|
+
When an InsensitiveHash is built from another Hash,
|
81
|
+
descendant Hash values are recursively converted to be insensitive.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
|
85
|
+
ih = { 'kids' => { :hello => [ { :world => '!!!' } ] } }.insensitive
|
86
|
+
ih[:kids]['Hello'].first['WORLD'] # !!!
|
87
|
+
|
88
|
+
ih = {:one => [ [ [ { :a => { :b => { :c => 'd' } } } ] ] ]}.insensitive
|
89
|
+
ih['one'].first.first.first['A']['b'][:C] # 'd'
|
90
|
+
```
|
91
|
+
|
92
|
+
However, once InsensitiveHash is initialized,
|
93
|
+
descendant Hashes (or Hashes in Arrays) are not automatically converted.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
ih = {}.insensitive
|
97
|
+
ih[:abc] = { :def => true }
|
98
|
+
|
99
|
+
ih['ABC']['DEF'] # nil
|
100
|
+
```
|
101
|
+
|
102
|
+
Simply build a new InsensitiveHash out of it if you need recursive conversion.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
ih2 = ih.insensitive
|
106
|
+
ih2['ABC']['DEF'] # true
|
107
|
+
```
|
108
|
+
|
109
|
+
### Example: Processing case-insensitive YAML input
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
db = YAML.load(File.read 'database.yml').insensitive
|
113
|
+
|
114
|
+
# Access values however you like
|
115
|
+
db['Development']['ADAPTER']
|
116
|
+
db[:production][:adapter]
|
117
|
+
```
|
118
|
+
|
119
|
+
## Enabling key-clash detection (Safe mode)
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
ih = InsensitiveHash.new
|
123
|
+
ih.safe = true
|
124
|
+
|
125
|
+
# Will raise InsensitiveHash::KeyClashError
|
126
|
+
h.merge!('hello world' => 1, :hello_world => 2)
|
127
|
+
|
128
|
+
# Disables key-clash detection
|
129
|
+
h.safe = false
|
130
|
+
h.merge!('hello world' => 1, :hello_world => 2)
|
131
|
+
h['Hello World'] # 2
|
132
|
+
```
|
133
|
+
|
134
|
+
## Contributing to insensitive_hash
|
135
|
+
|
136
|
+
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
137
|
+
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
138
|
+
- Fork the project
|
139
|
+
- Start a feature/bugfix branch
|
140
|
+
- Commit and push until you are happy with your contribution
|
141
|
+
- Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
142
|
+
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
143
|
+
|
144
|
+
## Copyright
|
145
|
+
|
146
|
+
- Copyright (c) 2013 Junegunn Choi.
|
147
|
+
- Copyright (c) 2018-2020 Box Factura
|
148
|
+
|
149
|
+
See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |test|
|
7
|
+
test.libs << 'lib' << 'test'
|
8
|
+
test.pattern = 'test/**/test_*.rb'
|
9
|
+
test.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Run tests'
|
13
|
+
task default: :test
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$:.push File.expand_path('../lib', __FILE__)
|
4
|
+
require 'insensitive_hash/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'insensitive_hash_bxf'
|
8
|
+
s.version = InsensitiveHash::VERSION
|
9
|
+
s.authors = ['Junegunn Choi', 'Arandi Lopez']
|
10
|
+
s.email = ['junegunn.c@gmail.com', 'arandilopez.93@gmail.com']
|
11
|
+
s.homepage = 'https://github.com/BoxFactura/insensitive_hash'
|
12
|
+
s.summary = 'Case-insensitive Ruby Hash'
|
13
|
+
|
14
|
+
s.description = 'Hash with case-insensitive, Symbol/String-indifferent key access'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_development_dependency 'rake'
|
22
|
+
s.add_development_dependency 'test-unit', '>= 2.3.0'
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'insensitive_hash/version'
|
4
|
+
require 'insensitive_hash/insensitive_hash'
|
5
|
+
|
6
|
+
# :nodoc:
|
7
|
+
class Hash
|
8
|
+
# @param [Hash] options Options
|
9
|
+
# @option options [Boolean] :safe Whether to detect key clash on merge
|
10
|
+
# @return [InsensitiveHash]
|
11
|
+
def insensitive options = {}
|
12
|
+
InsensitiveHash.new.tap do |ih|
|
13
|
+
ih.safe = options[:safe] if options.key?(:safe)
|
14
|
+
ih.default = default
|
15
|
+
ih.default_proc = default_proc if default_proc
|
16
|
+
|
17
|
+
ih.merge_recursive!(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Insensitive Hash.
|
4
|
+
# @author Junegunn Choi <junegunn.c@gmail.com>
|
5
|
+
class InsensitiveHash < Hash
|
6
|
+
# Thrown when safe mode is on and another Hash with conflicting keys cannot be merged safely
|
7
|
+
class KeyClashError < RuntimeError; end
|
8
|
+
|
9
|
+
def initialize(default = nil, &block)
|
10
|
+
if block_given?
|
11
|
+
raise ArgumentError, 'wrong number of arguments' unless default.nil?
|
12
|
+
|
13
|
+
super(&block)
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
@key_map = {}
|
19
|
+
@safe = false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sets whether to detect key clashes
|
23
|
+
# @param [Boolean]
|
24
|
+
# @return [Boolean]
|
25
|
+
def safe=(safe_val)
|
26
|
+
raise ArgumentError, 'Neither true nor false' unless [true, false].include?(safe_val)
|
27
|
+
|
28
|
+
@safe = safe_val
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Boolean] Key-clash detection enabled?
|
32
|
+
def safe?
|
33
|
+
@safe
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns a normal, sensitive Hash
|
37
|
+
# @return [Hash]
|
38
|
+
def to_hash
|
39
|
+
{}.merge self
|
40
|
+
end
|
41
|
+
alias sensitive to_hash
|
42
|
+
|
43
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
44
|
+
def self.[](*init)
|
45
|
+
h = Hash[*init]
|
46
|
+
new.tap do |ih|
|
47
|
+
ih.merge_recursive! h
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
%w[[] assoc has_key? include? key? member?].each do |symb|
|
52
|
+
class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
53
|
+
def #{symb}(key)
|
54
|
+
super lookup_key(key)
|
55
|
+
end
|
56
|
+
EVAL
|
57
|
+
end
|
58
|
+
|
59
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
60
|
+
def []=(key, value)
|
61
|
+
delete key
|
62
|
+
ekey = encode key
|
63
|
+
@key_map[ekey] = key
|
64
|
+
super key, value
|
65
|
+
end
|
66
|
+
alias store []=
|
67
|
+
|
68
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
69
|
+
def merge!(other_hash)
|
70
|
+
detect_clash other_hash
|
71
|
+
other_hash.each do |key, value|
|
72
|
+
store key, value
|
73
|
+
end
|
74
|
+
self
|
75
|
+
end
|
76
|
+
alias update! merge!
|
77
|
+
|
78
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
79
|
+
def merge(other_hash)
|
80
|
+
self.class.new.tap do |ih|
|
81
|
+
ih.replace self
|
82
|
+
ih.merge! other_hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
alias update merge
|
86
|
+
|
87
|
+
# Merge another hash recursively.
|
88
|
+
# @param [Hash|InsensitiveHash] other_hash
|
89
|
+
# @return [self]
|
90
|
+
def merge_recursive!(other_hash)
|
91
|
+
detect_clash other_hash
|
92
|
+
other_hash.each do |key, value|
|
93
|
+
deep_set key, value
|
94
|
+
end
|
95
|
+
self
|
96
|
+
end
|
97
|
+
alias update_recursive! merge_recursive!
|
98
|
+
|
99
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
100
|
+
def delete(key, &block)
|
101
|
+
super lookup_key(key, true), &block
|
102
|
+
end
|
103
|
+
|
104
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
105
|
+
def clear
|
106
|
+
@key_map.clear
|
107
|
+
super
|
108
|
+
end
|
109
|
+
|
110
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
111
|
+
def replace(other)
|
112
|
+
super other
|
113
|
+
|
114
|
+
self.safe = other.respond_to?(:safe?) ? other.safe? : safe?
|
115
|
+
|
116
|
+
@key_map.clear
|
117
|
+
each do |k, _v|
|
118
|
+
ekey = encode k
|
119
|
+
@key_map[ekey] = k
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
124
|
+
def shift
|
125
|
+
super.tap do |ret|
|
126
|
+
@key_map.delete_if { |_k, v| v == ret.first }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
131
|
+
def values_at(*keys)
|
132
|
+
keys.map { |k| self[k] }
|
133
|
+
end
|
134
|
+
|
135
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
136
|
+
def fetch(*args, &block)
|
137
|
+
args[0] = lookup_key(args[0]) if args.first
|
138
|
+
super(*args, &block)
|
139
|
+
end
|
140
|
+
|
141
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
142
|
+
def dup
|
143
|
+
super.tap { |copy| copy.instance_variable_set :@key_map, @key_map.dup }
|
144
|
+
end
|
145
|
+
|
146
|
+
# @see http://www.ruby-doc.org/core-1.9.3/Hash.html Hash
|
147
|
+
def clone
|
148
|
+
super.tap { |copy| copy.instance_variable_set :@key_map, @key_map.dup }
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def deep_set(key, value)
|
154
|
+
wv = wrap value
|
155
|
+
self[key] = wv
|
156
|
+
end
|
157
|
+
|
158
|
+
def wrap(value)
|
159
|
+
case value
|
160
|
+
when InsensitiveHash
|
161
|
+
value.tap { |ih| ih.safe = safe? }
|
162
|
+
when Hash
|
163
|
+
self.class.new.tap do |ih|
|
164
|
+
ih.safe = safe?
|
165
|
+
ih.merge_recursive!(value)
|
166
|
+
end
|
167
|
+
when Array
|
168
|
+
value.map { |v| wrap v }
|
169
|
+
else
|
170
|
+
value
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def lookup_key(key, delete = false)
|
175
|
+
@key_map = {} if @key_map.nil?
|
176
|
+
ekey = encode key
|
177
|
+
if @key_map.key?(ekey)
|
178
|
+
delete ? @key_map.delete(ekey) : @key_map[ekey]
|
179
|
+
else
|
180
|
+
key
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def encode(key)
|
185
|
+
case key
|
186
|
+
when String, Symbol
|
187
|
+
key.to_s.downcase.gsub(' ', '_')
|
188
|
+
else
|
189
|
+
key
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def detect_clash(hash)
|
194
|
+
return unless @safe
|
195
|
+
|
196
|
+
hash.keys.map { |k| encode k }.tap do |ekeys|
|
197
|
+
raise KeyClashError, 'Key clash detected' if ekeys != ekeys.uniq
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,572 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$VERBOSE = true
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
require 'test/unit'
|
8
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
|
+
require 'insensitive_hash'
|
10
|
+
require 'yaml'
|
11
|
+
|
12
|
+
class TestInsensitiveHash < Test::Unit::TestCase
|
13
|
+
def eight?
|
14
|
+
RUBY_VERSION =~ /^1\.8\./
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_keys set1, set2
|
18
|
+
if eight?
|
19
|
+
assert_equal(set1.sort { |a, b| a.to_s <=> b.to_s }, set2.sort { |a, b| a.to_s <=> b.to_s })
|
20
|
+
else
|
21
|
+
assert_equal set1, set2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_has_key_set
|
26
|
+
ih = InsensitiveHash.new
|
27
|
+
ih['a'] = 1
|
28
|
+
ih.store 'A', 2
|
29
|
+
|
30
|
+
['a', 'A', :a, :A].each do |a|
|
31
|
+
assert ih.has_key?(a)
|
32
|
+
assert ih.key?(a)
|
33
|
+
assert ih.include?(a)
|
34
|
+
assert ih.member?(a)
|
35
|
+
assert_equal 2, ih[a]
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_keys ['A'], ih.keys
|
39
|
+
assert_equal [2], ih.values
|
40
|
+
|
41
|
+
ih[:A] = 4
|
42
|
+
assert_keys [:A], ih.keys
|
43
|
+
assert_equal [4], ih.values
|
44
|
+
|
45
|
+
ih[:b] = { :c => 5 }
|
46
|
+
assert ih.keys.include?(:A)
|
47
|
+
assert ih.keys.include?(:b)
|
48
|
+
assert_equal 2, ih.keys.length
|
49
|
+
assert_equal({ :c => 5 }, ih['B'])
|
50
|
+
assert_equal 5, ih['B'][:c]
|
51
|
+
assert_equal nil, ih['B']['C']
|
52
|
+
|
53
|
+
ih['c'] = [{ 'x' => 1 }, { :y => 2 }]
|
54
|
+
assert ih.keys.include?('c')
|
55
|
+
assert_equal 3, ih.keys.length
|
56
|
+
|
57
|
+
assert_equal nil, ih[:c].first[:x]
|
58
|
+
assert_equal nil, ih[:c].last['Y']
|
59
|
+
|
60
|
+
ih = ih.insensitive
|
61
|
+
assert_equal 1, ih[:c].first[:x]
|
62
|
+
assert_equal 2, ih[:c].last['Y']
|
63
|
+
|
64
|
+
# Deeeeeper nesting
|
65
|
+
ih['c'] = [[[{ 'x' => 1 }, { :y => 2 }]]]
|
66
|
+
assert_equal nil, ih[:c].first.first.last[:Y]
|
67
|
+
ih = ih.insensitive
|
68
|
+
assert_equal 2, ih[:c].first.first.last[:Y]
|
69
|
+
|
70
|
+
ih['c'] = { 'a' => { 'a' => { 'a' => 100 } } }.insensitive
|
71
|
+
assert_equal 100, ih[:C][:a][:A]['A']
|
72
|
+
|
73
|
+
ih[5] = 50
|
74
|
+
assert_equal 50, ih[5]
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_from_hash
|
78
|
+
hash = {
|
79
|
+
'a' => 1,
|
80
|
+
'B' => 2,
|
81
|
+
:c => { :D => [{ 'e' => 3 }] }
|
82
|
+
}
|
83
|
+
|
84
|
+
pend('TODO') do
|
85
|
+
assert_raise(NoMethodError) { hash.insensitive }
|
86
|
+
end
|
87
|
+
|
88
|
+
[hash.insensitive, InsensitiveHash[hash]].each do |ih|
|
89
|
+
assert ih.is_a?(Hash)
|
90
|
+
assert_equal InsensitiveHash, ih.class
|
91
|
+
['c', 'C', :c, :C].each do |c|
|
92
|
+
assert_equal InsensitiveHash, ih[c].class
|
93
|
+
|
94
|
+
['d', 'D', :d, :D].each do |d|
|
95
|
+
assert_equal InsensitiveHash, ih[c][d].first.class
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Changelog 0.3.0
|
101
|
+
ih = {}.insensitive
|
102
|
+
ih[:a] = { :b => :c }
|
103
|
+
assert_nil ih[:a]['B']
|
104
|
+
ih2 = ih.insensitive
|
105
|
+
assert_equal :c, ih2[:a]['B']
|
106
|
+
|
107
|
+
# InsensitiveHash#insensitive
|
108
|
+
ihash1 = hash.insensitive
|
109
|
+
ihash1.default = :default
|
110
|
+
ihash2 = ihash1.insensitive.insensitive.insensitive
|
111
|
+
|
112
|
+
assert_equal InsensitiveHash, ihash2.class
|
113
|
+
assert_equal :default, ihash2.default
|
114
|
+
|
115
|
+
# Preserving default
|
116
|
+
[:default, nil].each do |d|
|
117
|
+
hash.default = d
|
118
|
+
assert_equal d, hash.insensitive.insensitive.insensitive[:anything]
|
119
|
+
end
|
120
|
+
|
121
|
+
# Preserving default_proc
|
122
|
+
unless eight?
|
123
|
+
hash2 = {}
|
124
|
+
hash2.replace hash
|
125
|
+
hash2.default_proc = proc { |h, k| h[k] = :default }
|
126
|
+
|
127
|
+
ihash2 = hash2.insensitive.insensitive.insensitive
|
128
|
+
assert !ihash2.has_key?(:anything)
|
129
|
+
assert_equal :default, ihash2[:anything]
|
130
|
+
assert ihash2.has_key?(:anything)
|
131
|
+
end
|
132
|
+
|
133
|
+
# FIXME: test insensitive call with encoder
|
134
|
+
h = InsensitiveHash[{ 'Key with spaces' => 1 }]
|
135
|
+
h2 = h.insensitive
|
136
|
+
|
137
|
+
assert_equal 1, h['key with spaces']
|
138
|
+
assert_equal 1, h[:key_with_spaces]
|
139
|
+
assert_equal 1, h2[:KEY_WITH_SPACES]
|
140
|
+
assert_equal 1, h2[:Key_with_spaces]
|
141
|
+
|
142
|
+
assert_equal ['Key with spaces'], h.keys
|
143
|
+
assert_equal ['Key with spaces'], h2.keys
|
144
|
+
|
145
|
+
h = { 'A key with spaces' => true }
|
146
|
+
ih = h.insensitive
|
147
|
+
assert ih[:a_key_with_spaces]
|
148
|
+
|
149
|
+
# FIXME: from README
|
150
|
+
ih = InsensitiveHash[h]
|
151
|
+
assert ih[:a_key_with_spaces]
|
152
|
+
|
153
|
+
# :safe
|
154
|
+
ih = {}.insensitive
|
155
|
+
assert_raise(ArgumentError) { ihs = {'a' => 1}.insensitive(:safe => 1) }
|
156
|
+
ihs = {'a' => 1}.insensitive(:safe => true)
|
157
|
+
assert !ih.safe?
|
158
|
+
assert ihs.safe?
|
159
|
+
|
160
|
+
assert_raise(InsensitiveHash::KeyClashError) { ihs.merge(:a => 2, 'A' => 3) }
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_delete
|
164
|
+
ih = InsensitiveHash[:a => 1]
|
165
|
+
assert_equal [:a], ih.keys
|
166
|
+
assert_equal [1], ih.values
|
167
|
+
|
168
|
+
assert_equal nil, ih.delete('B')
|
169
|
+
assert_equal 1, ih.delete('A')
|
170
|
+
assert_equal :notfound, ih.delete('A') { |a| :notfound }
|
171
|
+
assert_equal [], ih.keys
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_merge
|
175
|
+
%i[merge update].each do |method|
|
176
|
+
ih = InsensitiveHash[:a => 1, 'hello world' => 2]
|
177
|
+
nh = { :d => :e }
|
178
|
+
ih2 = ih.send(method, :b => 2, :c => nh)
|
179
|
+
|
180
|
+
assert_keys [:a, 'hello world'], ih.keys
|
181
|
+
assert_keys [:a, 'hello world', :b, :c], ih2.keys
|
182
|
+
assert ih2.has_key?('B'), 'correctly merged another hash'
|
183
|
+
# No recursive merge
|
184
|
+
assert_equal :e, ih2[:c][:d]
|
185
|
+
assert_equal nil, ih2[:c][:D]
|
186
|
+
assert_equal nh.object_id, ih2[:c].object_id
|
187
|
+
|
188
|
+
assert_equal 2, ih[:hello_world]
|
189
|
+
assert_equal 2, ih.send(method, :b => 2)[:hello_world]
|
190
|
+
|
191
|
+
ih.default = 10
|
192
|
+
assert_equal 10, ih.send(method, :b => 2)[:anything]
|
193
|
+
|
194
|
+
ih.default = nil
|
195
|
+
assert_nil ih.send(method, :b => 2)[:anything]
|
196
|
+
|
197
|
+
unless eight?
|
198
|
+
ih.default_proc = proc { |h, k| h[k] = :default }
|
199
|
+
mh = ih.send(method, :b => 2)
|
200
|
+
assert !mh.has_key?(:anything)
|
201
|
+
assert_equal :default, mh[:anything]
|
202
|
+
assert mh.has_key?(:anything)
|
203
|
+
end
|
204
|
+
|
205
|
+
ih2.delete 'b'
|
206
|
+
assert ih2.has_key?('B') == false
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_merge!
|
211
|
+
%i[merge! update!].each do |method|
|
212
|
+
ih = InsensitiveHash[:a => 1]
|
213
|
+
ih2 = ih.send(method, :b => 2)
|
214
|
+
|
215
|
+
assert_keys [:a, :b], ih.keys
|
216
|
+
assert_keys [:a, :b], ih2.keys
|
217
|
+
assert ih2.has_key?('B'), 'correctly merged another hash'
|
218
|
+
|
219
|
+
ih2.delete 'b'
|
220
|
+
assert ih2.has_key?('B') == false
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_merge_recursive!
|
225
|
+
%i[merge_recursive! update_recursive!].each do |method|
|
226
|
+
ih = InsensitiveHash.new
|
227
|
+
ih[:a] = 1
|
228
|
+
ih[:b] = 2
|
229
|
+
|
230
|
+
nh = { 'b' => 3, :c => :d }
|
231
|
+
ih.send(method, nh)
|
232
|
+
assert_equal 3, ih[:b]
|
233
|
+
assert_equal :d, ih['C']
|
234
|
+
|
235
|
+
ih.safe = true
|
236
|
+
nh = { 'd' => 4, 'D' => 5 }
|
237
|
+
assert_raise(InsensitiveHash::KeyClashError) { ih.send(method, nh) }
|
238
|
+
ih.safe = false
|
239
|
+
ih.send(method, nh)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_merge_clash_overwritten
|
244
|
+
ih = InsensitiveHash.new
|
245
|
+
|
246
|
+
ih = ih.merge(:a => 1, :A =>2)
|
247
|
+
# No guarantee in order in 1.8
|
248
|
+
unless eight?
|
249
|
+
assert_equal 2, ih.values.first
|
250
|
+
assert_equal 2, ih['A']
|
251
|
+
end
|
252
|
+
assert_equal 1, ih.length
|
253
|
+
|
254
|
+
ih = InsensitiveHash.new
|
255
|
+
ih.merge!(:hello_world => 1, 'hello world' => 2)
|
256
|
+
unless eight?
|
257
|
+
assert_equal 2, ih.values.first
|
258
|
+
assert_equal 2, ih[:Hello_World]
|
259
|
+
end
|
260
|
+
assert_equal 1, ih.length
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_merge_clash
|
264
|
+
ih = InsensitiveHash.new
|
265
|
+
ih2 = InsensitiveHash.new
|
266
|
+
|
267
|
+
sih = InsensitiveHash.new
|
268
|
+
sih.safe = true
|
269
|
+
|
270
|
+
%i[merge merge! update update!].each do |method|
|
271
|
+
# No problem
|
272
|
+
[ih, ih2].each do |h|
|
273
|
+
h.send(method, { :a => 1, :A => 1, 'A' => 1})
|
274
|
+
h.send(method, { 'a' => 1, 'A' => 1 })
|
275
|
+
end
|
276
|
+
|
277
|
+
assert_raise(InsensitiveHash::KeyClashError) {
|
278
|
+
sih.send(method, { :a => 1, :A => 1, 'A' => 1})
|
279
|
+
}
|
280
|
+
assert_raise(InsensitiveHash::KeyClashError) {
|
281
|
+
sih.send(method, { 'a' => 1, 'A' => 1 })
|
282
|
+
}
|
283
|
+
|
284
|
+
assert_raise(InsensitiveHash::KeyClashError) {
|
285
|
+
sih.send(method, { :hello_world => 1, 'hello world' => 2})
|
286
|
+
}
|
287
|
+
ih2.send(method, { :hello_world => 1, 'hello world' => 2})
|
288
|
+
end
|
289
|
+
|
290
|
+
ih.merge({ :a => 1, :A => 1, 'A' => 1})
|
291
|
+
assert_raise(InsensitiveHash::KeyClashError) {
|
292
|
+
sih.merge({ :a => 1, :A => 1, 'A' => 1})
|
293
|
+
}
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_assoc
|
297
|
+
pend "1.8" if eight?
|
298
|
+
|
299
|
+
h = InsensitiveHash[{
|
300
|
+
'colors' => ['red', 'blue', 'green'],
|
301
|
+
:Letters => ['a', 'b', 'c' ]
|
302
|
+
}]
|
303
|
+
assert_equal [:Letters, ['a', 'b', 'c']], h.assoc('letters')
|
304
|
+
assert_equal ['colors', ['red', 'blue', 'green']], h.assoc(:COLORS)
|
305
|
+
end
|
306
|
+
|
307
|
+
def test_clear_empty?
|
308
|
+
h = InsensitiveHash[:a, 1]
|
309
|
+
h.clear
|
310
|
+
assert_equal [], h.keys
|
311
|
+
assert h.empty?
|
312
|
+
end
|
313
|
+
|
314
|
+
def test_to_hash
|
315
|
+
h = InsensitiveHash[:a, 1, :b, { :c => 2 }]
|
316
|
+
assert_equal 1, h[:A]
|
317
|
+
assert_equal 2, h['B']['C']
|
318
|
+
|
319
|
+
h = h.to_hash
|
320
|
+
assert_equal Hash, h.class
|
321
|
+
assert_equal nil, h[:A]
|
322
|
+
assert_equal 1, h[:a]
|
323
|
+
assert_equal 2, h[:b][:c]
|
324
|
+
pend('TBD: Recursive conversion') do
|
325
|
+
assert_equal nil, h[:b]['C']
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def test_compare_by_identity
|
330
|
+
pend 'Not Implemented'
|
331
|
+
|
332
|
+
key = 'a'
|
333
|
+
key2 = 'a'.clone
|
334
|
+
h = InsensitiveHash.new
|
335
|
+
h[key] = 1
|
336
|
+
h[:b] = 2
|
337
|
+
|
338
|
+
assert !h.compare_by_identity?
|
339
|
+
|
340
|
+
assert_equal 1, h['A']
|
341
|
+
assert_equal 2, h[:b]
|
342
|
+
h.compare_by_identity
|
343
|
+
|
344
|
+
assert h.compare_by_identity?
|
345
|
+
|
346
|
+
assert_equal nil, h[key2]
|
347
|
+
assert_equal nil, h[key]
|
348
|
+
assert_equal 2, h[:B]
|
349
|
+
|
350
|
+
h[key] = 3
|
351
|
+
assert_not_equal 'a'.object_id, key.object_id
|
352
|
+
assert_equal nil, h[key2]
|
353
|
+
assert_equal 3, h[key]
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_initializer
|
357
|
+
# Hash
|
358
|
+
h = InsensitiveHash[{ :a => 1 }]
|
359
|
+
assert_equal 1, h['A']
|
360
|
+
assert_equal [:a], h.keys
|
361
|
+
assert_equal [1], h.values
|
362
|
+
|
363
|
+
# Pairs
|
364
|
+
h = InsensitiveHash['a', 2, 3, 4]
|
365
|
+
assert_equal 2, h[:a]
|
366
|
+
|
367
|
+
# Wrong number of arguments
|
368
|
+
assert_raise(ArgumentError) { h = InsensitiveHash['a', 2, 3] }
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_default
|
372
|
+
h = InsensitiveHash.new
|
373
|
+
assert_nil h.default
|
374
|
+
|
375
|
+
h = InsensitiveHash.new 'a'
|
376
|
+
assert_equal 'a', h.default
|
377
|
+
assert_equal 'a', h[:not_there]
|
378
|
+
|
379
|
+
h = InsensitiveHash.new { |h, k| h[k] = k == :right ? :ok : nil }
|
380
|
+
assert_equal nil, h.default
|
381
|
+
assert_equal nil, h.default(:wrong)
|
382
|
+
assert_equal :ok, h.default(:right)
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_default_proc_patch
|
386
|
+
h = InsensitiveHash.new { |h, k| k }
|
387
|
+
assert_equal 1, h[1]
|
388
|
+
assert_equal 2, h[2]
|
389
|
+
|
390
|
+
h = InsensitiveHash.new { |h, k| h[k] = [] }
|
391
|
+
h[:abc] << 1
|
392
|
+
h[:abc] << 2
|
393
|
+
h[:abc] << 3
|
394
|
+
assert_equal [1, 2, 3], h[:abc]
|
395
|
+
|
396
|
+
h = InsensitiveHash.new { |h, k| h[k] = {} }
|
397
|
+
h[:abc][:def] = 1
|
398
|
+
h[:abc][:ghi] = { :xyz => true }
|
399
|
+
assert_equal 1, h[:abc][:def]
|
400
|
+
assert_equal true, h[:abc][:ghi][:xyz]
|
401
|
+
assert_equal nil, h[:abc][:ghi][:XYZ] # This shouldn't work anymore from 0.3.0
|
402
|
+
|
403
|
+
h = InsensitiveHash.new
|
404
|
+
h[:abc] = arr = [1, 2, 3]
|
405
|
+
arr << 4
|
406
|
+
assert_equal [1, 2, 3, 4], h[:ABC]
|
407
|
+
end
|
408
|
+
|
409
|
+
def test_delete_if
|
410
|
+
# FIXME: Test passes, but key_map not updated
|
411
|
+
h = InsensitiveHash[:a => 100, :tmp_a => 200, :c => 300]
|
412
|
+
h.delete_if.each { |k, v| k == :tmp_a }
|
413
|
+
assert_keys [:a, :c], h.keys
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_has_key_after_delete
|
417
|
+
set = [:a, :A, 'a', 'A', :b, :B, 'b', 'B']
|
418
|
+
h = InsensitiveHash[:a => 1, :b => 2]
|
419
|
+
|
420
|
+
set.each { |s| assert h.has_key?(s) }
|
421
|
+
h.delete_if { |k, v| true }
|
422
|
+
set.each { |s| assert !h.has_key?(s) }
|
423
|
+
end
|
424
|
+
|
425
|
+
def test_nil
|
426
|
+
h = InsensitiveHash.new(1)
|
427
|
+
h[nil] = 2
|
428
|
+
assert h.has_key?(nil)
|
429
|
+
assert !h.has_key?(:not_there)
|
430
|
+
assert_equal 1, h[:not_there]
|
431
|
+
assert_equal 2, h[nil]
|
432
|
+
|
433
|
+
h = InsensitiveHash[nil => 1]
|
434
|
+
assert_equal :notfound, h.delete('a') { :notfound }
|
435
|
+
assert_equal 1, h.delete(nil) { :notfound }
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_each
|
439
|
+
h = InsensitiveHash[{ :a => 1, :b => 2, :c => 3}]
|
440
|
+
assert_equal 3, h.each.count
|
441
|
+
end
|
442
|
+
|
443
|
+
def test_has_value
|
444
|
+
h = InsensitiveHash[{ :a => 1, :b => 2, :c => 3}]
|
445
|
+
assert h.value?(3)
|
446
|
+
end
|
447
|
+
|
448
|
+
def test_replace
|
449
|
+
h = InsensitiveHash[:a, 1]
|
450
|
+
assert h.has_key?('A')
|
451
|
+
|
452
|
+
h.replace({ :b => 2 })
|
453
|
+
|
454
|
+
assert !h.has_key?('A')
|
455
|
+
assert h.has_key?('B')
|
456
|
+
|
457
|
+
# Default value
|
458
|
+
h.replace(Hash.new(5))
|
459
|
+
assert_equal 5, h[:anything]
|
460
|
+
assert_equal [], h.keys
|
461
|
+
|
462
|
+
# Default proc
|
463
|
+
h.replace(Hash.new { |h, k| h[k] = :default })
|
464
|
+
assert_equal :default, h[:anything]
|
465
|
+
assert_equal [:anything], h.keys
|
466
|
+
end
|
467
|
+
|
468
|
+
def test_rassoc
|
469
|
+
pend "1.8" if eight?
|
470
|
+
|
471
|
+
a = InsensitiveHash[{1=> 'one', 2 => 'two', 3 => 'three', 'ii' => 'two'}]
|
472
|
+
assert_equal [2, 'two'], a.rassoc('two')
|
473
|
+
assert_nil a.rassoc('four')
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_shift
|
477
|
+
h = InsensitiveHash[{:a => 1, :b => 2}]
|
478
|
+
assert_equal [:a, 1], h.shift
|
479
|
+
assert !h.has_key?('A')
|
480
|
+
assert h.has_key?('B')
|
481
|
+
end
|
482
|
+
|
483
|
+
def test_values_at
|
484
|
+
h = InsensitiveHash[{:a => 1, :b => 2}]
|
485
|
+
assert_equal [2, 1], h.values_at('B', :A)
|
486
|
+
end
|
487
|
+
|
488
|
+
def test_fetch
|
489
|
+
h = InsensitiveHash[{:a => 1, :b => 2}]
|
490
|
+
['a', 'A', :A].each do |k|
|
491
|
+
assert_equal 1, h.fetch(k)
|
492
|
+
assert_equal 1, h.fetch(k) { nil }
|
493
|
+
end
|
494
|
+
assert_equal 3, h.fetch(:c, 3)
|
495
|
+
assert_equal 3, h.fetch(:c) { 3 }
|
496
|
+
assert_raise(eight? ? IndexError : KeyError) { h.fetch('D') }
|
497
|
+
end
|
498
|
+
|
499
|
+
def test_underscore_inheritance
|
500
|
+
h =
|
501
|
+
{
|
502
|
+
'Key with spaces' => {
|
503
|
+
'Another key with spaces' => 1
|
504
|
+
},
|
505
|
+
'Key 2 with spaces' =>
|
506
|
+
InsensitiveHash['Yet another key with spaces' => 2],
|
507
|
+
'Key 3 with spaces' =>
|
508
|
+
InsensitiveHash['Yet another key with spaces' => 3]
|
509
|
+
}.insensitive
|
510
|
+
|
511
|
+
assert_equal 1, h['key with spaces']['another key with spaces']
|
512
|
+
|
513
|
+
assert_equal 2, h['key 2 with spaces']['yet another key with spaces']
|
514
|
+
assert_equal 2, h['key 2 with spaces'][:yet_another_key_with_spaces]
|
515
|
+
|
516
|
+
assert_equal 3, h['key 3 with spaces']['yet another key with spaces']
|
517
|
+
|
518
|
+
assert_equal 1, h[:key_with_spaces][:another_key_with_spaces]
|
519
|
+
assert_equal 2, h[:key_2_with_spaces][:yet_another_key_with_spaces]
|
520
|
+
assert_equal 3, h[:key_3_with_spaces][:yet_another_key_with_spaces]
|
521
|
+
end
|
522
|
+
|
523
|
+
def test_constructor_default
|
524
|
+
h = InsensitiveHash.new :default
|
525
|
+
assert_equal :default, h[:xxx]
|
526
|
+
|
527
|
+
h = InsensitiveHash.new { :default_from_block }
|
528
|
+
assert_equal :default_from_block, h[:xxx]
|
529
|
+
|
530
|
+
# But not both!
|
531
|
+
assert_raise(ArgumentError) {
|
532
|
+
InsensitiveHash.new(:default) { :default_from_block }
|
533
|
+
}
|
534
|
+
end
|
535
|
+
|
536
|
+
def test_dup_clone
|
537
|
+
a = InsensitiveHash.new
|
538
|
+
a[:key] = :value
|
539
|
+
|
540
|
+
b = a.dup
|
541
|
+
b.delete 'key'
|
542
|
+
assert_nil b[:key]
|
543
|
+
|
544
|
+
assert_equal :value, a[:key]
|
545
|
+
|
546
|
+
c = a.clone
|
547
|
+
c.delete 'KEY'
|
548
|
+
assert_nil c[:key]
|
549
|
+
|
550
|
+
assert_equal :value, a[:key]
|
551
|
+
end
|
552
|
+
|
553
|
+
def test_yaml_serialization
|
554
|
+
hash = { 'hello' => 'Hola' }.insensitive
|
555
|
+
|
556
|
+
yaml = YAML.dump hash
|
557
|
+
assert yaml.is_a? String
|
558
|
+
|
559
|
+
new_hash = YAML.load yaml
|
560
|
+
assert new_hash.is_a? InsensitiveHash
|
561
|
+
assert new_hash.is_a? Hash
|
562
|
+
end
|
563
|
+
|
564
|
+
class MyInsensitiveHash < InsensitiveHash
|
565
|
+
end
|
566
|
+
|
567
|
+
def test_subclassing
|
568
|
+
mih = MyInsensitiveHash[{ 'a' => { 'b' => 3 } }]
|
569
|
+
assert_instance_of MyInsensitiveHash, mih
|
570
|
+
assert_instance_of MyInsensitiveHash, mih['a']
|
571
|
+
end
|
572
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: insensitive_hash_bxf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Junegunn Choi
|
8
|
+
- Arandi Lopez
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2020-10-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: test-unit
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 2.3.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.3.0
|
42
|
+
description: Hash with case-insensitive, Symbol/String-indifferent key access
|
43
|
+
email:
|
44
|
+
- junegunn.c@gmail.com
|
45
|
+
- arandilopez.93@gmail.com
|
46
|
+
executables: []
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- ".gitignore"
|
51
|
+
- ".travis.yml"
|
52
|
+
- CHANGELOG.markdown
|
53
|
+
- Gemfile
|
54
|
+
- LICENSE.txt
|
55
|
+
- README.md
|
56
|
+
- Rakefile
|
57
|
+
- insensitive_hash.gemspec
|
58
|
+
- lib/insensitive_hash.rb
|
59
|
+
- lib/insensitive_hash/insensitive_hash.rb
|
60
|
+
- lib/insensitive_hash/minimal.rb
|
61
|
+
- lib/insensitive_hash/version.rb
|
62
|
+
- test/test_insensitive_hash.rb
|
63
|
+
homepage: https://github.com/BoxFactura/insensitive_hash
|
64
|
+
licenses: []
|
65
|
+
metadata: {}
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubygems_version: 3.1.4
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: Case-insensitive Ruby Hash
|
85
|
+
test_files: []
|