Skip to content

Commit

Permalink
JSON validation prototype.
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Oulevay committed Nov 25, 2014
1 parent 01478ee commit 562084b
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 23 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ source "https://rubygems.org"
group :development do
gem 'rake', '~> 10.3'
gem 'rspec', '~> 3.1'
gem 'rspec-collection_matchers', '~> 1.1.2'
gem 'jeweler', '~> 2.0'
gem 'rake-version', '~> 0.4'
gem 'simplecov', '~> 0.9'
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ GEM
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
rspec-mocks (~> 3.1.0)
rspec-collection_matchers (1.1.2)
rspec-expectations (>= 2.99.0.beta1)
rspec-core (3.1.6)
rspec-support (~> 3.1.0)
rspec-expectations (3.1.2)
Expand Down Expand Up @@ -92,4 +94,5 @@ DEPENDENCIES
rake (~> 10.3)
rake-version (~> 0.4)
rspec (~> 3.1)
rspec-collection_matchers (~> 1.1.2)
simplecov (~> 0.9)
18 changes: 14 additions & 4 deletions lib/errapi/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ module Errapi

module Model

def validate context, options = {}
self.class.errapi.validate self, context, options
def validate *args

options = args.last.kind_of?(Hash) ? args.pop : {}

name, context = :default, args.shift
if context.kind_of? Symbol
name = context
context = args.shift
end

self.class.errapi(name).validate self, context, options
end

def Model.included mod
Expand All @@ -12,8 +21,9 @@ def Model.included mod

module ClassMethods

def errapi &block
@errapi_validations ||= Validations.new(&block)
def errapi name = nil, &block
@errapi_validations ||= {}
@errapi_validations[name || :default] ||= Validations.new(&block)
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions lib/errapi/validation_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def error? criteria = {}
@errors.any?{ |err| err.matches? criteria }
end

def valid?
!error?
end

def clear
@errors.clear
end
Expand Down
64 changes: 45 additions & 19 deletions lib/errapi/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,28 @@ def initialize &block
end

def validates *args
register_validations *args
end

options = args.last.kind_of?(Hash) ? args.pop : {}
def validates_each *args

args = [ nil ] if args.empty?
options = args.last.kind_of?(Hash) ? args.pop : {}
options[:each] = args.shift

args.each do |target|
options.each_pair do |validator,validator_options|
next unless validator_options
if validator_options = validator_options.kind_of?(Hash) ? validator_options : {}
@validations << validator_options.merge(validator: validator, target: target)
end
end
end
args << options
register_validations *args
end

def validate value, context, options = {}

config = options.delete(:config) || Errapi.config

@validations.each do |validation|

target = validation[:target]
validator = validator config, validation[:validator]

if target.respond_to? :call
validator.validate target.call(value), context, validation
elsif !target.nil?
validator.validate value.send(target), context, validation
if options[:each]
values = extract options[:each], value
values.each{ |value| perform_validation value, validation, context, config } if values.kind_of? Array
else
validator.validate value, context, validation
perform_validation value, validation, context, config
end
end
end
Expand All @@ -47,5 +39,39 @@ def validate value, context, options = {}
def validator config, name
config.validators[name].new
end

def perform_validation value, validation, context, config
target = validation[:target]
validator = validator config, validation[:validator]
validator.validate extract(target, value), context, validation
end

def extract target, value
if target.respond_to? :call
target.call value
elsif value.respond_to? :[]
value[target]
elsif !target.nil?
value.send target
else
value
end
end

def register_validations *args

options = args.last.kind_of?(Hash) ? args.pop : {}
each_options = options[:each] ? { each: options.delete(:each) } : {}

args = [ nil ] if args.empty?

args.each do |target|
options.each_pair do |validator,validator_options|
next unless validator_options
validator_options = validator_options.kind_of?(Hash) ? validator_options : {}
@validations << validator_options.merge(validator: validator, target: target).merge(each_options)
end
end
end
end
end
25 changes: 25 additions & 0 deletions spec/example_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,35 @@
o.validate context
expect(context.error?).to be(true)
expect(context.error?(message: /cannot be null or empty/)).to be(true)
expect(context.errors).to have(1).item

context.clear
o.name = 'foo'
o.validate context
expect(context.error?).to be(false)
end

it "should validate parsed JSON" do

h = {
foo: 'bar',
baz: [
{ a: 'b' },
{ a: 'c' },
{ a: nil }
]
}

validations = Errapi::Validations.new do
validates :foo, presence: true
validates :qux, presence: true
validates_each :baz, :a, presence: true
end

validations.validate h, context

expect(context.error?).to be(true)
expect(context.error?(message: /cannot be null or empty/)).to be(true)
expect(context.errors).to have(2).items
end
end
1 change: 1 addition & 0 deletions spec/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
]

require 'rspec'
require 'rspec/collection_matchers'

Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each{ |f| require f }

Expand Down

0 comments on commit 562084b

Please sign in to comment.