class CICPHash

  1. cicphash.rb
Superclass: Object

Case Insensitive Case Preserving Hash

CICPHash has the same interface as Hash, but is case insensitive and case preserving. Any value can be used as a key. However, you cannot have two keys in the same CICPHash that would be the same if when converted to strings would be equal or differing only in case.

For example, all of the following keys would be considered equalivalent: 'ab', 'Ab', 'AB', 'aB', :ab, :Ab, :AB, :aB

CICPHash uses a last match wins policy. If an key-value pair is added to a CICPHash and a case insensitive variant of the key is already in the hash the instance of the key in the hash becomes the same the most recently added key (and the value is updated to reflect the new value).

You can change the rules determining which keys are equal by modifying the private convert_key method. By default, it is set to key.to_s.downcase. This method should produce the same output for any keys that you want to consider equal. For example, if you want :a and :A to be equal but :a to be different than “a”, maybe key.inspect.downcase would work for you.

Included modules

  1. Enumerable

Public Instance Aliases

deconstruct_keys -> to_hash
each_pair -> each
filter! -> select!
include? -> has_key?
index -> key
indexes -> values_at
indices -> values_at
key? -> has_key?
member? -> has_key?
merge! -> update
size -> length
store -> []=
to_h -> to_hash
value? -> has_value?

Public Class methods

[](*items)
[show source]
   # File cicphash.rb
24 def self.[](*items)
25   if items.length % 2 != 0
26     if items.length == 1 && items.first.is_a?(Hash)
27       new.merge(items.first)
28     else
29       raise ArgumentError, "odd number of arguments for CICPHash"
30     end
31   else
32     hash = new
33     loop do
34       break if items.length == 0
35       key = items.shift
36       value = items.shift
37       hash[key] = value
38     end
39     hash
40   end
41 end
new(*default, &block)
[show source]
   # File cicphash.rb
43 def initialize(*default, &block)
44   if default.length > 1 || default.length == 1 && block_given?
45     raise ArgumentError, "wrong number of arguments"
46   end
47   @name_hash = {}
48   @hash = {}
49   @default = default.first unless block_given?
50   @default_proc = Proc.new(&block) if block_given?
51 end

Public Instance methods

<(other)
[show source]
    # File cicphash.rb
362 def <(other)
363   to_hash < other.to_hash
364 end
<=(other)
[show source]
    # File cicphash.rb
366 def <=(other)
367   to_hash <= other.to_hash
368 end
==(hash)
[show source]
   # File cicphash.rb
53 def ==(hash)
54   to_hash == hash.to_hash
55 end
>(other)
[show source]
    # File cicphash.rb
354 def >(other)
355   to_hash > other.to_hash
356 end
>=(other)
[show source]
    # File cicphash.rb
358 def >=(other)
359   to_hash >= other.to_hash
360 end
[](key)
[show source]
   # File cicphash.rb
57 def [](key)
58   new_key = convert_key(key)
59   if @hash.include?(new_key)
60     @hash[new_key]
61   elsif @default_proc
62     @default_proc.call(self, key)
63   else
64     @default
65   end
66 end
[]=(key, value)
[show source]
   # File cicphash.rb
68 def []=(key, value)
69   new_key = convert_key(key)
70   @name_hash[new_key] = key
71   @hash[new_key] = value
72 end
assoc(obj)
[show source]
    # File cicphash.rb
301 def assoc(obj)
302   obj = convert_key(obj)
303   each do |k, v|
304     if convert_key(k) == obj
305       return [k, v]
306     end
307   end
308   nil
309 end
clear()
[show source]
   # File cicphash.rb
75 def clear
76   @name_hash.clear
77   @hash.clear
78 end
clone()
[show source]
   # File cicphash.rb
80 def clone
81   s = super
82   s.instance_variable_set(:@hash, @hash.clone)
83   s.instance_variable_set(:@name_hash, @name_hash.clone)
84   s
85 end
compact()
[show source]
    # File cicphash.rb
390 def compact
391   hash = dup
392   hash.compact!
393   hash
394 end
compact!()
[show source]
    # File cicphash.rb
396 def compact!
397   hash = to_hash
398   replace(hash) if hash.compact!
399 end
compare_by_identity()
[show source]
    # File cicphash.rb
