module Hval module Validators # Validators return a Proc to be called with a value to test, # this call return a result which is an array of 4 elements with: # - a name (validator name, eg.: :type) # - an expected value (eg.: String) # - a result which can be true, false or another result array # - the given value # # ==== Example # # irb> include Hval::Validators # irb> validate_format?(/guy/).call("guybrush") # => [:format, /guy/, true, "guybrush"] # irb> validate_type?(String).call(10) # => [:type, String, false, 10] # Validates the format of a value with a regular expression # # ==== Example # # irb> include Hval::Validators # irb> validate_format?(/guy/).call("guybrush") # => [:format, /guy/, true, "guybrush"] def validate_format?(spec) -> (value) { res = if value.respond_to? :match? value.match?(spec) else false end [ :format, spec, res, value ] } end # Validates the minimal size of a value with an Number # # ==== Example # # irb> include Hval::Validators # irb> validate_min_size?(10).call(13) # => [:min_size, 10, true, 13] def validate_min_size?(spec) -> (value) { res = case value when Enumerable, String value.size >= spec when Numeric value >= spec end [ :min_size, spec, res, value ] } end # Validates the maximal size of a value with an Number # # ==== Example # # irb> include Hval::Validators # irb> validate_max_size?(10).call(9) # => [:max_size, 10, true, 9] def validate_max_size?(spec) -> (value) { res = case value when Enumerable, String value.size <= spec when Numeric value <= spec end [ :max_size, spec, res, value ] } end # Validates a type of a given value # # ==== Example # # irb> include Hval::Validators # irb> validate_type?(String).call(10) # => [:type, String, false, 10] def validate_type?(spec) -> (value) { [ :type, spec, value.is_a?(spec), value ] } end # Validates that a value is included in a list # # ==== Example # # irb> include Hval::Validators # irb> validate_enum?([1,2,3,4]).call(2) # => [:enum, [1, 2, 3, 4], true, 2] def validate_enum?(spec) -> (value) { [ :enum, spec, spec.include?(value), value ] } end # Validates a value with a block. The block must return the result # in the array format [name, spec, result, given] # # ==== Example # # irb> include Hval::Validators # irb> _proc = ->(val){ [:proc, :greater_than_ten, val > 10, val] } # irb> validate_proc?(_proc).(10) # => [:proc, :greater_than_ten, false, 10] def validate_proc?(spec) -> (value) { spec.call(value) } end # Validates that the elements of an Array conform the schema # # ==== Example # # irb> include Hval::Validators # irb> validate_array?({type?: Integer}).([1,2,3,4,5]) # => [:array, {:type?=>Integer}, true, [1, 2, 3, 4, 5]] # irb> validate_array?({type?: String}).([1,2,3,4,5]) # => [:array, {:type?=>String}, false, [1, 2, 3, 4, 5]] def validate_array?(spec) -> (values) { res = if values.is_a? Array values.all? { |value| Hval::Schema.new(spec).match?(value) } else false end [ :array, spec, res, values ] } end # Validates that a value conform a schema only if provided. Nil or blank are allowed. # # ==== Example # # irb> include Hval::Validators # irb> validate_optional?({type?: Integer}).(1) # => [:optional, {:type?=>Integer}, true, 1] # irb> validate_optional?({type?: Integer}).(nil) # => [:optional, {:type?=>Integer}, true, nil] # irb> validate_optional?({type?: Integer}).("asdasd") # => [:optional, {:type?=>Integer}, false, "asdasd"] def validate_optional?(spec) -> (value) { res = case value when NilClass, "" true else Hval::Schema.new(spec).match?(value) end [ :optional, spec, res, value ] } end # Validates a Hash against a schema. # # The result on hashes also contains the key with the results associated with the key. As many results as validators defined. # # ==== Example # # irb> include Hval::Validators # irb> validate_hash?({name: {type?: String}}).({name: "carlos"}) # => [:hash, {:name=>{:type?=>String}}, [[:name, [[:type, String, true, "carlos"]]]], {:name=>"carlos"}] # irb> validate_hash?({name: {type?: String}}).({name: 123}) # => [:hash, {:name=>{:type?=>String}}, [[:name, [[:type, String, false, 123]]]], {:name=>123}] # irb> validate_hash?({name: {type?: String, format?: /carl/}}).({name: 123}) # => [:hash, {:name=>{:type?=>String, :format?=>/carl/}}, [[:name, [[:type, String, false, 123], [:format, /carl/, false, 123]]]], {:name=>123}] def validate_hash?(spec) -> (value) { res = if value.is_a? Hash Hval::Validator.new(spec).call(value) else false end [ :hash, spec, res, value ] } end end end