schemacop 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.rubocop.yml +59 -1
  4. data/CHANGELOG.md +10 -0
  5. data/README.md +389 -199
  6. data/Rakefile +2 -0
  7. data/VERSION +1 -1
  8. data/doc/Schemacop.html +41 -130
  9. data/doc/Schemacop/ArrayValidator.html +329 -0
  10. data/doc/Schemacop/BooleanValidator.html +145 -0
  11. data/doc/Schemacop/Collector.html +535 -0
  12. data/doc/Schemacop/Exceptions.html +39 -39
  13. data/doc/Schemacop/Exceptions/InvalidSchemaError.html +124 -0
  14. data/doc/Schemacop/Exceptions/ValidationError.html +124 -0
  15. data/doc/Schemacop/FieldNode.html +409 -0
  16. data/doc/Schemacop/FloatValidator.html +158 -0
  17. data/doc/Schemacop/HashValidator.html +263 -0
  18. data/doc/Schemacop/IntegerValidator.html +158 -0
  19. data/doc/Schemacop/NilValidator.html +145 -0
  20. data/doc/Schemacop/Node.html +1426 -0
  21. data/doc/Schemacop/NodeResolver.html +242 -0
  22. data/doc/Schemacop/NodeSupportingField.html +590 -0
  23. data/doc/Schemacop/NodeSupportingType.html +614 -0
  24. data/doc/Schemacop/NodeWithBlock.html +289 -0
  25. data/doc/Schemacop/NumberValidator.html +232 -0
  26. data/doc/Schemacop/ObjectValidator.html +288 -0
  27. data/doc/Schemacop/RootNode.html +171 -0
  28. data/doc/Schemacop/Schema.html +697 -0
  29. data/doc/Schemacop/StringValidator.html +295 -0
  30. data/doc/ScopedEnv.html +351 -0
  31. data/doc/_index.html +190 -47
  32. data/doc/class_list.html +24 -31
  33. data/doc/css/full_list.css +32 -31
  34. data/doc/css/style.css +244 -91
  35. data/doc/file.README.html +428 -232
  36. data/doc/file_list.html +26 -30
  37. data/doc/frames.html +7 -16
  38. data/doc/index.html +428 -232
  39. data/doc/inheritance.graphml +524 -0
  40. data/doc/inheritance.pdf +825 -0
  41. data/doc/js/app.js +106 -77
  42. data/doc/js/full_list.js +170 -135
  43. data/doc/method_list.html +494 -38
  44. data/doc/top-level-namespace.html +36 -36
  45. data/lib/schemacop.rb +22 -7
  46. data/lib/schemacop/collector.rb +34 -0
  47. data/lib/schemacop/exceptions.rb +2 -8
  48. data/lib/schemacop/field_node.rb +26 -0
  49. data/lib/schemacop/node.rb +127 -0
  50. data/lib/schemacop/node_resolver.rb +14 -0
  51. data/lib/schemacop/node_supporting_field.rb +62 -0
  52. data/lib/schemacop/node_supporting_type.rb +112 -0
  53. data/lib/schemacop/node_with_block.rb +16 -0
  54. data/lib/schemacop/root_node.rb +4 -0
  55. data/lib/schemacop/schema.rb +61 -0
  56. data/lib/schemacop/scoped_env.rb +18 -0
  57. data/lib/schemacop/validator/array_validator.rb +30 -0
  58. data/lib/schemacop/validator/boolean_validator.rb +5 -0
  59. data/lib/schemacop/validator/float_validator.rb +5 -0
  60. data/lib/schemacop/validator/hash_validator.rb +18 -0
  61. data/lib/schemacop/validator/integer_validator.rb +5 -0
  62. data/lib/schemacop/validator/nil_validator.rb +5 -0
  63. data/lib/schemacop/validator/number_validator.rb +19 -0
  64. data/lib/schemacop/validator/object_validator.rb +21 -0
  65. data/lib/schemacop/validator/string_validator.rb +37 -0
  66. data/schemacop.gemspec +7 -5
  67. data/test/custom_check_test.rb +86 -0
  68. data/test/custom_if_test.rb +95 -0
  69. data/test/nil_dis_allow_test.rb +41 -0
  70. data/test/short_forms_test.rb +316 -0
  71. data/test/test_helper.rb +6 -0
  72. data/test/types_test.rb +83 -0
  73. data/test/validator_array_test.rb +97 -0
  74. data/test/validator_boolean_test.rb +15 -0
  75. data/test/validator_float_test.rb +57 -0
  76. data/test/validator_hash_test.rb +71 -0
  77. data/test/validator_integer_test.rb +46 -0
  78. data/test/validator_nil_test.rb +13 -0
  79. data/test/validator_number_test.rb +60 -0
  80. data/test/validator_object_test.rb +87 -0
  81. data/test/validator_string_test.rb +76 -0
  82. metadata +78 -14
  83. data/doc/Schemacop/Exceptions/Base.html +0 -127
  84. data/doc/Schemacop/Exceptions/InvalidSchema.html +0 -141
  85. data/doc/Schemacop/Exceptions/Validation.html +0 -142
  86. data/doc/Schemacop/MethodValidation.html +0 -120
  87. data/doc/Schemacop/MethodValidation/ClassMethods.html +0 -196
  88. data/doc/Schemacop/Validator.html +0 -254
  89. data/lib/schemacop/validator.rb +0 -145
  90. data/test/schemacop_validator_test.rb +0 -257
