class Dry::Validation::Matchers::ValidateMatcher

Constants

DEFAULT_TYPE
TYPE_ERRORS

Public Class Methods

new(attr, acceptance) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 48
def initialize(attr, acceptance)
  @attr = attr
  @acceptance = acceptance
  @type = DEFAULT_TYPE
  @value_rules = []
  @macro_usage_params = []
  @check_filled = false
  @check_macro = false
end

Public Instance Methods

description() click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 58
def description
  @desc = []
  @desc << "validate for #{@acceptance} `#{@attr}`"

  validation_details_message = []
  validation_details_message << "filled with #{@type}" if @check_filled
  validation_details_message << "macro usage `#{@macro_usage_params.to_s}`" if @check_macro

  unless validation_details_message.empty?
    @desc << " ("
    @desc << validation_details_message.join("; ")
    @desc << ")"
  end

  @desc << " exists"
  @desc.join
end
failure_message() click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 76
def failure_message
  @desc = []
  @desc << "be missing validation for #{@acceptance} `#{@attr}`"

  validation_details_message = []
  validation_details_message << "filled with #{@type}" if @check_filled
  validation_details_message << "macro usage `#{@macro_usage_params.to_s}`" if @check_macro

  unless validation_details_message.empty?
    @desc << " ("
    @desc << validation_details_message.join("; ")
    @desc << ")"
  end

  @desc.join
end
filled(type=DEFAULT_TYPE) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 114
def filled(type=DEFAULT_TYPE)
  @check_filled = true
  @type = type
  self
end
macro_use?(macro_params) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 125
def macro_use?(macro_params)
  @check_macro = true
  @macro_usage_params = macro_params
  self
end
matches?(schema_or_schema_class) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 93
def matches?(schema_or_schema_class)
  if schema_or_schema_class.is_a?(Dry::Validation::Contract)
    schema = schema_or_schema_class
  elsif schema_or_schema_class.is_a?(Class) &&
    schema_or_schema_class.ancestors.include?(Dry::Validation::Contract)

    schema = schema_or_schema_class.new
  else
    fail(
      ArgumentError,
      "must be a schema instance or class; got #{schema_or_schema_class.inspect} instead"
    )
  end

  check_required_or_optional!(schema) &&
    check_filled!(schema) &&
    check_filled_with_type!(schema) &&
    check_value!(schema) &&
    check_macro_usage!(schema)
end
value(value_rules) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 120
def value(value_rules)
  @value_rules = value_rules
  self
end

Private Instance Methods

check_filled!(schema) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 147
def check_filled!(schema)
  return true if !@check_filled

  result = schema.(@attr => nil)
  if result.errors[@attr].nil? ||
      !result.errors[@attr].include?("must be filled")
    return false
  end
  true
end
check_filled_with_type!(schema) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 158
def check_filled_with_type!(schema)
  return true if !@check_filled
  result = schema.(@attr => TYPE_ERRORS[@type][:test_value])
  error_messages = result.errors[@attr]
  return true if error_messages.nil?
  # Message not allowed are all the type_error_messages that are not the
  # expected type. Any other message is accepted (like "size cannot be less than 20")
  unallowed_errors = type_error_messages - [TYPE_ERRORS[@type][:message]]
  # We check if error_messages intersect with the unallowed_errors.
  # if intersection is empty, then the check is passed.
  (error_messages & unallowed_errors).empty?
end
check_macro_usage!(schema) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 242
def check_macro_usage!(schema)
  return true if @macro_usage_params.empty?

  is_present = false

  schema.rules.each do |obj|
    next if obj.keys.first != @attr

    value = if @macro_usage_params.is_a?(Hash) && obj.macros.flatten.count > 1
              obj.macros.to_h.map { |k, v| [k, v.first] }.to_h
            else
              obj.macros.flatten.first
            end

    if value == @macro_usage_params
      is_present = true
      break
    end
  end

  is_present
end
check_required_or_optional!(schema) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 133
def check_required_or_optional!(schema)
  case @acceptance
  when :required
    result = schema.({})
    error_messages = result.errors[@attr]
    # NOTE should support required to specify but not fillup. Must wait for
    # https://github.com/dry-rb/dry-validation/issues/251
    error_messages.respond_to?('each') && error_messages.include?("is missing")
  else
    result = schema.({})
    result.errors[@attr].nil?
  end
end
check_value!(schema) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 171
def check_value!(schema)
  @value_rules.map do |rule|
    method_name = :"check_value_#{rule[0]}!"
    return true if !self.class.private_method_defined?(method_name)
    send(method_name, schema, rule)
  end.none? {|result| result == false}
end
check_value_included_in!(schema, rule) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 179
def check_value_included_in!(schema, rule)
  predicate = rule[0]
  allowed_values = rule[1]

  invalid_for_expected_values = allowed_values.map do |v|
    result = schema.(@attr => v)
    error_messages = result.errors[@attr]
    error_messages.respond_to?('each') && error_messages.grep(/must be one of/).any?
  end.any? {|result| result == true}
  return false if invalid_for_expected_values

  value_outside_required = allowed_values.sample.to_s + SecureRandom.hex(2)
  result = schema.(@attr => value_outside_required)
  error_messages = result.errors[@attr]
  return false if error_messages.nil?
  return true if error_messages.grep(/must be one of/).any?
  false
end
check_value_max_size!(schema, rule) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 223
def check_value_max_size!(schema, rule)
  predicate = rule[0]
  max_size = rule[1]

  expected_error_message = "size cannot be greater than #{max_size}"

  result = schema.(@attr => "a" * (max_size+1))
  error_messages = result.errors[@attr]
  error_when_over = error_messages.respond_to?('each') &&
    error_messages.include?(expected_error_message)

  result = schema.(@attr => "a" * (max_size))
  error_messages = result.errors[@attr]
  no_error_when_within = error_messages.nil? ||
    !error_messages.include?(expected_error_message)

  error_when_over && no_error_when_within
end
check_value_min_size!(schema, rule) click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 198
def check_value_min_size!(schema, rule)
  predicate = rule[0]
  min_size = rule[1]

  expected_error_message = "size cannot be less than #{min_size}"

  result = schema.(@attr => "a" * (min_size+1))
  error_messages = result.errors[@attr]
  no_error_when_over = error_messages.nil? ||
    !error_messages.include?(expected_error_message)

  result = schema.(@attr => "a" * (min_size))
  error_messages = result.errors[@attr]
  no_error_when_exact = error_messages.nil? ||
    !error_messages.include?(expected_error_message)

  result = schema.(@attr => "a" * (min_size-1))
  error_messages = result.errors[@attr]
  error_when_below = (min_size-1).zero? ||
    !error_messages.nil? &&
    error_messages.include?(expected_error_message)

  no_error_when_over && no_error_when_exact && error_when_below
end
type_error_messages() click to toggle source
# File lib/dry/validation/matchers/validate_matcher.rb, line 265
def type_error_messages
  type_error_messages = []
  TYPE_ERRORS.each_pair do |type, hash|
    type_error_messages << hash[:message]
  end
  type_error_messages
end