lib/trav3/response/response_collection.rb
# frozen_string_literal: true
module Trav3
class ResponseCollection
extend Forwardable
# @!macro [attach] def_delegators
# @!method count
# Forwards to $1.
# @see both Hash#count or Array#count
# @!method keys
# Forwards to $1.
# @see Hash#keys
# @!method values
# Forwards to $1.
# @see Hash#values
# @!method has_key?
# Forwards to $1.
# @see Hash#has_key?
# @!method key?
# Forwards to $1.
# @see Hash#key?
# @!method empty?
# Forwards to $1.
# @see both Hash#empty? or Array#empty?
def_delegators :@collection, :count, :keys, :values, :has_key?, :key?, :empty?
def initialize(travis, collection)
@travis = travis
@collection = collection
end
# Either the key or index of the item you wish to get depending on
# if this collection is a {#hash?} or an array.
#
# If the item retrieved is a Hash or Array then the returned item
# will be another instance of `ResponseCollection`. Otherwise it will
# be a `String` unless the target does not exist and then it will be `nil`.
#
# @param target [String, Integer]
# @return [ResponseCollection, String, nil]
def [](target)
result = collection[target]
return ResponseCollection.new(travis, result) if collection?(result)
result
end
# (see #[])
def dig(*target)
dug, *rest = target
result = collection.dig(dug)
if collection?(result)
rc = ResponseCollection.new(travis, result)
return rest.empty? ? rc : rc.dig(*rest)
end
result
end
# When the inner collection is an Array every item iterated
# over is yielded to you as a `ResponseCollection`.
#
# If the inner collection is a {#hash?} then this method acts
# as though you've called `each` directly on that `Hash`.
#
# @yieldparam [Array, ResponseCollection]
def each(&block)
return collection.each(&block) if hash?
collection.each do |item|
yield ResponseCollection.new(travis, item)
end
end
# Either the key or index of the item you wish to get depending on
# if this collection is a {#hash?} or an array.
#
# If the item retrieved is a Hash or Array then the returned item
# will be another instance of `ResponseCollection`. Otherwise it will
# be a `String`.
#
# If the target does not exist and no block was given this will raise
# an exception. If a block was given, then that block will be evaluated
# and that return value returned.
#
# @param target [String, Integer]
# @return [ResponseCollection, String, nil]
def fetch(target)
result = collection.fetch(target) { nil }
return ResponseCollection.new(travis, result) if collection?(result)
return result if result
# For error raising behavior
collection.fetch(target) unless block_given?
yield
end
# When the inner collection is an Array it returns the first
# item as either a `ResponseCollection` or a `String`. If the
# Array is empty it returns `nil`.
#
# If the inner collection is a {#hash?} then this simply returns `nil`.
#
# @return [ResponseCollection, String, nil]
def first
self[0]
end
# Follows `@href` link within item.
# If `#hash?` returns `true` then `#follow` takes no parameters.
# If `#hash?` returns `false` then `#follow` takes an index parameter
# for which item in the Array you wish to follow.
#
# @param idx [Integer] (optional parameter) index of array of item to follow `@href` url from
# @return [Success, RequestError]
def follow(idx = nil)
if href? && !idx
url = collection.fetch('@href')
return travis.send(:get_path_with_opts, url)
end
result = fetch(idx)
result.follow
end
# Reveals if the inner collection is a Hash or not.
#
# @return [Boolean]
def hash?
collection.is_a? Hash
end
# When the inner collection is an Array it returns the last
# item as either a `ResponseCollection` or a `String`. If the
# Array is empty it returns `nil`.
#
# If the inner collection is a {#hash?} then this simply returns `nil`.
#
# @return [ResponseCollection, String, nil]
def last
self[-1]
end
# If `@warnings` was returned with the response this will return
# a `ResponseCollection` instance of them. Otherwise this returns `nil`.
#
# @return [ResponseCollection, nil]
def warnings
return nil unless hash?
self['@warnings']
end
private
def collection?(input)
[Array, Hash].include? input.class
end
def href?
collection.respond_to?(:key?) and collection.key?('@href')
end
attr_reader :travis
attr_reader :collection
end
end