hashery 1.4.0 → 1.5.0
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/.ruby +57 -92
- data/.yardopts +8 -0
- data/COPYING.rdoc +45 -0
- data/HISTORY.rdoc +18 -0
- data/QED.rdoc +1 -0
- data/README.rdoc +42 -16
- data/lib/hashery.rb +16 -9
- data/lib/hashery.yml +57 -92
- data/lib/hashery/association.rb +3 -1
- data/lib/hashery/basic_object.rb +74 -0
- data/lib/hashery/basic_struct.rb +288 -1
- data/lib/hashery/basicobject.rb +1 -74
- data/lib/hashery/basicstruct.rb +1 -280
- data/lib/hashery/casting_hash.rb +171 -1
- data/lib/hashery/castinghash.rb +1 -171
- data/lib/hashery/core_ext.rb +82 -0
- data/lib/hashery/dictionary.rb +3 -0
- data/lib/hashery/fuzzy_hash.rb +154 -1
- data/lib/hashery/fuzzyhash.rb +1 -154
- data/lib/hashery/ini.rb +3 -2
- data/lib/hashery/key_hash.rb +186 -0
- data/lib/hashery/keyhash.rb +1 -0
- data/lib/hashery/linked_list.rb +195 -1
- data/lib/hashery/linkedlist.rb +1 -195
- data/lib/hashery/lru_hash.rb +273 -1
- data/lib/hashery/lruhash.rb +1 -273
- data/lib/hashery/open_cascade.rb +99 -1
- data/lib/hashery/open_hash.rb +77 -1
- data/lib/hashery/opencascade.rb +1 -99
- data/lib/hashery/openhash.rb +1 -77
- data/lib/hashery/ordered_hash.rb +168 -1
- data/lib/hashery/orderedhash.rb +1 -167
- data/lib/hashery/property_hash.rb +97 -1
- data/lib/hashery/propertyhash.rb +1 -97
- data/lib/hashery/query_hash.rb +35 -1
- data/lib/hashery/queryhash.rb +1 -35
- data/lib/hashery/stash.rb +3 -174
- data/lib/hashery/static_hash.rb +48 -1
- data/lib/hashery/statichash.rb +1 -48
- data/qed/06_opencascade.rdoc +12 -12
- data/test/case_association.rb +29 -15
- data/test/case_basicstruct.rb +192 -0
- data/test/case_dictionary.rb +149 -109
- data/test/case_keyhash.rb +175 -0
- data/test/case_opencascade.rb +89 -43
- data/test/case_openhash.rb +15 -11
- metadata +85 -78
- data/LICENSE +0 -206
- data/NOTICE +0 -11
- data/lib/hashery/sparse_array.rb +0 -1
- data/lib/hashery/sparsearray.rb +0 -577
- data/test/case_openobject.rb +0 -130
- data/test/case_sparsearray.rb +0 -316
- data/test/case_stash.rb +0 -131
data/lib/hashery/castinghash.rb
CHANGED
@@ -1,171 +1 @@
|
|
1
|
-
|
2
|
-
# are passed through casting procedures.
|
3
|
-
#--
|
4
|
-
# TODO: Handle default_proc.
|
5
|
-
#++
|
6
|
-
class CastingHash < Hash
|
7
|
-
|
8
|
-
# Default key conversion procedure.
|
9
|
-
KEY_PROC = lambda{ |x| x } #.to_s }
|
10
|
-
|
11
|
-
# Default value conversion procedure.
|
12
|
-
VAL_PROC = lambda{ |x| x }
|
13
|
-
|
14
|
-
#
|
15
|
-
def self.[](hash)
|
16
|
-
s = new
|
17
|
-
hash.each{ |k,v| s[k] = v }
|
18
|
-
s
|
19
|
-
end
|
20
|
-
|
21
|
-
#
|
22
|
-
def initialize(hash={}, value_cast=nil, &key_cast)
|
23
|
-
@key_proc = (key_cast || KEY_PROC)
|
24
|
-
@value_proc = (value_cast || VAL_PROC).to_proc
|
25
|
-
hash.each{ |k,v| self[k] = v }
|
26
|
-
end
|
27
|
-
|
28
|
-
#
|
29
|
-
def key_proc
|
30
|
-
@key_proc
|
31
|
-
end
|
32
|
-
|
33
|
-
#
|
34
|
-
def key_proc=(proc)
|
35
|
-
@key_proc = proc.to_proc
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
def value_proc
|
40
|
-
@value_proc
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
def value_proc=(proc)
|
45
|
-
@value_proc = proc.to_proc
|
46
|
-
end
|
47
|
-
|
48
|
-
#
|
49
|
-
def [](k)
|
50
|
-
super(key_proc[k])
|
51
|
-
end
|
52
|
-
|
53
|
-
#
|
54
|
-
def []=(k,v)
|
55
|
-
super(key_proc[k], value_proc[v])
|
56
|
-
end
|
57
|
-
|
58
|
-
#
|
59
|
-
def <<(other)
|
60
|
-
case other
|
61
|
-
when Hash
|
62
|
-
super(cast(other))
|
63
|
-
when Array
|
64
|
-
self[other[0]] = other[1]
|
65
|
-
else
|
66
|
-
raise ArgumentError
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def fetch(k)
|
71
|
-
super(key_proc[k])
|
72
|
-
end
|
73
|
-
|
74
|
-
#
|
75
|
-
def store(k, v)
|
76
|
-
super(key_proc[k], value_proc[v])
|
77
|
-
end
|
78
|
-
|
79
|
-
#
|
80
|
-
def key?(k)
|
81
|
-
super(key_proc[k])
|
82
|
-
end
|
83
|
-
|
84
|
-
#
|
85
|
-
def has_key?(k)
|
86
|
-
super(key_proc[k])
|
87
|
-
end
|
88
|
-
|
89
|
-
# Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
|
90
|
-
#
|
91
|
-
# foo = { :name=>'Gavin', :wife=>:Lisa }.to_stash
|
92
|
-
# foo.rekey!{ |k| k.upcase } #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
|
93
|
-
# foo.inspect #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
|
94
|
-
#
|
95
|
-
def rekey!(*args, &block)
|
96
|
-
# for backward comptability (DEPRECATE?).
|
97
|
-
block = args.pop.to_sym.to_proc if args.size == 1
|
98
|
-
if args.empty?
|
99
|
-
block = lambda{|k| k} unless block
|
100
|
-
keys.each do |k|
|
101
|
-
nk = block[k]
|
102
|
-
self[nk] = delete(k) #if nk
|
103
|
-
end
|
104
|
-
else
|
105
|
-
raise ArgumentError, "3 for 2" if block
|
106
|
-
to, from = *args
|
107
|
-
self[to] = delete(from) if has_key?(from)
|
108
|
-
end
|
109
|
-
self
|
110
|
-
end
|
111
|
-
|
112
|
-
#
|
113
|
-
def rekey(*args, &block)
|
114
|
-
dup.rekey!(*args, &block)
|
115
|
-
end
|
116
|
-
|
117
|
-
#
|
118
|
-
def delete(k)
|
119
|
-
super(key_proc[k])
|
120
|
-
end
|
121
|
-
|
122
|
-
#
|
123
|
-
def update(other)
|
124
|
-
super(cast(other))
|
125
|
-
end
|
126
|
-
|
127
|
-
# Same as #update.
|
128
|
-
def merge!(other)
|
129
|
-
super(cast(other))
|
130
|
-
end
|
131
|
-
|
132
|
-
#
|
133
|
-
def replace(other)
|
134
|
-
super(cast(other))
|
135
|
-
end
|
136
|
-
|
137
|
-
#
|
138
|
-
def values_at(*keys)
|
139
|
-
super(keys.map(&key_proc))
|
140
|
-
end
|
141
|
-
|
142
|
-
#
|
143
|
-
def to_hash
|
144
|
-
h = {}; each{ |k,v| h[k] = v }; h
|
145
|
-
end
|
146
|
-
|
147
|
-
#
|
148
|
-
alias_method :to_h, :to_hash
|
149
|
-
|
150
|
-
private
|
151
|
-
|
152
|
-
#
|
153
|
-
def cast(hash)
|
154
|
-
h
|
155
|
-
hash.each do |k,v|
|
156
|
-
h[key_proc[k]] = value_proc[v]
|
157
|
-
end
|
158
|
-
h
|
159
|
-
end
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
|
-
|
164
|
-
#class Hash
|
165
|
-
#
|
166
|
-
# # Convert a Hash to a CastingHash.
|
167
|
-
# def to_casting_hash(value_cast=nil, &key_cast)
|
168
|
-
# CastingHash.new(self, value_cast, &key_cast)
|
169
|
-
# end
|
170
|
-
#
|
171
|
-
#end
|
1
|
+
require 'hashery/casting_hash'
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Hashery
|
2
|
+
|
3
|
+
# This module is included into Ruby's core Hash class.
|
4
|
+
#
|
5
|
+
# These method derive from Ruby Facets.
|
6
|
+
module CoreExt
|
7
|
+
|
8
|
+
#
|
9
|
+
def to_h
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
def to_hash
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
|
19
|
+
#
|
20
|
+
# foo = { :name=>'Gavin', :wife=>:Lisa }
|
21
|
+
# foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa }
|
22
|
+
# foo.inspect #=> { "name"=>"Gavin", "wife"=>:Lisa }
|
23
|
+
#
|
24
|
+
def rekey(key_map=nil, &block)
|
25
|
+
if !(key_map or block)
|
26
|
+
block = lambda{|k| k.to_sym}
|
27
|
+
end
|
28
|
+
|
29
|
+
key_map ||= {}
|
30
|
+
|
31
|
+
hash = {}
|
32
|
+
|
33
|
+
(keys - key_map.keys).each do |key|
|
34
|
+
hash[key] = self[key]
|
35
|
+
end
|
36
|
+
|
37
|
+
key_map.each do |from, to|
|
38
|
+
hash[to] = self[from] if key?(from)
|
39
|
+
end
|
40
|
+
|
41
|
+
hash2 = {}
|
42
|
+
|
43
|
+
if block
|
44
|
+
if block.arity == 1 # TODO: is this condition needed?
|
45
|
+
hash.each do |k, v|
|
46
|
+
nk = block[k]
|
47
|
+
#nk = (NA == nk ? k : nk) # TODO: Can't support this here.
|
48
|
+
hash2[nk] = v
|
49
|
+
end
|
50
|
+
else
|
51
|
+
hash.each do |k, v|
|
52
|
+
nk = block[k,v]
|
53
|
+
#nk = (NA == nk ? k : nk) # TODO:
|
54
|
+
hash2[nk] = v
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
hash2 = hash
|
59
|
+
end
|
60
|
+
|
61
|
+
hash2
|
62
|
+
end
|
63
|
+
|
64
|
+
# Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
|
65
|
+
#
|
66
|
+
# foo = { :name=>'Gavin', :wife=>:Lisa }
|
67
|
+
# foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa }
|
68
|
+
# foo #=> { "name"=>"Gavin", "wife"=>:Lisa }
|
69
|
+
#
|
70
|
+
# CREDIT: Trans, Gavin Kistner
|
71
|
+
|
72
|
+
def rekey!(key_map=nil, &block)
|
73
|
+
replace(rekey(key_map, &block))
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
class Hash #:nodoc:
|
81
|
+
include Hashery::CoreExt
|
82
|
+
end
|
data/lib/hashery/dictionary.rb
CHANGED
@@ -124,6 +124,8 @@ class Dictionary
|
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
127
|
+
#
|
128
|
+
|
127
129
|
def order
|
128
130
|
reorder if @order_by
|
129
131
|
@order
|
@@ -176,6 +178,7 @@ class Dictionary
|
|
176
178
|
end
|
177
179
|
|
178
180
|
#
|
181
|
+
|
179
182
|
def reorder
|
180
183
|
if @order_by
|
181
184
|
assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by)
|
data/lib/hashery/fuzzy_hash.rb
CHANGED
@@ -1 +1,154 @@
|
|
1
|
-
require '
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
# = Fuzzy Hash
|
4
|
+
#
|
5
|
+
# A weird hash with special semantics for regex keys.
|
6
|
+
#
|
7
|
+
# This is useful when you want to have a lookup table that can either contain strings or regexes.
|
8
|
+
# For instance, you might want a catch all for certain regexes that perform a certain logic.
|
9
|
+
#
|
10
|
+
# >> hash = FuzzyHash.new
|
11
|
+
# >> hash[/^\d+$/] = 'number'
|
12
|
+
# >> hash[/.*/] = 'something'
|
13
|
+
# >> hash['chunky'] = 'bacon'
|
14
|
+
# >> hash['foo'] = 'vader'
|
15
|
+
#
|
16
|
+
# >> hash['foo']
|
17
|
+
# << 'vader'
|
18
|
+
# >> hash['food']
|
19
|
+
# << 'something'
|
20
|
+
# >> hash['123']
|
21
|
+
# << 'number'
|
22
|
+
#
|
23
|
+
# Copyright (c) 2009 Joshua Hull
|
24
|
+
|
25
|
+
class FuzzyHash
|
26
|
+
|
27
|
+
def initialize(init_hash = nil)
|
28
|
+
@fuzzies = []
|
29
|
+
@hash_reverse = {}
|
30
|
+
@fuzzies_reverse = {}
|
31
|
+
@fuzzy_hash = {}
|
32
|
+
@hash = {}
|
33
|
+
init_hash.each{ |key,value| self[key] = value } if init_hash
|
34
|
+
end
|
35
|
+
|
36
|
+
def clear
|
37
|
+
hash.clear
|
38
|
+
fuzzies.clear
|
39
|
+
hash_reverse.clear
|
40
|
+
fuzzies_reverse.clear
|
41
|
+
end
|
42
|
+
|
43
|
+
def size
|
44
|
+
hash.size + fuzzies.size
|
45
|
+
end
|
46
|
+
alias_method :count, :size
|
47
|
+
|
48
|
+
|
49
|
+
def ==(o)
|
50
|
+
o.is_a?(FuzzyHash)
|
51
|
+
o.send(:hash) == hash &&
|
52
|
+
o.send(:fuzzies) == fuzzies
|
53
|
+
end
|
54
|
+
|
55
|
+
def empty?
|
56
|
+
hash.empty? && fuzzies.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def keys
|
60
|
+
hash.keys + fuzzy_hash.keys
|
61
|
+
end
|
62
|
+
|
63
|
+
def values
|
64
|
+
hash.values + fuzzies.collect{|r| r.last}
|
65
|
+
end
|
66
|
+
|
67
|
+
def each
|
68
|
+
hash.each{|k,v| yield k,v }
|
69
|
+
fuzzies.each{|v| yield v.first, v.last }
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_value(value)
|
73
|
+
hash.delete(hash_reverse[value]) || ((rr = fuzzies_reverse[value]) && fuzzies.delete_at(rr[0]))
|
74
|
+
end
|
75
|
+
|
76
|
+
def []=(key, value)
|
77
|
+
if Regexp === key
|
78
|
+
fuzzies.delete_if{|f| f.first.inspect.hash == key.inspect.hash}
|
79
|
+
fuzzies_reverse.delete_if{|k, v| v[1].inspect.hash == key.inspect.hash}
|
80
|
+
hash_reverse.delete_if{|k,v| v.inspect.hash == key.inspect.hash}
|
81
|
+
|
82
|
+
fuzzy_hash[key] = value
|
83
|
+
fuzzies << [key, value]
|
84
|
+
reset_fuzz_test!
|
85
|
+
fuzzies_reverse[value] = [fuzzies.size - 1, key, value]
|
86
|
+
else
|
87
|
+
hash[key] = value
|
88
|
+
hash_reverse.delete_if{|k,v| v.hash == key.hash}
|
89
|
+
hash_reverse[value] = key
|
90
|
+
end
|
91
|
+
value
|
92
|
+
end
|
93
|
+
|
94
|
+
def replace(src, dest)
|
95
|
+
if hash_reverse.key?(src)
|
96
|
+
key = hash_reverse[src]
|
97
|
+
hash[key] = dest
|
98
|
+
hash_reverse.delete(src)
|
99
|
+
hash_reverse[dest] = key
|
100
|
+
elsif fuzzies_reverse.key?(src)
|
101
|
+
key = fuzzies_reverse[src]
|
102
|
+
fuzzies[rkey[0]] = [rkey[1], dest]
|
103
|
+
fuzzies_reverse.delete(src)
|
104
|
+
fuzzies_reverse[dest] = [rkey[0], rkey[1], dest]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def [](key)
|
109
|
+
(hash.key?(key) && hash[key]) ||
|
110
|
+
((lookup = fuzzy_lookup(key)) && lookup && lookup.first) ||
|
111
|
+
fuzzy_hash[key]
|
112
|
+
end
|
113
|
+
|
114
|
+
def match_with_result(key)
|
115
|
+
if hash.key?(key)
|
116
|
+
[hash[key], key]
|
117
|
+
else
|
118
|
+
fuzzy_lookup(key)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
attr_reader :fuzzies, :hash_reverse, :fuzzies_reverse, :hash, :fuzzy_hash
|
124
|
+
attr_writer :fuzz_test
|
125
|
+
|
126
|
+
def reset_fuzz_test!
|
127
|
+
self.fuzz_test = nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def fuzz_test
|
131
|
+
unless @fuzz_test
|
132
|
+
@fuzz_test = Object.new
|
133
|
+
@fuzz_test.instance_variable_set(:'@fuzzies', fuzzies)
|
134
|
+
method = "
|
135
|
+
def match(str)
|
136
|
+
case str\n
|
137
|
+
"
|
138
|
+
fuzzies.each_with_index do |reg, index|
|
139
|
+
method << "when #{reg.first.inspect}; [@fuzzies[#{index}][1], Regexp.last_match(0)];"
|
140
|
+
end
|
141
|
+
method << "end\nend\n"
|
142
|
+
@fuzz_test.instance_eval method
|
143
|
+
end
|
144
|
+
@fuzz_test
|
145
|
+
end
|
146
|
+
|
147
|
+
def fuzzy_lookup(key)
|
148
|
+
if !fuzzies.empty? && (value = fuzz_test.match(key))
|
149
|
+
value
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
data/lib/hashery/fuzzyhash.rb
CHANGED
@@ -1,154 +1 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
# = Fuzzy Hash
|
4
|
-
#
|
5
|
-
# A weird hash with special semantics for regex keys.
|
6
|
-
#
|
7
|
-
# This is useful when you want to have a lookup table that can either contain strings or regexes.
|
8
|
-
# For instance, you might want a catch all for certain regexes that perform a certain logic.
|
9
|
-
#
|
10
|
-
# >> hash = FuzzyHash.new
|
11
|
-
# >> hash[/^\d+$/] = 'number'
|
12
|
-
# >> hash[/.*/] = 'something'
|
13
|
-
# >> hash['chunky'] = 'bacon'
|
14
|
-
# >> hash['foo'] = 'vader'
|
15
|
-
#
|
16
|
-
# >> hash['foo']
|
17
|
-
# << 'vader'
|
18
|
-
# >> hash['food']
|
19
|
-
# << 'something'
|
20
|
-
# >> hash['123']
|
21
|
-
# << 'number'
|
22
|
-
#
|
23
|
-
# Copyright (c) 2009 Joshua Hull
|
24
|
-
|
25
|
-
class FuzzyHash
|
26
|
-
|
27
|
-
def initialize(init_hash = nil)
|
28
|
-
@fuzzies = []
|
29
|
-
@hash_reverse = {}
|
30
|
-
@fuzzies_reverse = {}
|
31
|
-
@fuzzy_hash = {}
|
32
|
-
@hash = {}
|
33
|
-
init_hash.each{ |key,value| self[key] = value } if init_hash
|
34
|
-
end
|
35
|
-
|
36
|
-
def clear
|
37
|
-
hash.clear
|
38
|
-
fuzzies.clear
|
39
|
-
hash_reverse.clear
|
40
|
-
fuzzies_reverse.clear
|
41
|
-
end
|
42
|
-
|
43
|
-
def size
|
44
|
-
hash.size + fuzzies.size
|
45
|
-
end
|
46
|
-
alias_method :count, :size
|
47
|
-
|
48
|
-
|
49
|
-
def ==(o)
|
50
|
-
o.is_a?(FuzzyHash)
|
51
|
-
o.send(:hash) == hash &&
|
52
|
-
o.send(:fuzzies) == fuzzies
|
53
|
-
end
|
54
|
-
|
55
|
-
def empty?
|
56
|
-
hash.empty? && fuzzies.empty?
|
57
|
-
end
|
58
|
-
|
59
|
-
def keys
|
60
|
-
hash.keys + fuzzy_hash.keys
|
61
|
-
end
|
62
|
-
|
63
|
-
def values
|
64
|
-
hash.values + fuzzies.collect{|r| r.last}
|
65
|
-
end
|
66
|
-
|
67
|
-
def each
|
68
|
-
hash.each{|k,v| yield k,v }
|
69
|
-
fuzzies.each{|v| yield v.first, v.last }
|
70
|
-
end
|
71
|
-
|
72
|
-
def delete_value(value)
|
73
|
-
hash.delete(hash_reverse[value]) || ((rr = fuzzies_reverse[value]) && fuzzies.delete_at(rr[0]))
|
74
|
-
end
|
75
|
-
|
76
|
-
def []=(key, value)
|
77
|
-
if Regexp === key
|
78
|
-
fuzzies.delete_if{|f| f.first.inspect.hash == key.inspect.hash}
|
79
|
-
fuzzies_reverse.delete_if{|k, v| v[1].inspect.hash == key.inspect.hash}
|
80
|
-
hash_reverse.delete_if{|k,v| v.inspect.hash == key.inspect.hash}
|
81
|
-
|
82
|
-
fuzzy_hash[key] = value
|
83
|
-
fuzzies << [key, value]
|
84
|
-
reset_fuzz_test!
|
85
|
-
fuzzies_reverse[value] = [fuzzies.size - 1, key, value]
|
86
|
-
else
|
87
|
-
hash[key] = value
|
88
|
-
hash_reverse.delete_if{|k,v| v.hash == key.hash}
|
89
|
-
hash_reverse[value] = key
|
90
|
-
end
|
91
|
-
value
|
92
|
-
end
|
93
|
-
|
94
|
-
def replace(src, dest)
|
95
|
-
if hash_reverse.key?(src)
|
96
|
-
key = hash_reverse[src]
|
97
|
-
hash[key] = dest
|
98
|
-
hash_reverse.delete(src)
|
99
|
-
hash_reverse[dest] = key
|
100
|
-
elsif fuzzies_reverse.key?(src)
|
101
|
-
key = fuzzies_reverse[src]
|
102
|
-
fuzzies[rkey[0]] = [rkey[1], dest]
|
103
|
-
fuzzies_reverse.delete(src)
|
104
|
-
fuzzies_reverse[dest] = [rkey[0], rkey[1], dest]
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def [](key)
|
109
|
-
(hash.key?(key) && hash[key]) ||
|
110
|
-
((lookup = fuzzy_lookup(key)) && lookup && lookup.first) ||
|
111
|
-
fuzzy_hash[key]
|
112
|
-
end
|
113
|
-
|
114
|
-
def match_with_result(key)
|
115
|
-
if hash.key?(key)
|
116
|
-
[hash[key], key]
|
117
|
-
else
|
118
|
-
fuzzy_lookup(key)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
private
|
123
|
-
attr_reader :fuzzies, :hash_reverse, :fuzzies_reverse, :hash, :fuzzy_hash
|
124
|
-
attr_writer :fuzz_test
|
125
|
-
|
126
|
-
def reset_fuzz_test!
|
127
|
-
self.fuzz_test = nil
|
128
|
-
end
|
129
|
-
|
130
|
-
def fuzz_test
|
131
|
-
unless @fuzz_test
|
132
|
-
@fuzz_test = Object.new
|
133
|
-
@fuzz_test.instance_variable_set(:'@fuzzies', fuzzies)
|
134
|
-
method = "
|
135
|
-
def match(str)
|
136
|
-
case str\n
|
137
|
-
"
|
138
|
-
fuzzies.each_with_index do |reg, index|
|
139
|
-
method << "when #{reg.first.inspect}; [@fuzzies[#{index}][1], Regexp.last_match(0)];"
|
140
|
-
end
|
141
|
-
method << "end\nend\n"
|
142
|
-
@fuzz_test.instance_eval method
|
143
|
-
end
|
144
|
-
@fuzz_test
|
145
|
-
end
|
146
|
-
|
147
|
-
def fuzzy_lookup(key)
|
148
|
-
if !fuzzies.empty? && (value = fuzz_test.match(key))
|
149
|
-
value
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
end
|
154
|
-
|
1
|
+
require 'hashery/fuzzy_hash'
|