locks/halibut

View on GitHub
lib/halibut/core/relation_map.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Halibut::Core

  # This is an abstract map with behaviour specific to HAL.
  #
  # spec spec spec
  class RelationMap
    extend Forwardable

    def_delegators :@relations, :[], :empty?, :==, :fetch

    DEFAULT_OPTIONS = { single_item_arrays: false }

    def initialize(options = {})
      @relations = {}
      @options = DEFAULT_OPTIONS.merge(options)
    end

    # Adds an object to a relation.
    #
    # @example
    #     relations = RelationMap.new
    #     relations.add 'self', Link.new('/resource/1')
    #     relations['self']
    #     # => [#<Halibut::Core::Link:0x007fa0ca5b92b8 @href=\"/resource/1\",
    #          @options=#<Halibut::Core::Link::Options:0x007fa0ca5b9240
    #          @templated=nil, @type=nil, @name=nil, @profile=nil,
    #          @title=nil, @hreflang=nil>>]
    #
    # @param [String] relation relation that the object belongs to
    # @param [Object] item     the object to add to the relation
    def add(relation, item)
      unless item.respond_to?(:to_hash)
        raise ArgumentError.new('only items that can be converted to hashes with #to_hash are permitted')
      end

      @relations[relation] = @relations.fetch(relation, []) << item
    end

    # Returns a hash corresponding to the object.
    #
    # RelationMap doens't just return @relations because it needs to convert
    # correctly when a relation only has a single item.
    #
    # @return [Hash] relation map in hash format
    def to_hash
      @relations.each_with_object({}) do |(rel,val), obj|
        rel = rel.to_s

        hashed_val = val.map(&:to_hash)
        if val.length == 1 && !single_item_arrays?
          hashed_val = val.first.to_hash
        end

        obj[rel] = hashed_val
      end
    end

    # Returns true if the relation map is configured to always to
    # permit single arrays when to_hash is called. The default behavior
    # is to convert single item arrays into instances
    def single_item_arrays?
      @options[:single_item_arrays]
    end
  end
end