module Validations

Overview

Enables the including type to define attribute validations.

struct User
  include Validations

  property name : String
  property email : String
  @age : UInt8?
  @nilable : String?

  def initialize(@name, @email, @age : UInt8? = nil, @nilable : String? = nil)
  end

  validate name, size: (1..16)
  validate email, size: (6..64), regex: /\w+@\w+\.\w{2,}/
  validate @age, gte: 18

  # Will not be run if `@nilable.nil?`
  validate @nilable, size: (5..10)

  # Custom validations are allowed
  def validate
    previous_def
    invalidate("name", "must not be equal to Vadim") if name == "Vadim"
  end
end

user = User.new("Vadim", "e-mail", 17)
pp user.valid?
# false
pp user.invalid_attributes
# {
#   "name" => ["must have size in (1..16)", "must not be equal to Vadim"],
#   "email" => ["must have size in (6..64)", "must match /\\w+@\\w+\\.\\w{2,}/"],
#   "@age" => ["must be greater than or equal to 18"]
# }

Defined in:

validations.cr

Instance Method Summary

Macro Summary

Instance Method Detail

def invalid_attributes #

A hash of invalid attributes, if any.

Example:

pp user.invalid_attributes
# {"name" => ["is too long"], ["is not Slav enough"]}

[View source]
def valid! #

Roughly check if the including type is valid, raising Error otherwise.


[View source]
def valid? #

Gently check if the including type is valid.


[View source]

Macro Detail

macro invalidate(attribute, message) #

Mark attribute as invalid with message.


[View source]
macro validate(attribute, **rules) #

Validate attribute with inline rules unless it's nil.

validate name, size: (1..16)
validate email, regex: /\w+@\w+\.\w{2,}/
validate age, gte: 18

List of currently implemented inline rules:

  • is: Object - check if attribute == object
  • gte: Comparable - check if attribute >= comparable
  • lte: Comparable - check if attribute <= comparable
  • gt: Comparable - check if attribute > comparable
  • lt: Comparable - check if attribute < comparable
  • in: Enumerable - check if enumerable.includes?(attribute)
  • size: Enumerable - check if enumerable.includes?(attribute.size)
  • size: Int - check if attribute.size == int
  • regex: Regex - check if regex.match(attribute)

The #validate method can also be redefined to run custom validations:

def validate
  previous_def # Mandatory, otherwise previous validations won't run
  invalidate("name", "some error") if name == "Foo"
end

[View source]