Class: Hash
- Inherits:
-
Object
- Object
- Hash
- Includes:
- Everythingrb::InspectQuotable
- Defined in:
- lib/everythingrb/hash.rb
Overview
Extensions to Ruby’s core Hash class
Provides:
-
#to_struct, #to_ostruct, #to_istruct: Convert hashes to different structures
-
#join_map: Combine filter_map and join operations
-
#transform_values.with_key: Transform values with access to keys
-
#transform, #transform!: Transform keys and values
-
#find_value, #select_values: Find values based on conditions
-
#rename_key, #rename_keys: Rename hash keys while preserving order
-
#merge_if, #merge_if!: Conditionally merge based on key-value pairs
-
#merge_if_values, #merge_if_values!: Conditionally merge based on values
-
#compact_merge, #compact_merge!: Merge only non-nil values
-
#compact_blank_merge, #compact_blank_merge!: Merge only present values (ActiveSupport)
Constant Summary collapse
- EMPTY_STRUCT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
A minimal empty struct for Ruby 3.2+ compatibility
Ruby 3.2 enforces stricter argument handling for Struct. This means trying to create a Struct from an empty Hash will result in an ArgumentError being raised. This is trying to keep a consistent experience with that version and newer versions.
Struct.new(:_).new(nil)
Instance Method Summary collapse
-
#compact_blank_merge(other = {}) ⇒ Hash
Merges only present (non-blank) values from another hash.
-
#compact_blank_merge!(other = {}) ⇒ self
Merges only present (non-blank) values from another hash, in place.
-
#compact_merge(other = {}) ⇒ Hash
Merges only non-nil values from another hash.
-
#compact_merge!(other = {}) ⇒ self
Merges only non-nil values from another hash, in place.
-
#deep_transform_values(with_key: false) {|value, key| ... } ⇒ Hash, Enumerator
Recursively transforms all values in the hash and nested structures.
-
#deep_transform_values!(with_key: false) {|value, key| ... } ⇒ self, Enumerator
Recursively transforms all values in the hash and nested structures in place.
-
#find_value {|key, value| ... } ⇒ Object, ...
Returns the first value where the key-value pair satisfies the given condition.
-
#join_map(join_with = "", with_index: false) {|key_value_pair, index| ... } ⇒ String
Combines filter_map and join operations.
-
#merge_if(other = {}) {|key, value| ... } ⇒ Hash
Conditionally merges key-value pairs from another hash based on a block.
-
#merge_if!(other = {}) {|key, value| ... } ⇒ self
Conditionally merges key-value pairs from another hash in place.
-
#merge_if_values(other = {}) {|value| ... } ⇒ Hash
Conditionally merges key-value pairs based only on values.
-
#merge_if_values!(other = {}) {|value| ... } ⇒ self
Conditionally merges key-value pairs based only on values, in place.
-
#rename_key(old_key, new_key) ⇒ Hash
Renames a key in the hash while preserving the original order of elements.
-
#rename_key!(old_key, new_key) ⇒ self
Renames a key in the hash in place while preserving the original order of elements.
-
#rename_key_unordered(old_key, new_key) ⇒ Hash
Renames a key in the hash without preserving element order (faster).
-
#rename_key_unordered!(old_key, new_key) ⇒ self
Renames a key in the hash in place without preserving element order (faster).
-
#rename_keys(**keys) ⇒ Hash
Renames multiple keys in the hash while preserving the original order of elements.
-
#rename_keys!(**keys) ⇒ self
Renames multiple keys in the hash in place while preserving the original order of elements.
-
#select_values {|key, value| ... } ⇒ Array, Enumerator
Returns all values where the key-value pairs satisfy the given condition.
-
#to_istruct ⇒ Data
Converts hash to an immutable Data structure.
-
#to_ostruct ⇒ OpenStruct
Converts hash to an OpenStruct recursively.
-
#to_struct ⇒ Struct
Converts hash to a Struct recursively.
-
#transform {|key, value| ... } ⇒ Hash, Enumerator
Transforms keys and values to create a new hash.
-
#transform! {|key, value| ... } ⇒ self, Enumerator
Transforms keys and values in place.
-
#transform_values(with_key: false) {|value, key| ... } ⇒ Hash, Enumerator
Returns a new hash with all values transformed by the block.
-
#transform_values!(with_key: false) {|value, key| ... } ⇒ self, Enumerator
Transforms all values in the hash in place.
Methods included from Everythingrb::InspectQuotable
Instance Method Details
#compact_blank_merge(other = {}) ⇒ Hash
Only available when ActiveSupport is loaded
Merges only present (non-blank) values from another hash
This method merges key-value pairs from another hash, but only includes values that are present according to ActiveSupport’s definition (not nil, not empty strings, not empty arrays, etc.).
744 745 746 |
# File 'lib/everythingrb/hash.rb', line 744 def compact_blank_merge(other = {}) merge_if_values(other) { |i| i.present? } end |
#compact_blank_merge!(other = {}) ⇒ self
Only available when ActiveSupport is loaded
Merges only present (non-blank) values from another hash, in place
This method merges key-value pairs from another hash into the current hash, but only includes values that are present according to ActiveSupport’s definition (not nil, not empty strings, not empty arrays, etc.).
770 771 772 |
# File 'lib/everythingrb/hash.rb', line 770 def compact_blank_merge!(other = {}) merge_if_values!(other) { |i| i.present? } end |
#compact_merge(other = {}) ⇒ Hash
Merges only non-nil values from another hash
This is a convenience method for the common pattern of merging only values that are not nil.
686 687 688 |
# File 'lib/everythingrb/hash.rb', line 686 def compact_merge(other = {}) merge_if_values(other) { |i| i.itself } end |
#compact_merge!(other = {}) ⇒ self
Merges only non-nil values from another hash, in place
This is a convenience method for the common pattern of merging only values that are not nil.
709 710 711 |
# File 'lib/everythingrb/hash.rb', line 709 def compact_merge!(other = {}) merge_if_values!(other) { |i| i.itself } end |
#deep_transform_values(with_key: false) {|value, key| ... } ⇒ Hash, Enumerator
Recursively transforms all values in the hash and nested structures
Walks through the hash and all nested hashes/arrays and yields each non-hash and non-array value to the block, replacing it with the block’s return value.
270 271 272 273 274 275 276 277 278 |
# File 'lib/everythingrb/hash.rb', line 270 def deep_transform_values(with_key: false, &block) return to_enum(:deep_transform_values, with_key:) if block.nil? if with_key _deep_transform_values_with_key(self, nil, &block) else og_deep_transform_values(&block) end end |
#deep_transform_values!(with_key: false) {|value, key| ... } ⇒ self, Enumerator
Recursively transforms all values in the hash and nested structures in place
Same as #deep_transform_values but modifies the hash in place.
307 308 309 310 311 312 313 314 315 |
# File 'lib/everythingrb/hash.rb', line 307 def deep_transform_values!(with_key: false, &block) return to_enum(:deep_transform_values!, with_key:) if block.nil? if with_key _deep_transform_values_with_key!(self, nil, &block) else og_deep_transform_values!(&block) end end |
#find_value {|key, value| ... } ⇒ Object, ...
Returns the first value where the key-value pair satisfies the given condition
416 417 418 419 420 |
# File 'lib/everythingrb/hash.rb', line 416 def find_value(&block) return to_enum(:find_value) if block.nil? find(&block)&.last end |
#join_map(join_with = "", with_index: false) {|key_value_pair, index| ... } ⇒ String
Combines filter_map and join operations
66 67 68 69 70 71 72 73 74 |
# File 'lib/everythingrb/hash.rb', line 66 def join_map(join_with = "", with_index: false, &block) block = ->(kv_pair) { kv_pair.compact } if block.nil? if with_index filter_map.with_index(&block).join(join_with) else filter_map(&block).join(join_with) end end |
#merge_if(other = {}) {|key, value| ... } ⇒ Hash
Conditionally merges key-value pairs from another hash based on a block
596 597 598 599 600 |
# File 'lib/everythingrb/hash.rb', line 596 def merge_if(other = {}, &block) other = other.select(&block) unless block.nil? merge(other) end |
#merge_if!(other = {}) {|key, value| ... } ⇒ self
Conditionally merges key-value pairs from another hash in place
619 620 621 622 623 |
# File 'lib/everythingrb/hash.rb', line 619 def merge_if!(other = {}, &block) other = other.select(&block) unless block.nil? merge!(other) end |
#merge_if_values(other = {}) {|value| ... } ⇒ Hash
Conditionally merges key-value pairs based only on values
640 641 642 |
# File 'lib/everythingrb/hash.rb', line 640 def merge_if_values(other = {}, &block) merge_if(other) { |k, v| block.call(v) } end |
#merge_if_values!(other = {}) {|value| ... } ⇒ self
Conditionally merges key-value pairs based only on values, in place
660 661 662 |
# File 'lib/everythingrb/hash.rb', line 660 def merge_if_values!(other = {}, &block) merge_if!(other) { |k, v| block.call(v) } end |
#rename_key(old_key, new_key) ⇒ Hash
Renames a key in the hash while preserving the original order of elements
460 461 462 |
# File 'lib/everythingrb/hash.rb', line 460 def rename_key(old_key, new_key) rename_keys(old_key => new_key) end |
#rename_key!(old_key, new_key) ⇒ self
Renames a key in the hash in place while preserving the original order of elements
477 478 479 |
# File 'lib/everythingrb/hash.rb', line 477 def rename_key!(old_key, new_key) rename_keys!(old_key => new_key) end |
#rename_key_unordered(old_key, new_key) ⇒ Hash
Renames a key in the hash without preserving element order (faster)
This method is significantly faster than #rename_key but does not guarantee that the order of elements in the hash will be preserved.
539 540 541 542 543 544 545 546 547 548 549 550 |
# File 'lib/everythingrb/hash.rb', line 539 def rename_key_unordered(old_key, new_key) # Fun thing I learned. For small hashes, using #except is 1.5x faster than using dup and delete. # But as the hash becomes larger, the performance improvements become diminished until they're roughly the same. # Neat! hash = except(old_key) # Only modify the hash if the old key exists return hash unless key?(old_key) hash[new_key] = self[old_key] hash end |
#rename_key_unordered!(old_key, new_key) ⇒ self
Renames a key in the hash in place without preserving element order (faster)
This method is significantly faster than #rename_key! but does not guarantee that the order of elements in the hash will be preserved.
568 569 570 571 572 573 574 |
# File 'lib/everythingrb/hash.rb', line 568 def rename_key_unordered!(old_key, new_key) # Only modify the hash if the old key exists return self unless key?(old_key) self[new_key] = delete(old_key) self end |
#rename_keys(**keys) ⇒ Hash
Renames multiple keys in the hash while preserving the original order of elements
This method maintains the original order of all keys in the hash, renaming only the specified keys while keeping their positions unchanged.
495 496 497 498 499 500 |
# File 'lib/everythingrb/hash.rb', line 495 def rename_keys(**keys) # I tried multiple different ways to rename the key while preserving the order, this was the fastest transform_keys do |key| keys.key?(key) ? keys[key] : key end end |
#rename_keys!(**keys) ⇒ self
Renames multiple keys in the hash in place while preserving the original order of elements
This method maintains the original order of all keys in the hash, renaming only the specified keys while keeping their positions unchanged.
517 518 519 520 521 522 |
# File 'lib/everythingrb/hash.rb', line 517 def rename_keys!(**keys) # I tried multiple different ways to rename the key while preserving the order, this was the fastest transform_keys! do |key| keys.key?(key) ? keys[key] : key end end |
#select_values {|key, value| ... } ⇒ Array, Enumerator
Returns all values where the key-value pairs satisfy the given condition
442 443 444 445 446 |
# File 'lib/everythingrb/hash.rb', line 442 def select_values(&block) return to_enum(:select_values) if block.nil? select(&block).values end |
#to_istruct ⇒ Data
Converts hash to an immutable Data structure
87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/everythingrb/hash.rb', line 87 def to_istruct recurse = lambda do |input| case input when Hash input.to_istruct when Array input.map(&recurse) else input end end Data.define(*keys.map(&:to_sym)).new(*values.map { |value| recurse.call(value) }) end |
#to_ostruct ⇒ OpenStruct
Converts hash to an OpenStruct recursively
141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/everythingrb/hash.rb', line 141 def to_ostruct recurse = lambda do |value| case value when Hash value.to_ostruct when Array value.map(&recurse) else value end end OpenStruct.new(**transform_values { |value| recurse.call(value) }) end |
#to_struct ⇒ Struct
Converts hash to a Struct recursively
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/everythingrb/hash.rb', line 113 def to_struct # For Ruby 3.2, it raises if you attempt to create a Struct with no keys return EMPTY_STRUCT if RUBY_VERSION.start_with?("3.2") && empty? recurse = lambda do |value| case value when Hash value.to_struct when Array value.map(&recurse) else value end end Struct.new(*keys.map(&:to_sym)).new(*values.map { |value| recurse.call(value) }) end |
#transform {|key, value| ... } ⇒ Hash, Enumerator
Transforms keys and values to create a new hash
369 370 371 372 373 |
# File 'lib/everythingrb/hash.rb', line 369 def transform(&block) return to_enum(:transform) if block.nil? to_h(&block) end |
#transform! {|key, value| ... } ⇒ self, Enumerator
Transforms keys and values in place
391 392 393 394 395 |
# File 'lib/everythingrb/hash.rb', line 391 def transform!(&block) return to_enum(:transform!) if block.nil? replace(transform(&block)) end |
#transform_values(with_key: false) {|value, key| ... } ⇒ Hash, Enumerator
Returns a new hash with all values transformed by the block
Enhances Ruby’s standard transform_values with key access capability.
185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/everythingrb/hash.rb', line 185 def transform_values(with_key: false, &block) return to_enum(:transform_values, with_key:) if block.nil? if with_key each_pair.with_object({}) do |(key, value), output| output[key] = block.call(value, key) end else og_transform_values(&block) end end |
#transform_values!(with_key: false) {|value, key| ... } ⇒ self, Enumerator
Transforms all values in the hash in place
Enhances Ruby’s standard transform_values! with key access capability.
224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/everythingrb/hash.rb', line 224 def transform_values!(with_key: false, &block) return to_enum(:transform_values!, with_key:) if block.nil? if with_key each_pair do |key, value| self[key] = block.call(value, key) end else og_transform_values!(&block) end end |