293 def compare_by_identity
294   raise TypeError, "CICPHash cannot compare by identity, use regular Hash"
295 end
compare_by_identity?()
[show source]
    # File cicphash.rb
297 def compare_by_identity?
298   false
299 end
default()
[show source]
   # File cicphash.rb
87 def default
88   @default
89 end
default=(value)
[show source]
   # File cicphash.rb
91 def default=(value)
92   @default = value
93 end
default_proc()
[show source]
   # File cicphash.rb
95 def default_proc
96   @default_proc
97 end
delete(key)
[show source]
    # File cicphash.rb
 99 def delete(key)
100   new_key = convert_key(key)
101   @name_hash.delete(new_key)
102   @hash.delete(new_key)
103 end
delete_if(&block)
[show source]
    # File cicphash.rb
105 def delete_if(&block)
106   hash = CICPHash.new
107   each{|key, value| block.call(key, value) ? delete(key) : (hash[key] = value)}
108   hash
109 end
dig(arg, *a)
[show source]
    # File cicphash.rb
370 def dig(arg, *a)
371   h = self[arg]
372   if a.empty?
373     h
374   elsif !h.nil?
375     raise TypeError, "#{h.class} does not have #dig method" unless h.respond_to?(:dig)
376     h.dig(*a) 
377   end
378 end
dup()
[show source]
    # File cicphash.rb
111 def dup
112   s = super
113   s.instance_variable_set(:@hash, @hash.dup)
114   s.instance_variable_set(:@name_hash, @name_hash.dup)
115   s
116 end
each()
[show source]
    # File cicphash.rb
118 def each
119   @hash.each{|key, value| yield @name_hash[key], value }
120 end
each_key()
[show source]
    # File cicphash.rb
123 def each_key
124   @hash.each_key{|key| yield @name_hash[key] }
125 end
each_value()
[show source]
    # File cicphash.rb
127 def each_value
128   @hash.each_value{|value| yield value }
129 end
empty?()
[show source]
    # File cicphash.rb
131 def empty?
132   @hash.empty?
133 end
except(*a)
[show source]
    # File cicphash.rb
435 def except(*a)
436   h = dup
437   a.each{|k| h.delete(k)}
438   h
439 end
fetch(key, *default, &block)
[show source]
    # File cicphash.rb
135 def fetch(key, *default, &block)
136   raise ArgumentError, "wrong number of arguments (#{default.length+1} for 2)" if default.length > 1
137   if include?(key)
138     self[key]
139   elsif block_given?
140     block.call(key)
141   elsif default.length == 1
142     default.first
143   else
144     error_class = RUBY_VERSION < '1.9' ? IndexError : KeyError
145     raise error_class, "key not found"
146   end
147 end
fetch_values(*a)
[show source]
    # File cicphash.rb
380 def fetch_values(*a)
381   a.map{|x| fetch(x)}
382 end
flatten(*a)
[show source]
    # File cicphash.rb
313 def flatten(*a)
314   if a.empty?
315     to_a.flatten(1)
316   else
317     to_a.flatten(*a)
318   end
319 end
has_key?(key)
[show source]
    # File cicphash.rb
149 def has_key?(key)
150   @hash.has_key?(convert_key(key))
151 end
has_value?(value)
[show source]
    # File cicphash.rb
156 def has_value?(value)
157   @hash.has_value?(value)
158 end
inspect()
[show source]
    # File cicphash.rb
175 def inspect
176   to_hash.inspect
177 end
invert()
[show source]
    # File cicphash.rb
179 def invert
180   hash = CICPHash.new
181   each{|key, value| hash[value] = key}
182   hash
183 end
keep_if(&block)
[show source]
    # File cicphash.rb
321 def keep_if(&block)
322   to_a.each do |k, v|
323     delete(k) unless yield(k, v)
324   end
325   self
326 end
key(value)
[show source]
    # File cicphash.rb
162 def key(value)
163   @name_hash[@hash.key(value)]
164 end
keys()
[show source]
    # File cicphash.rb
185 def keys
186   @name_hash.values
187 end
length()
[show source]
    # File cicphash.rb
189 def length
190   @hash.length
191 end
merge(hash, &block)
[show source]
    # File cicphash.rb
