Class: Hashery::FuzzyHash

Inherits:
Object show all
Defined in:
lib/hashery/fuzzy_hash.rb

Overview

FuzzyHash is a weird hash with special semantics for regex keys.

This is useful when you want to have a lookup table that can either contain strings or regexes. For instance, you might want a catch all for certain regexes that perform a certain logic.

>> hash = FuzzyHash.new
>> hash[/^\d+$/] = 'number'
>> hash[/.*/] = 'something'
>> hash['chunky'] = 'bacon'
>> hash['foo'] = 'vader'

>> hash['foo']
<< 'vader'
>> hash['food']
<< 'something'
>> hash['123']
<< 'number'

This class is based on Joshua Hull’s original FuzzyHash class.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(init_hash = nil) ⇒ FuzzyHash

Returns a new instance of FuzzyHash.



30
31
32
33
34
35
36
37
# File 'lib/hashery/fuzzy_hash.rb', line 30

def initialize(init_hash = nil)
  @fuzzies = []
  @hash_reverse = {}
  @fuzzies_reverse = {}
  @fuzzy_hash = {}
  @hash = {}
  init_hash.each{ |key,value| self[key] = value } if init_hash
end

Instance Attribute Details

#fuzz_testObject (private)



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/hashery/fuzzy_hash.rb', line 176

def fuzz_test
  unless @fuzz_test
    @fuzz_test = Object.new
    @fuzz_test.instance_variable_set(:'@fuzzies', fuzzies)
    method = "
      def match(str)
        case str\n
    "
    fuzzies.each_with_index do |reg, index|
      method << "when #{reg.first.inspect}; [@fuzzies[#{index}][1], Regexp.last_match(0)];"
    end
    method << "end\nend\n"
    @fuzz_test.instance_eval method
  end
  @fuzz_test
end

#fuzziesObject (readonly, private)

Returns the value of attribute fuzzies.



163
164
165
# File 'lib/hashery/fuzzy_hash.rb', line 163

def fuzzies
  @fuzzies
end

#fuzzies_reverseObject (readonly, private)

Returns the value of attribute fuzzies_reverse.



163
164
165
# File 'lib/hashery/fuzzy_hash.rb', line 163

def fuzzies_reverse
  @fuzzies_reverse
end

#fuzzy_hashObject (readonly, private)

Returns the value of attribute fuzzy_hash.



163
164
165
# File 'lib/hashery/fuzzy_hash.rb', line 163

def fuzzy_hash
  @fuzzy_hash
end

#hashObject (readonly, private)

Returns the value of attribute hash.



163
164
165
# File 'lib/hashery/fuzzy_hash.rb', line 163

def hash
  @hash
end

#hash_reverseObject (readonly, private)

Returns the value of attribute hash_reverse.



163
164
165
# File 'lib/hashery/fuzzy_hash.rb', line 163

def hash_reverse
  @hash_reverse
end

Instance Method Details

#==(o) ⇒ Object



61
62
63
64
65
# File 'lib/hashery/fuzzy_hash.rb', line 61

def ==(o)
  o.is_a?(FuzzyHash)
  o.send(:hash) == hash &&
  o.send(:fuzzies) == fuzzies
end

#[](key) ⇒ Object



144
145
146
147
148
# File 'lib/hashery/fuzzy_hash.rb', line 144

def [](key)
  (hash.key?(key) && hash[key])  ||
    ((lookup = fuzzy_lookup(key)) && lookup && lookup.first) ||
    fuzzy_hash[key]
end

#[]=(key, value) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/hashery/fuzzy_hash.rb', line 106

def []=(key, value)
  if Regexp === key
    fuzzies.delete_if{|f| f.first.inspect.hash == key.inspect.hash}
    fuzzies_reverse.delete_if{|k, v| v[1].inspect.hash == key.inspect.hash}
    hash_reverse.delete_if{|k,v| v.inspect.hash == key.inspect.hash}

    fuzzy_hash[key] = value
    fuzzies << [key, value]
    reset_fuzz_test!
    fuzzies_reverse[value] = [fuzzies.size - 1, key, value]
  else
    hash[key] = value
    hash_reverse.delete_if{|k,v| v.hash == key.hash}
    hash_reverse[value] = key
  end
  value
end

#clearObject



42
43
44
45
46
47
# File 'lib/hashery/fuzzy_hash.rb', line 42

def clear
  hash.clear
  fuzzies.clear
  hash_reverse.clear
  fuzzies_reverse.clear
end

#delete_value(value) ⇒ Object



99
100
101
# File 'lib/hashery/fuzzy_hash.rb', line 99

def delete_value(value)
  hash.delete(hash_reverse[value]) || ((rr = fuzzies_reverse[value]) && fuzzies.delete_at(rr[0]))
end

#eachObject



91
92
93
94
# File 'lib/hashery/fuzzy_hash.rb', line 91

def each
  hash.each{|k,v| yield k,v }
  fuzzies.each{|v| yield v.first, v.last }
end

#empty?Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/hashery/fuzzy_hash.rb', line 70

def empty?
  hash.empty? && fuzzies.empty?
end

#fuzzy_lookup(key) ⇒ Object (private)



196
197
198
199
200
# File 'lib/hashery/fuzzy_hash.rb', line 196

def fuzzy_lookup(key)
  if !fuzzies.empty? && (value = fuzz_test.match(key))
    value
  end
end

#keysObject



77
78
79
# File 'lib/hashery/fuzzy_hash.rb', line 77

def keys
  hash.keys + fuzzy_hash.keys
end

#match_with_result(key) ⇒ Object



153
154
155
156
157
158
159
# File 'lib/hashery/fuzzy_hash.rb', line 153

def match_with_result(key)
  if hash.key?(key)
    [hash[key], key]
  else
    fuzzy_lookup(key)
  end
end

#replace(src, dest) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/hashery/fuzzy_hash.rb', line 127

def replace(src, dest)
  if hash_reverse.key?(src)
    key = hash_reverse[src]
    hash[key] = dest
    hash_reverse.delete(src)
    hash_reverse[dest] = key
  elsif fuzzies_reverse.key?(src)
    key = fuzzies_reverse[src]
    fuzzies[rkey[0]] = [rkey[1], dest]
    fuzzies_reverse.delete(src)
    fuzzies_reverse[dest] = [rkey[0], rkey[1], dest]
  end
end

#reset_fuzz_test!Object (private)



169
170
171
# File 'lib/hashery/fuzzy_hash.rb', line 169

def reset_fuzz_test!
  self.fuzz_test = nil
end

#sizeObject Also known as: count



52
53
54
# File 'lib/hashery/fuzzy_hash.rb', line 52

def size
  hash.size + fuzzies.size
end

#valuesObject



84
85
86
# File 'lib/hashery/fuzzy_hash.rb', line 84

def values
  hash.values + fuzzies.collect{|r| r.last}
end