lib/cmdx/validators/numeric.rb



# frozen_string_literal: true

module CMDx
  module Validators
    module Numeric

      extend self

      def call(value, options = {})
        case options[:numeric]
        in { within: within }
          raise_within_validation_error!(within.begin, within.end, options) unless within.cover?(value)
        in { not_within: not_within }
          raise_not_within_validation_error!(not_within.begin, not_within.end, options) if not_within.cover?(value)
        in { in: yn }
          raise_within_validation_error!(yn.begin, yn.end, options) unless yn.cover?(value)
        in { not_in: not_in }
          raise_not_within_validation_error!(not_in.begin, not_in.end, options) if not_in.cover?(value)
        in { min: min, max: max }
          raise_within_validation_error!(min, max, options) unless value.between?(min, max)
        in { min: min }
          raise_min_validation_error!(min, options) unless min <= value
        in { max: max }
          raise_max_validation_error!(max, options) unless value <= max
        in { is: is }
          raise_is_validation_error!(is, options) unless value == is
        in { is_not: is_not }
          raise_is_not_validation_error!(is_not, options) if value == is_not
        else
          raise ArgumentError, "no known numeric validator options given"
        end
      end

      private

      def raise_within_validation_error!(min, max, options)
        message = options.dig(:numeric, :within_message) ||
                  options.dig(:numeric, :in_message) ||
                  options.dig(:numeric, :message)
        message %= { min:, max: } unless message.nil?

        raise ValidationError, message || I18n.t(
          "cmdx.validators.numeric.within",
          min:,
          max:,
          default: "must be within #{min} and #{max}"
        )
      end

      def raise_not_within_validation_error!(min, max, options)
        message = options.dig(:numeric, :not_within_message) ||
                  options.dig(:numeric, :not_in_message) ||
                  options.dig(:numeric, :message)
        message %= { min:, max: } unless message.nil?

        raise ValidationError, message || I18n.t(
          "cmdx.validators.numeric.not_within",
          min:,
          max:,
          default: "must not be within #{min} and #{max}"
        )
      end

      def raise_min_validation_error!(min, options)
        message = options.dig(:numeric, :min_message) ||
                  options.dig(:numeric, :message)
        message %= { min: } unless message.nil?

        raise ValidationError, message || I18n.t(
          "cmdx.validators.numeric.min",
          min:,
          default: "must be at least #{min}"
        )
      end

      def raise_max_validation_error!(max, options)
        message = options.dig(:numeric, :max_message) ||
                  options.dig(:numeric, :message)
        message %= { max: } unless message.nil?

        raise ValidationError, message || I18n.t(
          "cmdx.validators.numeric.max",
          max:,
          default: "must be at most #{max}"
        )
      end

      def raise_is_validation_error!(is, options)
        message = options.dig(:numeric, :is_message) ||
                  options.dig(:numeric, :message)
        message %= { is: } unless message.nil?

        raise ValidationError, message || I18n.t(
          "cmdx.validators.numeric.is",
          is:,
          default: "must be #{is}"
        )
      end

      def raise_is_not_validation_error!(is_not, options)
        message = options.dig(:numeric, :is_not_message) ||
                  options.dig(:numeric, :message)
        message %= { is_not: } unless message.nil?

        raise ValidationError, message || I18n.t(
          "cmdx.validators.numeric.is_not",
          is_not:,
          default: "must not be #{is_not}"
        )
      end

    end
  end
end