class KindValidator

Constants

CLASS_OR_MODULE

Public Instance Methods

validate_each(record, attribute, value) click to toggle source
# File lib/kind/validator.rb, line 48
def validate_each(record, attribute, value)
  return if options[:allow_nil] && value.nil?

  return unless error = call_validation_for(attribute, value)

  raise Kind::Error.new("#{attribute} #{error}") if options[:strict]

  record.errors.add(attribute, error)
end

Private Instance Methods

array_of(expected, value) click to toggle source
# File lib/kind/validator.rb, line 144
def array_of(expected, value)
  types = Array(expected)

  return if value.kind_of?(::Array) && !value.empty? && value.all? { |val| types.any? { |type| type === val } }

  "must be an array of #{types.map { |klass| klass.name }.join(', ')}"
end
array_with(expected, value) click to toggle source
# File lib/kind/validator.rb, line 138
def array_with(expected, value)
  return if value.kind_of?(::Array) && !value.empty? && (value - Kind.of!(::Array, expected)).empty?

  "must be an array with #{expected.join(', ')}"
end
call_validation_for(attribute, value) click to toggle source
# File lib/kind/validator.rb, line 60
def call_validation_for(attribute, value)
  expected = options[:with] || options[:in]

  return validate_with_default_strategy(expected, value) if expected

  return kind_of(expected, value) if expected = options[:of]
  return kind_is(expected, value) if expected = options[:is]
  return respond_to(expected, value) if expected = options[:respond_to]
  return instance_of(expected, value) if expected = options[:instance_of]
  return array_with(expected, value) if expected = options[:array_with]
  return array_of(expected, value) if expected = options[:array_of]

  raise Kind::Validator::InvalidDefinition.new(attribute)
end
instance_of(expected, value) click to toggle source
# File lib/kind/validator.rb, line 130
def instance_of(expected, value)
  types = Array(expected)

  return if types.any? { |type| value.instance_of?(type) }

  "must be an instance of #{types.map { |klass| klass.name }.join(', ')}"
end
kind_is(expected, value) click to toggle source
# File lib/kind/validator.rb, line 93
def kind_is(expected, value)
  return kind_is_not(expected, value) unless expected.kind_of?(::Array)

  result = expected.map { |kind| kind_is_not(kind, value) }.tap(&:compact!)

  result.empty? || result.size < expected.size ? nil : result.join(', ')
end
kind_is_not(expected, value) click to toggle source
# File lib/kind/validator.rb, line 101
def kind_is_not(expected, value)
  case expected
  when ::Class
    return if expected == Kind.of_class(value) || value < expected

    "must be the class or a subclass of `#{expected.name}`"
  when ::Module
    return if value.kind_of?(::Class) && value <= expected
    return if expected == Kind.of_module_or_class(value) || value.kind_of?(expected)

    "must include the `#{expected.name}` module"
  else
    raise Kind::Error.new(CLASS_OR_MODULE, expected)
  end
end
kind_of(expected, value) click to toggle source
# File lib/kind/validator.rb, line 79
def kind_of(expected, value)
  if ::Array === expected
    return if expected.any? { |type| type === value }

    "must be a kind of #{expected.map { |type| type.name }.join(', ')}"
  else
    return if expected === value

    expected.respond_to?(:name) ? "must be a kind of #{expected.name}" : 'invalid kind'
  end
end
respond_to(expected, value) click to toggle source
# File lib/kind/validator.rb, line 117
def respond_to(expected, value)
  method_names = Array(expected)

  expected_methods = method_names.select { |method_name| !value.respond_to?(method_name) }
  expected_methods.map! { |method_name| "`#{method_name}`" }

  return if expected_methods.empty?

  methods = expected_methods.size == 1 ? 'method' : 'methods'

  "must respond to the #{methods}: #{expected_methods.join(', ')}"
end
validate_with_default_strategy(expected, value) click to toggle source
# File lib/kind/validator.rb, line 75
def validate_with_default_strategy(expected, value)
  send(Kind::Validator.default_strategy, expected, value)
end