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.
Methods
Public Class
Public Instance
- <
- <=
- ==
- >
- >=
- []
- []=
- assoc
- clear
- clone
- compact
- compact!
- compare_by_identity
- compare_by_identity?
- default
- default=
- default_proc
- delete
- delete_if
- dig
- dup
- each
- each_key
- each_value
- empty?
- except
- fetch
- fetch_values
- flatten
- has_key?
- has_value?
- inspect
- invert
- keep_if
- key
- keys
- length
- merge
- rassoc
- rehash
- reject
- reject!
- replace
- select
- select!
- shift
- slice
- sort
- to_a
- to_hash
- to_proc
- to_s
- transform_keys
- transform_keys!
- transform_values
- transform_values!
- update
- values
- values_at
Included modules
- Enumerable
Public Instance Aliases
Public Class methods
# 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
# 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
# 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
# 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
# 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
# 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
# File cicphash.rb 390 def compact 391 hash = dup 392 hash.compact! 393 hash 394 end
# File cicphash.rb 396 def compact! 397 hash = to_hash 398 replace(hash) if hash.compact! 399 end
# File cicphash.rb 293 def compare_by_identity 294 raise TypeError, "CICPHash cannot compare by identity, use regular Hash" 295 end
# File cicphash.rb 297 def compare_by_identity? 298 false 299 end
# 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
# 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
# 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
# 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
# File cicphash.rb 118 def each 119 @hash.each{|key, value| yield @name_hash[key], value } 120 end
# File cicphash.rb 123 def each_key 124 @hash.each_key{|key| yield @name_hash[key] } 125 end
# File cicphash.rb 127 def each_value 128 @hash.each_value{|value| yield value } 129 end
# File cicphash.rb 435 def except(*a) 436 h = dup 437 a.each{|k| h.delete(k)} 438 h 439 end
# 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
# File cicphash.rb 380 def fetch_values(*a) 381 a.map{|x| fetch(x)} 382 end
# 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
# File cicphash.rb 149 def has_key?(key) 150 @hash.has_key?(convert_key(key)) 151 end
# File cicphash.rb 156 def has_value?(value) 157 @hash.has_value?(value) 158 end
# File cicphash.rb 179 def invert 180 hash = CICPHash.new 181 each{|key, value| hash[value] = key} 182 hash 183 end
# 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
# File cicphash.rb 162 def key(value) 163 @name_hash[@hash.key(value)] 164 end
# 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
# 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
# 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
# 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
# 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
# File cicphash.rb 230 def replace(hash) 231 clear 232 update(hash) 233 end
# 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
# 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
# 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
# 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
# File cicphash.rb 247 def sort(&block) 248 block_given? ? to_a.sort(&block) : to_a.sort 249 end
# File cicphash.rb 251 def to_a 252 array = [] 253 each{|key, value| array << [key, value]} 254 array 255 end
# File cicphash.rb 257 def to_hash 258 hash = {} 259 each{|key, value| hash[key] = value} 260 hash 261 end
# File cicphash.rb 417 def transform_keys(&block) 418 dup.transform_keys!(&block) 419 end
# File cicphash.rb 421 def transform_keys!(&block) 422 replace(to_hash.transform_keys!(&block)) 423 end
# File cicphash.rb 401 def transform_values(&block) 402 dup.transform_values!(&block) 403 end
# File cicphash.rb 405 def transform_values!(&block) 406 replace(to_hash.transform_values!(&block)) 407 end
# 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
# File cicphash.rb 283 def values_at(*keys) 284 keys.collect{|key| self[key]} 285 end