## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## ----setup--------------------------------------------------------------------
library(fluffy)

## ----add_rule definition, eval=FALSE------------------------------------------
# add_rule(
#   obj,
#   name,
#   validator_fn,
#   schema_fn = NULL,
#   rule_type = c("validate", "control", "transform", "finalize")
# )

## ----schema validation function arg examples, echo=FALSE, results='asis'------
knitr::kable(
  data.frame(
    " " = "`function(field, ...)`",
    " " = "`function(field, .schema ...)` or `function(field, .self ...)`",
    " " = "`function(field, .schema, .self)`",
    check.names = FALSE,
    fix.empty.names = FALSE
  )
)

## ----data validation function arg examples, echo=FALSE, results='asis'--------
knitr::kable(
  data.frame(
    " " = "`function(field, schema_field, ...)`",
    " " = "`function(field, schema_field, .data ...)` or `function(field, schema_field, .self ...)`",
    " " = "`function(field, schema_field, .data, .self)`",
    check.names = FALSE,
    fix.empty.names = FALSE
  )
)

## ----schema validation function example, eval=FALSE---------------------------
# schema_validation_fn <- function(field, ...) {
#   if (!is.character(field) || length(field) != 1L) {
#     "Must be a length 1 character."
#   }
# }

## ----empty schema validation function example, eval=FALSE---------------------
# allow_any_schema_fn <- function(field, ...) {}

## ----list return example, eval=FALSE------------------------------------------
# return(list(error = ..., data = ..., continue = ...))

## ----data validation function example, eval=FALSE-----------------------------
# data_validation_fn <- function(data_field, schema_field, ...) {
#   if (!is.character(data_field) || length(data_field) != 1L) {
#     list(error = "Data must be a length 1 character.")
#   } else {
#     list(data = paste0(data_field, schema_field))
#   }
# }

## ----data validation function example 2---------------------------------------
Validator(
  data = list(a = 1),
  schema = list(
    b = list(
      required = FALSE,
      type = "character",
      min_length = 5L
    )
  )
)@valid

## ----rule categories----------------------------------------------------------
r <- Registry()
r@control_rules # first pass
r@transform_rules # second pass
r@validate_rules # third pass
r@finalize_rules # fourth pass

## ----add_type_rule add_coerce_rule definition, eval=FALSE---------------------
# add_type_rule(obj, type_name, type_fn)
# 
# add_coerce_rule(obj, coerce_name, coerce_fn)

## ----add_type_rule example----------------------------------------------------
s <- Schema(list(type = "my_type"))
s@valid
s@errors

s <- add_type_rule(s, "my_type", function(x) isTRUE(class(x) == "my_type"))
s@valid

v <- Validator(1L, s)
v@valid
v@errors

s@schema <- list(coerce = "my_type", type = "my_type")
s@valid
s@errors

s <- add_coerce_rule(s, "my_type", function(x) structure(x, class = "my_type"))
s@valid

v <- Validator(1L, s)
v@valid
v@data

## ----add_cross_rule definition, eval=FALSE------------------------------------
# add_cross_rule(obj, name, rule_names, cross_fn)

## ----add_cross_rule example---------------------------------------------------
s <- Schema(list(min_length = 5, min_val = 5))

s <- add_cross_rule(
  s,
  name = "min_length_cannot_equal_min_val",
  rule_names = c("min_length", "min_val"),
  cross_fn = function(node, ...) {
    if (node$min_length >= node$min_val) {
      "min_length must be less than min_val."
    }
  }
)
s@valid
s@errors

## ----fluffy extending validate example, error=TRUE----------------------------
try({
mySchema <- Schema(list(check_my_attr = 1L))
mySchema@errors

mySchema <- add_rule(
  obj = mySchema,
  name = "check_my_attr",
  validator_fn = function(data_field, schema_field, ...) {
    if (attr(data_field, "my_attr") != schema_field) {
      list(error = "Data doesn't match schema 'my_attr'.")
    }
  },
  schema_fn = function(schema_field, ...) {
    if (!is.character(schema_field) || length(schema_field) != 1L) {
      "Must be length 1 character"
    }
  },
  rule_type = "validate"
)

mySchema@errors
mySchema@schema$check_my_attr <- "Hi"

Validator(structure(1L, my_attr = "Hi"), mySchema)@valid
Validator(structure(1L, my_attr = 1L), mySchema, error = TRUE)
})

## ----fluffy extending transform example, error=TRUE---------------------------
try({
s <- Schema(list(double_if_five_else_error = TRUE))
s@valid

s <- add_rule(
  s,
  name = "double_if_five_else_error",
  validator_fn = function(field, schema_field, ...) {
    if (schema_field) {
      if (field != 5) {
        list(error = "Does not equal 5.")
      } else {
        list(data = field * 2)
      }
    }
  },
  schema_fn = function(schema_field, ...) {
    if (!isTRUE(schema_field) && !isFALSE(schema_field)) {
      "Must be a boolean."
    }
  },
  rule_type = "transform"
)
s@valid

v <- Validator(data = 5, schema = s)
v@valid
v@data
Validator(data = 1, schema = s, error = TRUE)
})

