Module: Odin::Validation::FormatValidators

Defined in:
lib/odin/validation/format_validators.rb

Constant Summary collapse

EMAIL_RE =

Email: RFC 5322 simplified

/\A[^@\s]+@[^@\s]+\.[^@\s]+\z/
URI_RE =

URI: scheme:non-whitespace

/\A[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*\z/
URL_RE =

URL: http(s)://…

%r{\Ahttps?://[^\s/$.?#].[^\s]*\z}
UUID_RE =

UUID: 8-4-4-4-12 hex

/\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\z/
DATE_RE =

Date: YYYY-MM-DD

/\A\d{4}-\d{2}-\d{2}\z/
TIME_RE =

Time: HH:MM:SS or HH:MM

/\A[T]?\d{2}:\d{2}(:\d{2})?\z/
DATETIME_RE =

DateTime: ISO 8601

/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
DURATION_RE =

Duration: ISO 8601 P…

/\AP(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+(\.\d+)?S)?)?\z/
HOSTNAME_RE =

Hostname: RFC 952/1123

/\A[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)*\z/
PHONE_RE =

Phone: international format

/\A\+?[\d\s\-().]{7,20}\z/
CREDIT_CARD_RE =

Credit card: 13-19 digits

/\A\d{13,19}\z/
SSN_RE =

SSN: 123-45-6789 or 123456789

/\A\d{3}-?\d{2}-?\d{4}\z/
NAIC_RE =

NAIC: 5-digit insurance code

/\A\d{5}\z/
EIN_RE =

EIN/FEIN: 12-3456789

/\A\d{2}-\d{7}\z/
FEIN_RE =
EIN_RE
ZIP_RE =

ZIP: 12345 or 12345-6789

/\A\d{5}(-\d{4})?\z/
VIN_RE =

VIN: 17 chars, no I/O/Q

/\A[A-HJ-NPR-Z0-9]{17}\z/
IBAN_RE =

IBAN: 2 letters + 2 digits + up to 30 alphanumeric

/\A[A-Z]{2}\d{2}[A-Z0-9]{4,30}\z/
BIC_RE =

BIC/SWIFT: 8 or 11 chars

/\A[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?\z/
ROUTING_RE =

Routing number: 9 digits

/\A\d{9}\z/
CUSIP_RE =

CUSIP: 9 chars alphanumeric

/\A[A-Z0-9]{9}\z/
ISIN_RE =

ISIN: 2 letters + 9 chars + 1 check digit

/\A[A-Z]{2}[A-Z0-9]{9}\d\z/
LEI_RE =

LEI: 20 chars alphanumeric

/\A[A-Z0-9]{20}\z/
NPI_RE =

NPI: 10 digits

/\A\d{10}\z/
DEA_RE =

DEA: 2 chars + 7 digits

/\A[A-Z]{2}\d{7}\z/
IMEI_RE =

IMEI: 15 digits

/\A\d{15}\z/
ICCID_RE =

ICCID: 19-20 digits

/\A\d{19,20}\z/
HEX_RE =

Hex: hex string

/\A[0-9a-fA-F]+\z/
CURRENCY_CODES =

ISO 4217 currency codes

%w[
  AED AFN ALL AMD ANG AOA ARS AUD AWG AZN
  BAM BBD BDT BGN BHD BIF BMD BND BOB BRL
  BSD BTN BWP BYN BZD CAD CDF CHF CLP CNY
  COP CRC CUP CVE CZK DJF DKK DOP DZD EGP
  ERN ETB EUR FJD FKP GBP GEL GHS GIP GMD
  GNF GTQ GYD HKD HNL HRK HTG HUF IDR ILS
  INR IQD IRR ISK JMD JOD JPY KES KGS KHR
  KMF KPW KRW KWD KYD KZT LAK LBP LKR LRD
  LSL LYD MAD MDL MGA MKD MMK MNT MOP MRU
  MUR MVR MWK MXN MYR MZN NAD NGN NIO NOK
  NPR NZD OMR PAB PEN PGK PHP PKR PLN PYG
  QAR RON RSD RUB RWF SAR SBD SCR SDG SEK
  SGD SHP SLE SOS SRD SSP STN SVC SYP SZL
  THB TJS TMT TND TOP TRY TTD TWD TZS UAH
  UGX USD UYU UZS VES VND VUV WST XAF XCD
  XOF XPF YER ZAR ZMW ZWL
].to_set.freeze
US_STATES =

US state/territory codes

%w[
  AK AL AR AS AZ CA CO CT DC DE
  FL GA GU HI IA ID IL IN KS KY
  LA MA MD ME MI MN MO MP MS MT
  NC ND NE NH NJ NM NV NY OH OK
  OR PA PR RI SC SD TN TX UT VA
  VI VT WA WI WV WY
].to_set.freeze
VALIDATORS =
{
  "email"         => ->(v) { EMAIL_RE.match?(v) },
  "uri"           => ->(v) { URI_RE.match?(v) },
  "url"           => ->(v) { URL_RE.match?(v) },
  "uuid"          => ->(v) { UUID_RE.match?(v) },
  "date"          => ->(v) { DATE_RE.match?(v) },
  "time"          => ->(v) { TIME_RE.match?(v) },
  "datetime"      => ->(v) { DATETIME_RE.match?(v) },
  "date-time"     => ->(v) { DATETIME_RE.match?(v) },
  "date-iso"      => ->(_v) { true },
  "duration"      => ->(v) { DURATION_RE.match?(v) },
  "hostname"      => ->(v) { HOSTNAME_RE.match?(v) && v.length <= 253 },
  "ipv4"          => ->(v) { validate_ipv4(v) },
  "ipv6"          => ->(v) { validate_ipv6(v) },
  "phone"         => ->(v) { PHONE_RE.match?(v) },
  "credit-card"   => ->(v) { validate_creditcard(v) },
  "creditcard"    => ->(v) { validate_creditcard(v) },
  "ssn"           => ->(v) { validate_ssn(v) },
  "ein"           => ->(v) { EIN_RE.match?(v) },
  "fein"          => ->(v) { EIN_RE.match?(v) },
  "zip"           => ->(v) { ZIP_RE.match?(v) },
  "vin"           => ->(v) { VIN_RE.match?(v.upcase) },
  "iban"          => ->(v) { IBAN_RE.match?(v.upcase) },
  "bic"           => ->(v) { BIC_RE.match?(v.upcase) },
  "swift"         => ->(v) { BIC_RE.match?(v.upcase) },
  "routing"       => ->(v) { ROUTING_RE.match?(v) },
  "cusip"         => ->(v) { CUSIP_RE.match?(v.upcase) },
  "isin"          => ->(v) { ISIN_RE.match?(v.upcase) },
  "lei"           => ->(v) { LEI_RE.match?(v.upcase) },
  "npi"           => ->(v) { NPI_RE.match?(v) },
  "naic"          => ->(v) { NAIC_RE.match?(v) },
  "dea"           => ->(v) { DEA_RE.match?(v.upcase) },
  "imei"          => ->(v) { IMEI_RE.match?(v) },
  "iccid"         => ->(v) { ICCID_RE.match?(v) },
  "hex"           => ->(v) { HEX_RE.match?(v) },
  "currency-code" => ->(v) { v.length == 3 && v.match?(/\A[A-Z]{3}\z/) && CURRENCY_CODES.include?(v) },
  "state-us"      => ->(v) { v.length == 2 && v.match?(/\A[A-Z]{2}\z/) && US_STATES.include?(v) },
}.freeze

Class Method Summary collapse

Class Method Details

.known?(format_name) ⇒ Boolean

Returns:

  • (Boolean)


166
167
168
# File 'lib/odin/validation/format_validators.rb', line 166

def self.known?(format_name)
  VALIDATORS.key?(format_name)
end

.validate(format_name, value) ⇒ Object



159
160
161
162
163
164
# File 'lib/odin/validation/format_validators.rb', line 159

def self.validate(format_name, value)
  validator = VALIDATORS[format_name]
  return true unless validator # unknown format is permissive
  return false unless value.is_a?(String)
  validator.call(value)
end