serradura/kind

View on GitHub
lib/kind/dig.rb

Summary

Maintainability
A
2 hrs
Test Coverage
A
100%
# frozen_string_literal: true

require 'kind/basic'
require 'kind/empty'
require 'kind/presence'

module Kind
  module Dig
    extend self

    def call!(data, keys = Empty::ARRAY) # :nodoc
      keys.reduce(data) do |memo, key|
        value = get(memo, key)

        break if KIND.nil_or_undefined?(value)

        value
      end
    end

    def call(data, *input)
      args = input.size == 1 && input[0].kind_of?(::Array) ? input[0] : input

      result = call!(data, args)

      return result unless block_given?

      yield(result) unless KIND.nil_or_undefined?(result)
    end

    def presence(*args, &block)
      Presence.(call(*args, &block))
    end

    def [](*keys)
      ->(data) { call!(data, keys) }
    end

    private

      def get(data, key)
        return data[key] if ::Hash === data

        case data
        when ::Array
          data[key] if key.respond_to?(:to_int)
        when ::OpenStruct
          data[key] if key.respond_to?(:to_sym)
        when ::Struct
          data[key] rescue nil if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
        else
          data.public_send(key) if key.respond_to?(:to_sym) && data.respond_to?(key)
        end
      end
  end
end