module Grape module Validations module Types # This class wraps {MultipleTypeCoercer}, for use with collections # that allow members of more than one type. class VariantCollectionCoercer < Virtus::Attribute # Construct a new coercer that will attempt to coerce # a list of values such that all members are of one of # the given types. The container may also optionally be # coerced to a +Set+. An arbitrary coercion +method+ may # be supplied, which will be passed the entire collection # as a parameter and should return a new collection, or # may return the same one if no coercion was required. # # @param types [Array,Set] list of allowed types, # also specifying the container type # @param method [#call,#parse] method by which values should be coerced def initialize(types, method = nil) @types = types @method = method.respond_to?(:parse) ? method.method(:parse) : method # If we have a coercion method, pass it in here to save # building another one, even though we call it directly. @member_coercer = MultipleTypeCoercer.new types, method end # Coerce the given value. # # @param value [Array] collection of values to be coerced # @return [Array,Set,InvalidValue] # the coerced result, or an instance # of {InvalidValue} if the value could not be coerced. def coerce(value) return InvalidValue.new unless value.is_a? Array value = if @method @method.call(value) else value.map { |v| @member_coercer.call(v) } end return Set.new value if @types.is_a? Set value end # Assert that the value has been coerced successfully. # # @param value [Object] a coerced result returned from {#coerce} # @return [true,false] whether or not the coerced value # satisfies type requirements. def value_coerced?(value) value.is_a?(@types.class) && value.all? { |v| @member_coercer.success?(@types, v) } end end end end end