module Check

Overview

Standalone check module that provides a practical workflow for validations.

Defined in:

check.cr
checkable.cr

Constant Summary

RULES = {} of String => HashLiteral(String, ASTNode)

Class Method Summary

Macro Summary

Class Method Detail

def self.new_validation(errors : Errors) #

Initializes a new Validation instance to combine a series of checks (Validation#check). using an existing errors Hash (Check::Errors).

v = Check.new_validation existing_errors

Same as:

v = Check::Validation.new existing_errors

Example to combine two hashes of validation errors:

preview_validation = Check.new_validation
v = Check.new_validation preview_validation.errors

def self.new_validation #

Initializes a new Validation instance to combine a series of checks (Validation#check).

v = Check.new_validation

Same as:

v = Check::Validation.new

Macro Detail

macro checkable #

A mixin to make a class checkable. This mixin includes Checkable and CheckableStatic. It must be used in conjonction with Check.rules.

require "validator/check"

class Article
  # Mixin
  Check.checkable

  property title : String
  property content : String, {
    required: true,
    check:    {
      not_empty: {"Article content is required"},
      between:   {"The article content must be between 10 and 20 000 characters", 10, 20_000},
      # ...
    },
    clean: {
      type:    String,
      to:      :to_s,
      format:  ->(content : String) { content.strip },
      message: "Wrong type",
    },
  }
end

# Triggered on all data
v, article = Article.check(input_data)

# Triggered on a value
v, content = Article.check_content(input_data["content"]?)

macro rules(**fields) #

Generates check, check_{{field}} and clean_{{field}} methods for fields (class variables).

require "validator/check"

class Article
  # Mixin
  Check.checkable

  property title : String
  property content : String
  property url : String?

  private def self.after_check_content(v : Check::Validation, content : String?, required : Bool, format : Bool)
    puts "after_check_content"
    puts "Valid? #{v.valid?}"
    content
  end

  Check.rules(
    content: {
      required:     "Content is required", # or `true` to use the default error message
      before_check: ->(v : Check::Validation, content : String?, required : Bool, format : Bool) {
        puts "before_check_content"
        content
      },
      after_check: :after_check_email,
      check:       {
        not_empty: {"Article content is required"},
        between:   {"The article content must be between 10 and 20 000 characters", 10, 20_000},
        # ...
      },
      clean: {
        type: String,
        to:   :to_s,
        # Proc or method name (Symbol)
        format:  ->(content : String) { content.strip },
        message: "Wrong type",
      },
    },
    url: {
      check: {
        url: {"Article URL is invalid"},
      },
      clean: {
        # `nilable` means omited if not provided,
        # regardless of Crystal type (nilable or not)
        nilable: true,
        # Crystal type
        type: String,
        # Converter to the expected typed value
        to: :to_s,
      },
    },
      # ...
)
end

# Triggered on all data
v, article = Article.check(input_data)

# Triggered on all fields of an instance
article = Article.new(title: "foo", content: "bar")
v = article.check

# Triggered on a value
v, content = Article.check_content(input_data["content"]?)

# Cast and clean a value
ok, content = Article.clean_content(input_data["content"]?)

See also Check.checkable.