Skip to content

Commit

Permalink
Renames Validators to Predicates
Browse files Browse the repository at this point in the history
  • Loading branch information
eliasjpr committed Dec 26, 2020
1 parent 3aff189 commit 1e40377
Show file tree
Hide file tree
Showing 17 changed files with 42 additions and 41 deletions.
57 changes: 29 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ class User < Model
property childrens : Array(String)
property childrens_ages : Array(Int32)
# To use a custom validator, this will enable the predicate `unique_record`
# which is derived from the class name minus `validator`
# To use a custom validator. UniqueRecordValidator will be initialized with an `User` instance
use UniqueRecordValidator
# Use the `custom` class name predicate as follow
Expand All @@ -182,13 +181,12 @@ class User < Model
end
```

## Custom Validations
### Custom Validations

Simply create a class `{Name}Validator` with the following signature:

```crystal
class EmailValidator < Schema::Validator
include Schema::Validators
getter :record, :field, :message
def initialize(@record : UserModel)
Expand All @@ -215,11 +213,9 @@ class UniqueRecordValidator < Schema::Validator
end
```

Notice that `unique_record:` corresponds to `UniqueRecord`Validator.
### Defining Predicates

### Defining Your Own Predicates

You can define your custom predicates by simply creating a custom validator or creating methods in the `Schema::Validators` module ending with `?` and it should return a `boolean`. For example:
You can define your custom predicates by simply creating a custom validator or creating methods in the `Schema::Predicates` module ending with `?` and it should return a `boolean`. For example:

```crystal
class User < Model
Expand All @@ -230,13 +226,16 @@ class User < Model
property childrens : Array(String)
property childrens_ages : Array(Int32)
...
validate password : String, presence: true
...
# Uses a `presense` predicate
validate password : String, presence: true
predicates do
def presence?(password : String, _other : String) : Bool
!value.nil?
end
# Use the `predicates` macro to define predicate methods
predicates do
# Presence Predicate Definition
def presence?(password : String, _other : String) : Bool
!value.nil?
end
end
Expand All @@ -245,15 +244,25 @@ class User < Model
end
```

### Differences: Custom Validator vs Predicates

The differences between a custom validator and a method predicate are:

- Custom validators receive an instance of the object as a `record` instance var.
- Custom validators allow for more control over validations.
- Predicates are assertions against the class properties (instance var).
- Predicates matches property value with predicate value.
**Custom Validators**
- Must be inherited from `Schema::Validator` abstract
- Receives an instance of the object as a `record` instance var.
- Must have a `:field` and `:message` defined.
- Must implement a `def valid? : Array(Schema::Error)` method.

**Predicates**
- Assertions of the property value against an expected value.
- Predicates are light weight boolean methods.
- Predicates methods must be defined as `def {predicate}?(property_value, expected_value) : Bool` .

### Built in Predicates

These are the current available predicates.

```crystal
gte - Greater Than or Equal To
lte - Less Than or Equal To
Expand All @@ -265,23 +274,15 @@ regex - Regular Expression
eq - Equal
```

> **CONTRIBUTE** - Add more predicates to this shards by contributing a Pull Request.
Additional params

```crystal
message - Error message to display
nilable - Allow nil, true or false
```

## Development (Help Wanted!)

API subject to change until marked as released version

Things left to do:

- [x] Validate nested - When calling `valid?` validates schemas.
- [x] Build nested `json`- Currently `json` do not support the sub schemas.
- [x] Document Custom Converter for custom types.

## Contributing

1. Fork it (<https://github.com/your-github-user/schemas/fork>)
Expand Down
1 change: 0 additions & 1 deletion spec/validation_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class UserModel
end

class EmailValidator < Schema::Validator
include Schema::Validators
getter :record, :field, :message

def initialize(@record : UserModel)
Expand Down
4 changes: 2 additions & 2 deletions spec/validators_spec.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "./spec_helper"
include Schema::Validators
include Schema::Predicates

describe Schema::Validators do
describe Schema::Predicates do
describe "#eq?" do
it { eq?(1, 1).should be_true }
it { eq?("one", "one").should be_true }
Expand Down
12 changes: 6 additions & 6 deletions src/schema/validation.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require "./validation/validators"
require "./validation/predicates"
require "./validation/error"
require "./validation/validator"
require "./validation/constraint"
Expand All @@ -25,14 +25,14 @@ module Schema
end

macro predicates
module Schema::Validators
module Schema::Predicates
{{yield}}
end
end

macro create_validator(type_validator)
{% type_validator = type_validator.resolve %}

class Validator
def self.validate(instance : {{type_validator}})
errors = Array(Schema::Error).new
Expand All @@ -42,18 +42,18 @@ module Schema
errors + rule.valid?
end
end

private def self.validations(rules, instance)
{% for validtor in type_validator.constant(:SCHEMA_VALIDATORS) %}
rules << {{validtor}}.new(instance)
{% end %}

rules << Schema::Constraint.new do |rule, errors|
{% for name, options in type_validator.constant(:SCHEMA_VALIDATIONS) %}
{% for predicate, expected_value in options %}
{% if !["message"].includes?(predicate.stringify) %}
unless rule.{{predicate.id}}?(instance.{{name.id}}, {{expected_value}})
errors << Schema::Error.new(:{{name.id}}, {{options["message"] || "Invalid field: " + name.stringify}})
errors << Schema::Error.new(:{{name.id}}, {{options["message"] || "Invalid field: " + name.stringify}})
end
{% end %}
{% end %}
Expand Down
3 changes: 2 additions & 1 deletion src/schema/validation/constraint.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Schema
class Constraint
include Schema::Validators
include Schema::Predicates

@errors = Array(Schema::Error).new

def initialize(&block : Constraint, Array(Schema::Error) -> Nil)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "./validators/*"
require "./predicates/*"

module Schema
module Validators
module Predicates
include Equal
include Exclusion
include GreaterThan
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/schema/validation/validator.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Schema
abstract class Validator
include Schema::Validators
include Schema::Predicates

def initialize(@record)
end
Expand Down

0 comments on commit 1e40377

Please sign in to comment.