Compel
Ruby Hash Coercion and Validation
This is a straight forward way to validate a Ruby Hash: just give an object and the schema.
The motivation was to create an integration for RestMyCase and have validations before any business logic execution.
Based on the same principle from Grape framework and sinatra-param gem to validate request params. The schema builder is based on Joi.
Usage
object = {
first_name: 'Joaquim',
birth_date: '1989-0',
address: {
line_one: 'Lisboa',
post_code: '1100',
country_code: 'PT'
}
}
schema = Compel.hash.keys({
first_name: Compel.string.required,
last_name: Compel.string.required,
birth_date: Compel.datetime,
address: Compel.hash.keys({
line_one: Compel.string.required,
line_two: Compel.string.default('-'),
post_code: Compel.string.format(/^\d{4}-\d{3}$/).required,
country_code: Compel.string.in(['PT', 'GB']).default('PT')
})
})
Compel.run(object, schema)
Will return an Hashie::Mash object:
{
"first_name" => "Joaquim",
"birth_date" => "1989-0",
"address" => {
"line_one" => "Lisboa",
"line_two" => "-",
"post_code" => "1100",
"country_code" => "PT"
},
"errors" => {
"last_name" => ["is required"],
"birth_date" => ["'1989-0' is not a parsable date with format: %Y-%m-%d"],
"address" => {
"post_code" => ["must match format ^\d{4}-\d{3}$"]
}
}
}
There are 4 ways to run validations:
| Method | Behaviour |
|---|---|
#run |
Validates and returns an Hash with coerced params plus a :errors key with a Rails like Hash of errors if any. |
#run! |
Validates and raises Compel::InvalidObjectError exception with the coerced params and errors. |
#run? |
Validates and returns true or false. |
schema#validate |
Check below |
==========================
Schema Builder API
Compel#array*is(array)#items(schema)ruby * ex: [1, 2, 3], [{ a: 1, b: 2}, { a: 3, b: 4 }]
Compel#hash*#keys(schema_hash)ruby * ex: { a: 1, b: 2, c: 3 }
Compel.date*#format(ruby_date_format)iso8601, set format to:%Y-%m-%d
Compel.datetime & Compel.time*#format(ruby_date_format)#iso8601, set format to:%FT%T
Compel#string**#format(regexp)#min_length(integer)#max_length(integer)
Compel#json** ex: "{\"a\":1,\"b\":2,\"c\":3}"Compel#boolean** ex: 1/0, true/false, 't'/'f', 'yes'/'no', 'y'/'n'Compel#integer**Compel#float**
(*) Common methods
requireddefault(value)
(**) Common value methods
is(value)in(array)length(integer)min(value)max(value)
Schema Validate
For straight forward validations, you can call #validate on schema and it will return a Compel::Result object.
result = Compel.string
.format(/^\d{4}-\d{3}$/)
.required
.validate('1234')
puts result.errors
# => ["must match format ^\\d{4}-\\d{3}$"]
Compel Result
Simple object that encapsulates a validation result.
| Method | Behaviour |
|---|---|
#value |
the coerced value or the input value is invalid |
#errors |
array of errors is any. |
#valid? |
true or false |
#raise? |
raises a Compel::InvalidObjectError if invalid, otherwise returns #value |
==========================
Sinatra Integration
If you want to use with Sinatra, here's an example:
class App < Sinatra::Base
set :show_exceptions, false
set :raise_errors, true
before do
content_type :json
end
helpers do
def compel(schema)
params.merge! Compel.run!(params, Compel.hash.keys(schema))
end
end
error Compel::InvalidObjectError do |exception|
status 400
{ errors: exception.object[:errors] }.to_json
end
configure :development do
set :show_exceptions, false
set :raise_errors, true
end
post '/api/posts' do
compel({
post: Compel.hash.keys({
title: Compel.string.required,
body: Compel.string,
published: Compel.boolean.default(false)
}).required
})
params.to_json
end
end
Installation
Add this line to your application's Gemfile:
gem 'compel', '~> 0.2.0'
And then execute:
$ bundle
TODO
- Write Advanced Documentation (check specs for now ;)
- Rails integration
- RestMyCase integration
Get in touch
If you have any questions, write an issue or get in touch @joaquimadraz