Module: Dry::Transformer::HashTransformations
- Extended by:
- Registry
- Defined in:
- lib/dry/transformer/hash_transformations.rb
Overview
Transformation functions for Hash objects
Class Method Summary collapse
-
.accept_keys(hash, keys) ⇒ Hash
Accepts specified keys from a hash.
-
.copy_keys(source_hash, mapping) ⇒ Hash
Copy all keys in a hash using provided mapping hash.
-
.deep_merge(hash, other) ⇒ Hash
Merge a hash recursively.
-
.deep_stringify_keys(hash) ⇒ Hash
Stringify keys in a hash recursively.
-
.deep_symbolize_keys(hash) ⇒ Hash
Symbolize keys in a hash recursively.
-
.eval_values(hash, args, filters = []) ⇒ Object
Recursively evaluate hash values if they are procs/lambdas.
-
.fold(hash, key, tuple_key) ⇒ Hash
Folds array of tuples to array of values from a specified key.
-
.map_keys(source_hash, fn) ⇒ Hash
Map all keys in a hash with the provided transformation function.
-
.map_value(hash, key, fn) ⇒ Hash
Map a key in a hash with the provided transformation function.
-
.map_values(source_hash, fn) ⇒ Hash
Map all values in a hash using transformation function.
-
.nest(hash, root, keys) ⇒ Hash
Nest values from specified keys under a new key.
-
.reject_keys(hash, keys) ⇒ Hash
Rejects specified keys from a hash.
-
.rename_keys(source_hash, mapping) ⇒ Hash
Rename all keys in a hash using provided mapping hash.
-
.split(hash, key, keys) ⇒ Array<Hash>
Splits hash to array by all values from a specified key.
-
.stringify_keys(hash) ⇒ Hash
Stringify all keys in a hash.
-
.symbolize_keys(hash) ⇒ Hash
Symbolize all keys in a hash.
-
.unwrap(source_hash, root, selected = nil, prefix: false) ⇒ Hash
Collapse a nested hash from a specified key.
Methods included from Registry
[], contain?, fetch, import, register, store
Class Method Details
.accept_keys(hash, keys) ⇒ Hash
Accepts specified keys from a hash
208 209 210 |
# File 'lib/dry/transformer/hash_transformations.rb', line 208 def self.accept_keys(hash, keys) Hash[hash].slice(*keys) end |
.copy_keys(source_hash, mapping) ⇒ Hash
Copy all keys in a hash using provided mapping hash
170 171 172 173 174 175 176 177 178 |
# File 'lib/dry/transformer/hash_transformations.rb', line 170 def self.copy_keys(source_hash, mapping) Hash[source_hash].tap do |hash| mapping.each do |original_key, new_keys| [*new_keys].each do |new_key| hash[new_key] = hash[original_key] end end end end |
.deep_merge(hash, other) ⇒ Hash
Merge a hash recursively
418 419 420 421 422 423 424 425 426 427 |
# File 'lib/dry/transformer/hash_transformations.rb', line 418 def self.deep_merge(hash, other) Hash[hash].merge(other) do |_, original_value, new_value| if original_value.respond_to?(:to_hash) && new_value.respond_to?(:to_hash) deep_merge(Hash[original_value], Hash[new_value]) else new_value end end end |
.deep_stringify_keys(hash) ⇒ Hash
Stringify keys in a hash recursively
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/dry/transformer/hash_transformations.rb', line 109 def self.deep_stringify_keys(hash) hash.each_with_object({}) do |(key, value), output| output[key.to_s] = case value when ::Hash deep_stringify_keys(value) when ::Array value.map { |item| item.is_a?(Hash) ? deep_stringify_keys(item) : item } else value end end end |
.deep_symbolize_keys(hash) ⇒ Hash
Symbolize keys in a hash recursively
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/dry/transformer/hash_transformations.rb', line 65 def self.deep_symbolize_keys(hash) hash.each_with_object({}) do |(key, value), output| output[key.to_sym] = case value when ::Hash deep_symbolize_keys(value) when ::Array value.map { |item| item.is_a?(::Hash) ? deep_symbolize_keys(item) : item } else value end end end |
.eval_values(hash, args, filters = []) ⇒ Object
Recursively evaluate hash values if they are procs/lambdas
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
# File 'lib/dry/transformer/hash_transformations.rb', line 380 def self.eval_values(hash, args, filters = []) hash.each_with_object({}) do |(key, value), output| output[key] = case value when Proc if filters.empty? || filters.include?(key) value.call(*args) else value end when ::Hash eval_values(value, args, filters) when ::Array value.map { |item| item.is_a?(Hash) ? eval_values(item, args, filters) : item } else value end end end |
.fold(hash, key, tuple_key) ⇒ Hash
Folds array of tuples to array of values from a specified key
315 316 317 |
# File 'lib/dry/transformer/hash_transformations.rb', line 315 def self.fold(hash, key, tuple_key) hash.merge(key => ArrayTransformations.extract_key(hash[key], tuple_key)) end |
.map_keys(source_hash, fn) ⇒ Hash
Map all keys in a hash with the provided transformation function
32 33 34 |
# File 'lib/dry/transformer/hash_transformations.rb', line 32 def self.map_keys(source_hash, fn) Hash[source_hash].transform_keys!(&fn) end |
.map_value(hash, key, fn) ⇒ Hash
Map a key in a hash with the provided transformation function
223 224 225 |
# File 'lib/dry/transformer/hash_transformations.rb', line 223 def self.map_value(hash, key, fn) hash.merge(key => fn[hash[key]]) end |
.map_values(source_hash, fn) ⇒ Hash
Map all values in a hash using transformation function
136 137 138 |
# File 'lib/dry/transformer/hash_transformations.rb', line 136 def self.map_values(source_hash, fn) Hash[source_hash].transform_values!(&fn) end |
.nest(hash, root, keys) ⇒ Hash
Nest values from specified keys under a new key
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/dry/transformer/hash_transformations.rb', line 238 def self.nest(hash, root, keys) child = {} keys.each do |key| child[key] = hash[key] if hash.key?(key) end output = Hash[hash] child.each_key { |key| output.delete(key) } old_root = hash[root] if old_root.is_a?(Hash) output[root] = old_root.merge(child) else output[root] = child end output end |
.reject_keys(hash, keys) ⇒ Hash
Rejects specified keys from a hash
192 193 194 |
# File 'lib/dry/transformer/hash_transformations.rb', line 192 def self.reject_keys(hash, keys) Hash[hash].reject { |k, _| keys.include?(k) } end |
.rename_keys(source_hash, mapping) ⇒ Hash
Rename all keys in a hash using provided mapping hash
152 153 154 155 156 |
# File 'lib/dry/transformer/hash_transformations.rb', line 152 def self.rename_keys(source_hash, mapping) Hash[source_hash].tap do |hash| mapping.each { |k, v| hash[v] = hash.delete(k) if hash.key?(k) } end end |
.split(hash, key, keys) ⇒ Array<Hash>
Splits hash to array by all values from a specified key
The operation adds missing keys extracted from the array to regularize the output.
347 348 349 350 351 352 353 354 355 356 357 358 |
# File 'lib/dry/transformer/hash_transformations.rb', line 347 def self.split(hash, key, keys) list = Array(hash[key]) return [hash.reject { |k, _| k == key }] if list.empty? existing = list.flat_map(&:keys).uniq grouped = existing - keys ungrouped = existing & keys list = ArrayTransformations.group(list, key, grouped) if grouped.any? list = list.map { |item| item.merge(reject_keys(hash, [key])) } ArrayTransformations.add_keys(list, ungrouped) end |
.stringify_keys(hash) ⇒ Hash
Stringify all keys in a hash
92 93 94 |
# File 'lib/dry/transformer/hash_transformations.rb', line 92 def self.stringify_keys(hash) map_keys(hash, Coercions[:to_string].fn) end |
.symbolize_keys(hash) ⇒ Hash
Symbolize all keys in a hash
47 48 49 |
# File 'lib/dry/transformer/hash_transformations.rb', line 47 def self.symbolize_keys(hash) map_keys(hash, Coercions[:to_symbol].fn) end |
.unwrap(source_hash, root, selected = nil, prefix: false) ⇒ Hash
Collapse a nested hash from a specified key
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/dry/transformer/hash_transformations.rb', line 276 def self.unwrap(source_hash, root, selected = nil, prefix: false) return source_hash unless source_hash[root] add_prefix = lambda do |key| combined = [root, key].join("_") root.is_a?(::Symbol) ? combined.to_sym : combined end Hash[source_hash].merge(root => Hash[source_hash[root]]).tap do |hash| nested_hash = hash[root] keys = nested_hash.keys keys &= selected if selected new_keys = prefix ? keys.map(&add_prefix) : keys nested_contains_root_key = nested_hash.key?(root) hash.update(Hash[new_keys.zip(keys.map { |key| nested_hash.delete(key) })]) hash.delete(root) if nested_hash.empty? && !nested_contains_root_key end end |