Class: Scimitar::Support::HashWithIndifferentCaseInsensitiveAccess
- Inherits:
-
ActiveSupport::HashWithIndifferentAccess
- Object
- ActiveSupport::HashWithIndifferentAccess
- Scimitar::Support::HashWithIndifferentCaseInsensitiveAccess
- Defined in:
- lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb
Overview
A subclass of ActiveSupport::HashWithIndifferentAccess where not only can Hash keys be queried as Symbols or Strings, but they are looked up in a case-insensitive fashion too.
During enumeration, Hash keys will always be returned in whatever case they were originally set. Just as with ActiveSupport::HashWithIndifferentAccess, though, the type of the keys is always returned as a String, even if originally set as a Symbol - only the upper/lower case nature of the original key is preserved.
If a key is written more than once with the same effective meaning in a to-string, to-downcase form, then whatever case was used first wins; e.g. if you did hash = 23, then hash = 42, the result would be => 42.
It’s important to remember that Hash#merge is shallow and replaces values found at existing keys in the target (“this”) hash with values in the inbound Hash. If that new value that is itself a Hash, this replaces the value. For example:
-
Original:
'Foo' => { 'Bar' => 42 }
-
Merge:
'FOO' => { 'BAR' => 24 }
…results in “this” target hash’s key Foo
being addressed in the merge by inbound key FOO
, so the case doesn’t change. But the value for Foo
is replaced by the merging-in Hash completely:
-
Result:
'Foo' => { 'BAR' => 24 }
…and of course we might’ve replaced with a totally different type, such as true
:
-
Original:
'Foo' => { 'Bar' => 42 }
-
Merge:
'FOO' => true
-
Result:
'Foo' => true
If you’re intending to merge nested Hashes, then use ActiveSupport’s #deep_merge or an equivalent. This will have the expected outcome, where the hash with ‘BAR’ is merged into the existing value and, therefore, the original ‘Bar’ key case is preserved:
-
Original:
'Foo' => { 'Bar' => 42 }
-
Deep merge:
'FOO' => { 'BAR' => 24 }
-
Result:
'Foo' => { 'Bar' => 24 }
Instance Method Summary collapse
-
#[]=(key, value) ⇒ Object
Override the individual key writer.
-
#dup ⇒ Object
It’s vital that the attribute map is carried over when one of these objects is duplicated.
-
#initialize(constructor = nil) ⇒ HashWithIndifferentCaseInsensitiveAccess
constructor
A new instance of HashWithIndifferentCaseInsensitiveAccess.
-
#merge(*other_hashes, &block) ⇒ Object
Override #merge to express it in terms of #merge! (also overridden), so that merged hashes can have their keys treated indifferently too.
-
#merge!(*hashes_to_merge_to_self, &block) ⇒ Object
Modifies-self version of #merge, overriding Hash#merge!.
- #with_indifferent_case_insensitive_access ⇒ Object
Constructor Details
#initialize(constructor = nil) ⇒ HashWithIndifferentCaseInsensitiveAccess
Returns a new instance of HashWithIndifferentCaseInsensitiveAccess.
97 98 99 100 |
# File 'lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb', line 97 def initialize(constructor = nil) @scimitar_hash_with_indifferent_case_insensitive_access_key_map = {} super end |
Instance Method Details
#[]=(key, value) ⇒ Object
Override the individual key writer.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb', line 118 def []=(key, value) string_key = scimitar_hash_with_indifferent_case_insensitive_access_string(key) indifferent_key = scimitar_hash_with_indifferent_case_insensitive_access_downcase(string_key) converted_value = convert_value(value, conversion: :assignment) # Note '||=', as there might have been a prior use of the "same" key in # a different case. The earliest one is preserved since the actual Hash # underneath all this is already using that variant of the key. # key_for_writing = ( @scimitar_hash_with_indifferent_case_insensitive_access_key_map[indifferent_key] ||= string_key ) regular_writer(key_for_writing, converted_value) end |
#dup ⇒ Object
It’s vital that the attribute map is carried over when one of these objects is duplicated. Duplication of this ivar state does not happen when ‘dup’ is called on our superclass, so we have to do that manually.
106 107 108 109 110 111 112 113 114 |
# File 'lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb', line 106 def dup duplicate = super duplicate.instance_variable_set( '@scimitar_hash_with_indifferent_case_insensitive_access_key_map', @scimitar_hash_with_indifferent_case_insensitive_access_key_map ) return duplicate end |
#merge(*other_hashes, &block) ⇒ Object
Override #merge to express it in terms of #merge! (also overridden), so that merged hashes can have their keys treated indifferently too.
137 138 139 |
# File 'lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb', line 137 def merge(*other_hashes, &block) dup.merge!(*other_hashes, &block) end |
#merge!(*hashes_to_merge_to_self, &block) ⇒ Object
Modifies-self version of #merge, overriding Hash#merge!.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb', line 143 def merge!(*hashes_to_merge_to_self, &block) if block_given? hashes_to_merge_to_self.each do |hash_to_merge_to_self| hash_to_merge_to_self.each_pair do |key, value| value = block.call(key, self[key], value) if self.key?(key) self[key] = value end end else hashes_to_merge_to_self.each do |hash_to_merge_to_self| hash_to_merge_to_self.each_pair do |key, value| self[key] = value end end end self end |
#with_indifferent_case_insensitive_access ⇒ Object
93 94 95 |
# File 'lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb', line 93 def with_indifferent_case_insensitive_access self end |