194 def merge(hash, &block)
195   new_hash = CICPHash.new.merge!(self)
196   hash.each do |key, value| 
197     new_hash[key] = if block_given? && new_hash.include?(key)
198       block.call(key, new_hash[key], hash[key])
199     else 
200       value
201     end
202   end
203   new_hash
204 end
rassoc(obj)
[show source]
    # File cicphash.rb
328 def rassoc(obj)
329   each do |k, v|
330     if v == obj
331       return [k, v]
332     end
333   end
334   nil
335 end
rehash()
[show source]
    # File cicphash.rb
206 def rehash
207   @name_hash.keys.each do |key|
208     new_key = @name_hash[key].to_s.downcase 
209     if new_key != key
210       @name_hash[new_key] = @name_hash.delete(key)
211       @hash[new_key] = @hash.delete(key)
212     end
213   end
214   self
215 end
reject(&block)
[show source]
    # File cicphash.rb
217 def reject(&block)
218   hash = CICPHash.new
219   each{|key, value| hash[key] = self[key] unless block.call(key, value)}
220   hash
221 end
reject!(&block)
[show source]
    # File cicphash.rb
223 def reject!(&block)
224   hash = CICPHash.new
225   changes = false
226   each{|key, value| block.call(key, value) ? (changes = true; delete(key)) : (hash[key] = value)}
227   changes ? hash : nil
228 end
replace(hash)
[show source]
    # File cicphash.rb
230 def replace(hash)
231   clear
232   update(hash)
233 end
select(&block)
[show source]
    # File cicphash.rb
235 def select(&block)
236   array = []
237   each{|key, value| array << [key, value] if block.call(key, value)}
238   array
239 end
select!(&block)
[show source]
    # File cicphash.rb
337 def select!(&block)
338   mod = false
339   to_a.each do |k, v|
340     unless yield(k, v)
341       mod = true
342       delete(k)
343     end
344   end
345   self if mod
346 end
shift()
[show source]
    # File cicphash.rb
241 def shift
242   return nil if @name_hash.length == 0
243   key, value = @name_hash.shift
244   [value, @hash.delete(key)]
245 end
slice(*a)
[show source]
    # File cicphash.rb
411 def slice(*a)
412   h = self.class.new
413   a.each{|k| h[k] = self[k] if has_key?(k)}
414   h
415 end
sort(&block)
[show source]
    # File cicphash.rb
247 def sort(&block)
248   block_given? ? to_a.sort(&block) : to_a.sort
249 end
to_a()
[show source]
    # File cicphash.rb
251 def to_a
252   array = []
253   each{|key, value| array << [key, value]}
254   array
255 end
to_hash()
[show source]
    # File cicphash.rb
257 def to_hash
258   hash = {}
259   each{|key, value| hash[key] = value}
260   hash
261 end
to_proc()
[show source]
    # File cicphash.rb
384 def to_proc
385   lambda{|x| self[x]}
386 end
to_s()
[show source]
    # File cicphash.rb
263 def to_s
264   to_a.join
265 end
transform_keys(&block)
[show source]
    # File cicphash.rb
417 def transform_keys(&block)
418   dup.transform_keys!(&block)
419 end
transform_keys!(&block)
[show source]
    # File cicphash.rb
421 def transform_keys!(&block)
422   replace(to_hash.transform_keys!(&block))
423 end
transform_values(&block)
[show source]
    # File cicphash.rb
401 def transform_values(&block)
402   dup.transform_values!(&block)
403 end
transform_values!(&block)
[show source]
    # File cicphash.rb
405 def transform_values!(&block)
406   replace(to_hash.transform_values!(&block))
407 end
update(hash, &block)
[show source]
    # File cicphash.rb
267 def update(hash, &block)
268   hash.each do |key, value| 
269     self[key] = if block_given? && include?(key)
270       block.call(key, self[key], hash[key])
271     else 
272       value
273     end
274   end
275   self
276 end
values()
[show source]
    # File cicphash.rb
279 def values
280   @hash.values
281 end
values_at(*keys)
[show source]
    # File cicphash.rb
283 def values_at(*keys)
284   keys.collect{|key| self[key]}
285 end