require 'active_support/concern'
require 'active_model'
# comment single files bcs. AM requires lazy and in rails 4 names have changed!
# left them in for reference
#require 'active_model/validations'
#require 'active_model/naming'
#require 'active_model/translation'
#require 'active_model/conversion'
module SchemaTools
module Modules
# Add schema properties to a class by including this module and defining from
# which schema to inherit attributes.
module Validations
extend ActiveSupport::Concern
include ActiveModel::Conversion
include ActiveModel::Validations
#included do
# validate_with_schema :schema_name
#end
# Runs all the validations within the specified context. Returns true if no errors are found,
# false otherwise.
#
# If the argument is false (default is +nil+), the context is set to :create if
# new_record? is true, and to :update if it is not.
#
# Validations with no :on option will run no matter the context. Validations with
# some :on option will only run in the specified context.
def valid?(context = nil)
#context ||= (new_record? ? :create : :update)
output = super(context)
errors.empty? && output
end
module ClassMethods
# @param [Symbol|String] schema name
# @param [Hash] opts
# @options opts [String] :path schema path
# @options opts [SchemaTools::Reader] :reader instance, instead of global reader/registry
def validate_with(schema, opts={})
reader = opts[:reader] || SchemaTools::Reader
schema = reader.read(schema, opts[:path])
# make getter / setter
schema[:properties].each do |key, val|
validates_length_of key, validate_length_opts(val) if val['maxLength'] || val['minLength']
validates_presence_of key if val['required'] || val['required'] == 'true'
validates_numericality_of key, validate_number_opts(val) if val['type'] == 'number'
#TODO array minItems, max unique, null, string
# format: date-time, regex color style, email,uri, ..
validates_numericality_of key, validate_number_opts(val) if val['type'] == 'number'
#end
end
end
def validate_length_opts(attr)
opts = {}
opts[:within] = attr['minLength']..attr['maxLength'] if attr['minLength'] && attr['maxLength']
opts[:maximum] = attr['maxLength'] if attr['maxLength'] && !attr['minLength']
opts[:minimum] = attr['minLength'] if attr['minLength'] && !attr['maxLength']
opts[:allow_blank] = true if !attr['required']
opts
end
# @param [Hash] attr property values
def validate_number_opts(attr)
opts = {}
opts[:allow_blank] = true
# those vals should not be set both in one property
opts[:greater_than_or_equal_to] = attr['minimum'] if attr['minimum'].present?
opts[:less_than_or_equal_to] = attr['maximum'] if attr['maximum'].present?
opts[:less_than] = attr['exclusiveMinimum'] if attr['exclusiveMinimum'].present?
opts[:greater_than] = attr['exclusiveMaximum'] if attr['exclusiveMaximum'].present?
opts
end
end # ClassMethods
end
end
end