# frozen_string_literal: true class MiniDefender::Rules::Integer < MiniDefender::Rule attr_reader :mode attr_reader :parsed DIGIT_MAP = { # Arabic-Indic Digits "\u0660" => '0', "\u0661" => '1', "\u0662" => '2', "\u0663" => '3', "\u0664" => '4', "\u0665" => '5', "\u0666" => '6', "\u0667" => '7', "\u0668" => '8', "\u0669" => '9', # Extended Arabic-Indic Digits "\u06F0" => '0', "\u06F1" => '1', "\u06F2" => '2', "\u06F3" => '3', "\u06F4" => '4', "\u06F5" => '5', "\u06F6" => '6', "\u06F7" => '7', "\u06F8" => '8', "\u06F9" => '9', } def initialize(mode = 'strict') @mode = mode end def self.signature 'integer' end def self.make(args) new(args[0] || 'strict') end def coerce(value) @parsed end def passes?(attribute, value, validator) # Avoid converting integers to string and back if value.is_a?(Integer) @parsed = value return true end value = value.to_s if @mode == 'relaxed' value = normalize_digits(value) end @parsed = Integer(value) rescue false end def message(attribute, value, validator) "The value must be an integer." end def normalize_digits(data) # Check if arabic digits exist or avoid expensive string creation operation unless data.match?(/[\u0660-\u0669\u06F0-\u06F9]/) return data end DIGIT_MAP.each do |k, v| data = data.gsub(k, v) end data end end