@@ -0,0 +1,112 @@
1
+ module Schemacop
2
+ class NodeSupportingType < NodeWithBlock
3
+ block_method :type
4
+
5
+ def self.build(options, &block)
6
+ new(nil, options, &block)
7
+ end
8
+
9
+ def initialize(options = {}, &block)
10
+ super(options)
11
+
12
+ @types = []
13
+ exec_block(&block)
14
+
15
+ if @types.none?
16
+ fail Exceptions::InvalidSchemaError, 'Block must contain a type definition or not be given at all.' if block_given?
17
+ type :object
18
+ end
19
+
20
+ # if @types.none?
21
+ # super(options)
22
+ # exec_block(&block)
23
+ # if @types.none?
24
+ # fail Exceptions::InvalidSchemaError, 'Block must contain a type definition or not be given at all.' if block_given?
25
+ # end
26
+ # else
27
+ # super({})
28
+ # end
29
+ end
30
+
31
+ def exec_block(&block)
32
+ super
33
+ rescue NoMethodError
34
+ @types = []
35
+ type :hash, {}, &block
36
+ end
37
+
38
+ # required signature:
39
+ # First argument must be a type or an array of types
40
+ # Following arguments may be subtypes
41
+ # Last argument may be an options hash.
42
+ # Options and given block are passed to the last specified type.
43
+ # Not permitted to give subtypes / options / a block if an array of types is given.
44
+ #
45
+ # TODO: Probably change this method so that the 'rescue NoMethodError'
46
+ # happens in here directly and not in the constructor. This way we can
47
+ # always call 'type', even if we don't have one and the type is auto-guessed
48
+ # as it formerly was the case in the constructor.
49
+ def type(*args, &block)
50
+ options = args.last.is_a?(Hash) ? args.pop : {}
51
+ types = [*args.shift]
52
+ subtypes = args
53
+
54
+ unless types.any?
55
+ fail Exceptions::InvalidSchemaError, 'At least one type must be given.'
56
+ end
57
+
58
+ if subtypes.any? && types.size > 1
59
+ fail Exceptions::InvalidSchemaError, "First given type can't be an array if subtypes are given."
60
+ end
61
+
62
+ if types.size > 1 && options.any?
63
+ fail Exceptions::InvalidSchemaError, 'No options can be specified if multiple types are given.'
64
+ end
65
+
66
+ types.each do |type|
67
+ klass = resolve_type_klass(type)
68
+
69
+ if subtypes.any?
70
+ unless klass <= NodeSupportingType
71
+ fail "Node #{klass} does not support subtypes."
72
+ end
73
+
74
+ child = klass.new do
75
+ self.type(*subtypes, options, &block)
76
+ end
77
+
78
+ # child = klass.build(options)
79
+ #
80
+ #
81
+ # child.type(*subtypes, &block)
82
+ else
83
+ if klass == ObjectValidator && type.is_a?(Class)
84
+ options[:classes] = type
85
+ end
86
+
87
+ child = klass.new(options, &block)
88
+ end
89
+
90
+ @types << child
91
+ end
92
+ end
93
+
94
+ def validate(data, collector)
95
+ super
96
+
97
+ validate_types(data, collector)
98
+ end
99
+
100
+ protected
101
+
102
+ def validate_types(data, collector)
103
+ unless (match = @types.find { |t| t.type_matches?(data) })
104
+ allowed_types = @types.map(&:type_label)
105
+
106
+ collector.error "Data type not matching: #{data.class}, allowed types: #{allowed_types.join('; ')}"
107
+ return
108
+ end
109
+ match.validate(data, collector)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,16 @@
1
+ module Schemacop
2
+ class NodeWithBlock < Node
3
+ class_attribute :block_methods
4
+ self.block_methods = [].freeze
5
+
6
+ def self.block_method(name)
7
+ self.block_methods += [name]
8
+ end
9
+
10
+ def exec_block(&block)
11
+ return unless block_given?
12
+ se = ScopedEnv.new(self, self.class.block_methods)
13
+ se.instance_exec(&block)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ module Schemacop
2
+ class RootNode < NodeSupportingType
3
+ end
4
+ end
@@ -0,0 +1,61 @@
1
+ module Schemacop
2
+ class Schema
3
+ # Create a new Schema
4
+ #
5
+ # For detailed usage, please refer to README.md in the root of this project.
6
+ #
7
+ # @param args [Array] An array of arguments to apply to the root node of the
8
+ # Schema.
9
+ # @param block A block with further Schema specification.
10
+ # @raise [Schemacop::Exceptions::InvalidSchemaError] If the Schema defined
11
+ # is invalid.
12
+ def initialize(*args, &block)
13
+ @root = HashValidator.new do
14
+ req :root, *args, &block
15
+ end
16
+ end
17
+
18
+ # Query data validity
19
+ #
20
+ # @param data The data to validate.
21
+ # @return [Boolean] True if the data is valid, false otherwise.
22
+ def valid?(data)
23
+ validate(data).valid?
24
+ end
25
+
26
+ # Query data validity
27
+ #
28
+ # @param data The data to validate.
29
+ # @return [Boolean] True if data is invalid, false otherwise.
30
+ def invalid?(data)
31
+ !valid?(data)
32
+ end
33
+
34
+ # Validate data for the defined Schema
35
+ #
36
+ # @param data The data to validate.
37
+ # @return [Schemacop::Collector] The object that collected errors
38
+ # throughout the validation.
39
+ def validate(data)
40
+ collector = Collector.new
41
+ @root.fields[:root].validate({ root: data }, collector)
42
+ return collector
43
+ end
44
+
45
+ # Validate data for the defined Schema
46
+ #
47
+ # @param data The data to validate.
48
+ # @raise [Schemacop::Exceptions::ValidationError] If the data is invalid,
49
+ # this exception is thrown.
50
+ # @return nil
51
+ def validate!(data)
52
+ collector = validate(data)
53
+
54
+ unless collector.valid?
55
+ fail Exceptions::ValidationError, collector.exception_message
56
+ end
57
+
58
+ return nil
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ class ScopedEnv
2
+ def initialize(delegation_object, methods)
3
+ @delegation_object = delegation_object
4
+ @methods = methods
5
+ end
6
+
7
+ def method_missing(symbol, *args, &block)
8
+ if @methods.include?(symbol)
9
+ @delegation_object.send(symbol, *args, &block)
10
+ else
11
+ super
12
+ end
13
+ end
14
+
15
+ def respond_to_missing?(symbol, include_private = false)
16
+ @methods.include?(symbol) || super
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ module Schemacop
2
+ class ArrayValidator < NodeSupportingType
3
+ register symbols: :array, klasses: Array
4
+
5
+ option :min # Minimal number of elements
6
+ option :max # Maximal number of elements
7
+ option :nil # Whether to allow nil values
8
+
9
+ def initialize(*args)
10
+ super
11
+ type(:nil) if option(:nil)
12
+ end
13
+
14
+ def validate(data, collector)
15
+ validate_custom_check(data, collector)
16
+
17
+ if option?(:min) && data.size < option(:min)
18
+ collector.error "Array must have more (>=) than #{option(:min)} elements."
19
+ end
20
+ if option?(:max) && data.size > option(:max)
21
+ collector.error "Array must have less (<=) than #{option(:max)} elements."
22
+ end
23
+ data.each_with_index do |entry, index|
24
+ collector.path("[#{index}]") do
25
+ validate_types(entry, collector)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module Schemacop
2
+ class BooleanValidator < Node
3
+ register symbols: :boolean, klasses: [TrueClass, FalseClass]
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Schemacop
2
+ class FloatValidator < NumberValidator
3
+ register symbols: :float, klasses: Float
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ module Schemacop
2
+ class HashValidator < NodeSupportingField
3
+ register symbols: :hash, klasses: Hash
4
+
5
+ def validate(data, collector)
6
+ super
7
+
8
+ allowed_fields = @fields.keys
9
+ obsolete_keys = data.keys - allowed_fields
10
+
11
+ collector.error "Obsolete keys: #{obsolete_keys.inspect}." if obsolete_keys.any?
12
+
13
+ @fields.values.each do |field|
14
+ field.validate(data, collector)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module Schemacop
2
+ class IntegerValidator < NumberValidator
3
+ register symbols: :integer, klasses: Integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Schemacop
2
+ class NilValidator < Node
3
+ register symbols: :nil, klasses: NilClass
4
+ end
5
+ end
@@ -0,0 +1,19 @@
1
+ module Schemacop
2
+ class NumberValidator < Node
3
+ register symbols: :number, klasses: [Integer, Float]
4
+
5
+ option :min
6
+ option :max
7
+
8
+ def validate(data, collector)
9
+ super
10
+
11
+ if option?(:min) && data < option(:min)
12
+ collector.error "Value must be >= #{option(:min)}."
13
+ end
14
+ if option?(:max) && data > option(:max)
15
+ collector.error "Value must be <= #{option(:max)}."
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module Schemacop
2
+ class ObjectValidator < Node
3
+ register symbols: :object, klasses: Object
4
+
5
+ option :classes
6
+
7
+ def type_label
8
+ "#{super} (#{classes.join(', ')})"
9
+ end
10
+
11
+ def type_matches?(data)
12
+ super && (classes.empty? || classes.include?(data.class)) && !data.nil?
13
+ end
14
+
15
+ private
16
+
17
+ def classes
18
+ [*option(:classes)]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ module Schemacop
2
+ class StringValidator < Node
3
+ register symbols: :string, klasses: String
4
+
5
+ option :min
6
+ option :max
7
+
8
+ def initialize(options = {})
9
+ super(options)
10
+
11
+ validate_options!
12
+ end
13
+
14
+ def validate(data, collector)
15
+ super
16
+
17
+ if option?(:min) && data.size < option(:min)
18
+ collector.error "String must be longer (>=) than #{option(:min)} characters."
19
+ end
20
+ if option?(:max) && data.size > option(:max)
21
+ collector.error "String must be shorter (<=) than #{option(:max)} characters."
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def validate_options!
28
+ option_schema = Schema.new :integer, min: 0
29
+
30
+ if option?(:min) && option_schema.invalid?(option(:min))
31
+ fail Exceptions::InvalidSchemaError, 'String option :min must be an integer >= 0.'
32
+ elsif option?(:max) && option_schema.invalid?(option(:max))
33
+ fail Exceptions::InvalidSchemaError, 'String option :max must be an integer >= 0.'
34
+ end
35
+ end
36
+ end
37
+ end
data/schemacop.gemspec CHANGED
@@ -1,18 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: schemacop 1.0.2 ruby lib
2
+ # stub: schemacop 2.0.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "schemacop".freeze
6
- s.version = "1.0.2"
6
+ s.version = "2.0.0"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sitrox".freeze]
11
- s.date = "2016-10-06"
12
- s.files = [".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, ".travis.yml".freeze, ".yardopts".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "doc/Schemacop.html".freeze, "doc/Schemacop/Exceptions.html".freeze, "doc/Schemacop/Exceptions/Base.html".freeze, "doc/Schemacop/Exceptions/InvalidSchema.html".freeze, "doc/Schemacop/Exceptions/Validation.html".freeze, "doc/Schemacop/MethodValidation.html".freeze, "doc/Schemacop/MethodValidation/ClassMethods.html".freeze, "doc/Schemacop/Validator.html".freeze, "doc/_index.html".freeze, "doc/class_list.html".freeze, "doc/css/common.css".freeze, "doc/css/full_list.css".freeze, "doc/css/style.css".freeze, "doc/file.README.html".freeze, "doc/file_list.html".freeze, "doc/frames.html".freeze, "doc/index.html".freeze, "doc/js/app.js".freeze, "doc/js/full_list.js".freeze, "doc/js/jquery.js".freeze, "doc/method_list.html".freeze, "doc/top-level-namespace.html".freeze, "lib/schemacop.rb".freeze, "lib/schemacop/exceptions.rb".freeze, "lib/schemacop/validator.rb".freeze, "schemacop.gemspec".freeze, "test/schemacop_validator_test.rb".freeze]
11
+ s.date = "2017-05-15"
12
+ s.files = [".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, ".travis.yml".freeze, ".yardopts".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "doc/Schemacop.html".freeze, "doc/Schemacop/ArrayValidator.html".freeze, "doc/Schemacop/BooleanValidator.html".freeze, "doc/Schemacop/Collector.html".freeze, "doc/Schemacop/Exceptions.html".freeze, "doc/Schemacop/Exceptions/InvalidSchemaError.html".freeze, "doc/Schemacop/Exceptions/ValidationError.html".freeze, "doc/Schemacop/FieldNode.html".freeze, "doc/Schemacop/FloatValidator.html".freeze, "doc/Schemacop/HashValidator.html".freeze, "doc/Schemacop/IntegerValidator.html".freeze, "doc/Schemacop/NilValidator.html".freeze, "doc/Schemacop/Node.html".freeze, "doc/Schemacop/NodeResolver.html".freeze, "doc/Schemacop/NodeSupportingField.html".freeze, "doc/Schemacop/NodeSupportingType.html".freeze, "doc/Schemacop/NodeWithBlock.html".freeze, "doc/Schemacop/NumberValidator.html".freeze, "doc/Schemacop/ObjectValidator.html".freeze, "doc/Schemacop/RootNode.html".freeze, "doc/Schemacop/Schema.html".freeze, "doc/Schemacop/StringValidator.html".freeze, "doc/ScopedEnv.html".freeze, "doc/_index.html".freeze, "doc/class_list.html".freeze, "doc/css/common.css".freeze, "doc/css/full_list.css".freeze, "doc/css/style.css".freeze, "doc/file.README.html".freeze, "doc/file_list.html".freeze, "doc/frames.html".freeze, "doc/index.html".freeze, "doc/inheritance.graphml".freeze, "doc/inheritance.pdf".freeze, "doc/js/app.js".freeze, "doc/js/full_list.js".freeze, "doc/js/jquery.js".freeze, "doc/method_list.html".freeze, "doc/top-level-namespace.html".freeze, "lib/schemacop.rb".freeze, "lib/schemacop/collector.rb".freeze, "lib/schemacop/exceptions.rb".freeze, "lib/schemacop/field_node.rb".freeze, "lib/schemacop/node.rb".freeze, "lib/schemacop/node_resolver.rb".freeze, "lib/schemacop/node_supporting_field.rb".freeze, "lib/schemacop/node_supporting_type.rb".freeze, "lib/schemacop/node_with_block.rb".freeze, "lib/schemacop/root_node.rb".freeze, "lib/schemacop/schema.rb".freeze, "lib/schemacop/scoped_env.rb".freeze, "lib/schemacop/validator/array_validator.rb".freeze, "lib/schemacop/validator/boolean_validator.rb".freeze, "lib/schemacop/validator/float_validator.rb".freeze, "lib/schemacop/validator/hash_validator.rb".freeze, "lib/schemacop/validator/integer_validator.rb".freeze, "lib/schemacop/validator/nil_validator.rb".freeze, "lib/schemacop/validator/number_validator.rb".freeze, "lib/schemacop/validator/object_validator.rb".freeze, "lib/schemacop/validator/string_validator.rb".freeze, "schemacop.gemspec".freeze, "test/custom_check_test.rb".freeze, "test/custom_if_test.rb".freeze, "test/nil_dis_allow_test.rb".freeze, "test/short_forms_test.rb".freeze, "test/test_helper.rb".freeze, "test/types_test.rb".freeze, "test/validator_array_test.rb".freeze, "test/validator_boolean_test.rb".freeze, "test/validator_float_test.rb".freeze, "test/validator_hash_test.rb".freeze, "test/validator_integer_test.rb".freeze, "test/validator_nil_test.rb".freeze, "test/validator_number_test.rb".freeze, "test/validator_object_test.rb".freeze, "test/validator_string_test.rb".freeze]
13
+ s.homepage = "https://github.com/sitrox/schemacop".freeze
14
+ s.licenses = ["MIT".freeze]
13
15
  s.rubygems_version = "2.6.6".freeze
14
16
  s.summary = "Schemacop validates ruby structures consisting of nested hashes and arrays against simple schema definitions.".freeze
15
- s.test_files = ["test/schemacop_validator_test.rb".freeze]
17
+ s.test_files = ["test/custom_check_test.rb".freeze, "test/custom_if_test.rb".freeze, "test/nil_dis_allow_test.rb".freeze, "test/short_forms_test.rb".freeze, "test/test_helper.rb".freeze, "test/types_test.rb".freeze, "test/validator_array_test.rb".freeze, "test/validator_boolean_test.rb".freeze, "test/validator_float_test.rb".freeze, "test/validator_hash_test.rb".freeze, "test/validator_integer_test.rb".freeze, "test/validator_nil_test.rb".freeze, "test/validator_number_test.rb".freeze, "test/validator_object_test.rb".freeze, "test/validator_string_test.rb".freeze]
16
18
 
17
19
  if s.respond_to? :specification_version then
18
20
  s.specification_version = 4
@@ -0,0 +1,86 @@
1
+ require 'test_helper'
2
+
3
+ module Schemacop
4
+ class CustomCheckTest < Minitest::Test
5
+ def test_integer_check_short_form
6
+ s = Schema.new :integer, check: proc { |i| i.even? }
7
+ assert_nil s.validate!(2)
8
+ assert_nil s.validate!(-8)
9
+ assert_nil s.validate!(0)
10
+ assert_verr { s.validate!(1) }
11
+ assert_verr { s.validate!(-7) }
12
+ assert_verr { s.validate!(2.1) }
13
+ end
14
+
15
+ def test_integer_check_with_lambda
16
+ s = Schema.new do
17
+ type :integer, check: ->(i) { i.even? }
18
+ end
19
+
20
+ assert_nil s.validate!(2)
21
+ assert_nil s.validate!(-8)
22
+ assert_nil s.validate!(0)
23
+ assert_verr { s.validate!(1) }
24
+ assert_verr { s.validate!(-7) }
25
+ assert_verr { s.validate!(2.1) }
26
+ end
27
+
28
+ def test_in_type_dsl
29
+ s = Schema.new do
30
+ type :number, check: proc { |x| x == 42 }
31
+ end
32
+ assert_nil s.validate!(42)
33
+ assert_verr { s.validate!(42.1) }
34
+ assert_verr { s.validate!(0) }
35
+ end
36
+
37
+ def test_with_array
38
+ s = Schema.new do
39
+ type :array, check: proc { |a| a.first == 1 } do
40
+ type :integer
41
+ end
42
+ end
43
+ assert_nil s.validate!([1, 2, 3])
44
+ assert_verr { s.validate!([2, 3, 4]) }
45
+ end
46
+
47
+ def test_with_array_nested
48
+ s = Schema.new do
49
+ type :array, check: proc { |a| a.first == 4 } do
50
+ type :integer, check: proc { |i| i >= 2 }
51
+ end
52
+ end
53
+
54
+ assert_nil s.validate!([4, 3, 2])
55
+ assert_verr { s.validate!([3, 2]) }
56
+ assert_verr { s.validate!([4, 1]) }
57
+ end
58
+
59
+ def test_with_hash
60
+ s = Schema.new :hash, check: proc { |h| h.all? { |k, v| k == v } } do
61
+ opt 1, :integer
62
+ opt 'two', :string
63
+ end
64
+ assert_nil s.validate!(1 => 1, 'two' => 'two')
65
+ assert_verr { s.validate!(1 => 2, 'two' => 'two') }
66
+ assert_verr { s.validate!(1 => 1, 'two' => 'one') }
67
+ end
68
+
69
+ def test_mixed_if_check
70
+ s = Schema.new do
71
+ req :first_name,
72
+ :string,
73
+ if: proc { |str| str.start_with?('Sand') },
74
+ check: proc { |str| str == 'Sandy' }
75
+ req :first_name, :string, min: 3
76
+ end
77
+
78
+ assert_nil s.validate!(first_name: 'Bob')
79
+ assert_nil s.validate!(first_name: 'Sandy')
80
+ assert_nil s.validate!(first_name: 'Sansibar')
81
+
82
+ assert_verr { s.validate!(first_name: 'Sandkasten') }
83
+ assert_verr { s.validate!(first_name: 'a') }
84
+ end
85
+ end
86
+ end