Module: Corefines::Hash::Rekey

Defined in:
lib/corefines/hash.rb

Instance Method Summary collapse

Instance Method Details

#rekey(key_map) ⇒ Hash #rekey {|key, value| ... } ⇒ Hash

Returns a new hash with keys transformed according to the given key_map or the block.

If no key_map or block is given, then all keys are converted to Symbols, as long as they respond to to_sym.

Examples:

hash = { :a => 1, 'b' => 2 }
hash.rekey(:a => :x, :c => :y) # => { :x => 1, 'b' => 2 }
hash.rekey(&:to_s) # => { 'a' => 1, 'b' => 2 }
hash.rekey { |k| k.to_s.upcase } # => { 'A' => 1, 'B' => 2 }
hash.rekey # => { :a => 1, :b => 2 }

Overloads:

  • #rekey(key_map) ⇒ Hash

    Parameters:

    • key_map (Hash) —

      a translation map from the old keys to the new keys; {from_key => to_key, ...}.

  • #rekey {|key, value| ... } ⇒ Hash

    Yields:

    • (key, value) —

      gives every key-value pair to the block. The return value becomes a new key.

Returns:

  • (Hash) —

    a new hash.

Raises:

  • ArgumentError if both key_map and the block are given.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/corefines/hash.rb', line 246

module Rekey
  refine ::Hash do
    def rekey(key_map = nil, &block)
      fail ArgumentError, "provide key_map, or block, not both" if key_map && block

      # Note: self.dup is used to preserve the default_proc.
      if key_map
        key_map.each_with_object(dup) do |(from, to), hash|
          hash[to] = hash.delete(from) if hash.key? from
        end
      else
        transform_key = if !block
          ->(k, _) { k.to_sym rescue k }
        elsif block.arity.abs == 1 || block.lambda? && block.arity != 2
          # This is needed for "symbol procs" (e.g. &:to_s). It behaves
          # differently since Ruby 3.0!
          # Ruby <3.0: block.arity => -1, block.lambda? => false
          # Ruby 3.0: block.arity => -2, block.lambda? => true
          ->(k, _) { block[k] }
        else
          block
        end

        each_with_object(dup.clear) do |(key, value), hash|
          hash[ transform_key[key, value] ] = value
        end
      end
    end

    def rekey!(key_map = nil, &block)
      replace rekey(key_map, &block)
    end
  end
end

#rekey!(key_map) ⇒ Hash #rekey! {|key, value| ... } ⇒ Hash

Transforms keys according to the given key_map or the block. Same as #rekey, but modifies self.

Overloads:

  • #rekey!(key_map) ⇒ Hash

    Parameters:

    • key_map (Hash) —

      a translation map from the old keys to the new keys; {from_key => to_key, ...}.

  • #rekey! {|key, value| ... } ⇒ Hash

    Yields:

    • (key, value) —

      gives every key-value pair to the block. The return value becomes a new key.

Returns:

Raises:

  • ArgumentError if both key_map and the block are given.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/corefines/hash.rb', line 246

module Rekey
  refine ::Hash do
    def rekey(key_map = nil, &block)
      fail ArgumentError, "provide key_map, or block, not both" if key_map && block

      # Note: self.dup is used to preserve the default_proc.
      if key_map
        key_map.each_with_object(dup) do |(from, to), hash|
          hash[to] = hash.delete(from) if hash.key? from
        end
      else
        transform_key = if !block
          ->(k, _) { k.to_sym rescue k }
        elsif block.arity.abs == 1 || block.lambda? && block.arity != 2
          # This is needed for "symbol procs" (e.g. &:to_s). It behaves
          # differently since Ruby 3.0!
          # Ruby <3.0: block.arity => -1, block.lambda? => false
          # Ruby 3.0: block.arity => -2, block.lambda? => true
          ->(k, _) { block[k] }
        else
          block
        end

        each_with_object(dup.clear) do |(key, value), hash|
          hash[ transform_key[key, value] ] = value
        end
      end
    end

    def rekey!(key_map = nil, &block)
      replace rekey(key_map, &block)
    end
  end
end