Sha256: 98c28aff03ae6262202b51450c9dcd565075cd16e83543197d375d6a39d2affe

Contents?: true

Size: 1.8 KB

Versions: 52

Compression:

Stored size: 1.8 KB

Contents

# frozen_string_literal: true

class ReeHash::Slice
  include Ree::FnDSL

  fn :slice do
    link :build_filter_keys
    link 'ree_hash/contracts/hash_keys_contract', -> { HashKeysContract }
  end

  MissingKeyErr = Class.new(ArgumentError)
  InvalidFilterKey = Class.new(ArgumentError)

  doc(<<~DOC)
    Replaces the hash with only the given keys.
    Returns a hash containing the removed key/value pairs.

      hash = { a: 1, b: {e: 2, f: 1}, c: 3, d: 4 }
      slice(hash, [:a, :b])  # => {a: 1, b: 2}
      slice(hash, [:a, b: [:e]])  # => {a: 1, b: {e: 2}}
  DOC

  contract(
    Hash,
    HashKeysContract,
    Ksplat[
      raise?: Bool
    ] => Hash
  ).throws(MissingKeyErr, InvalidFilterKey)
  def call(hash, keys, **opts)
    filter_keys = build_filter_keys(keys)
    recursively_slice(hash, filter_keys, !!opts[:raise])
  end

  private

  def recursively_slice(hash, filter_keys, raise_if_missing)
    result = {}

    filter_keys.each do |filter_k, filter_v|
      if !hash.has_key?(filter_k)
        if raise_if_missing
          raise MissingKeyErr.new("missing key `#{filter_k.inspect}`")
        else
          next
        end
      end

      value = hash[filter_k]

      if filter_v.empty?
        result[filter_k] = value
        next
      end

      if value.is_a?(Array)
        result[filter_k] = value.map do |v|
          if v.is_a?(Hash)
            recursively_slice(v, filter_v, raise_if_missing)
          else
            raise InvalidFilterKey.new("invalid filter key #{filter_v.inspect} for value: #{v.inspect}")
          end
        end
      elsif value.is_a?(Hash)
        result[filter_k] = recursively_slice(value, filter_v, raise_if_missing)
      else
        raise InvalidFilterKey.new("invalid filter key #{filter_v.inspect} for value: #{value.inspect}")
      end
    end

    result
  end
end

Version data entries

52 entries across 52 versions & 1 rubygems

Version Path
ree_lib-1.0.124 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.123 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.122 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.121 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.120 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.119 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.118 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.117 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.116 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.115 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.114 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.113 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.112 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.111 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.110 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.109 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.108 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.107 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.106 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb
ree_lib-1.0.105 lib/ree_lib/packages/ree_hash/package/ree_hash/functions/slice.rb