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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.rubocop.yml +59 -1
- data/CHANGELOG.md +10 -0
- data/README.md +389 -199
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/doc/Schemacop.html +41 -130
- data/doc/Schemacop/ArrayValidator.html +329 -0
- data/doc/Schemacop/BooleanValidator.html +145 -0
- data/doc/Schemacop/Collector.html +535 -0
- data/doc/Schemacop/Exceptions.html +39 -39
- data/doc/Schemacop/Exceptions/InvalidSchemaError.html +124 -0
- data/doc/Schemacop/Exceptions/ValidationError.html +124 -0
- data/doc/Schemacop/FieldNode.html +409 -0
- data/doc/Schemacop/FloatValidator.html +158 -0
- data/doc/Schemacop/HashValidator.html +263 -0
- data/doc/Schemacop/IntegerValidator.html +158 -0
- data/doc/Schemacop/NilValidator.html +145 -0
- data/doc/Schemacop/Node.html +1426 -0
- data/doc/Schemacop/NodeResolver.html +242 -0
- data/doc/Schemacop/NodeSupportingField.html +590 -0
- data/doc/Schemacop/NodeSupportingType.html +614 -0
- data/doc/Schemacop/NodeWithBlock.html +289 -0
- data/doc/Schemacop/NumberValidator.html +232 -0
- data/doc/Schemacop/ObjectValidator.html +288 -0
- data/doc/Schemacop/RootNode.html +171 -0
- data/doc/Schemacop/Schema.html +697 -0
- data/doc/Schemacop/StringValidator.html +295 -0
- data/doc/ScopedEnv.html +351 -0
- data/doc/_index.html +190 -47
- data/doc/class_list.html +24 -31
- data/doc/css/full_list.css +32 -31
- data/doc/css/style.css +244 -91
- data/doc/file.README.html +428 -232
- data/doc/file_list.html +26 -30
- data/doc/frames.html +7 -16
- data/doc/index.html +428 -232
- data/doc/inheritance.graphml +524 -0
- data/doc/inheritance.pdf +825 -0
- data/doc/js/app.js +106 -77
- data/doc/js/full_list.js +170 -135
- data/doc/method_list.html +494 -38
- data/doc/top-level-namespace.html +36 -36
- data/lib/schemacop.rb +22 -7
- data/lib/schemacop/collector.rb +34 -0
- data/lib/schemacop/exceptions.rb +2 -8
- data/lib/schemacop/field_node.rb +26 -0
- data/lib/schemacop/node.rb +127 -0
- data/lib/schemacop/node_resolver.rb +14 -0
- data/lib/schemacop/node_supporting_field.rb +62 -0
- data/lib/schemacop/node_supporting_type.rb +112 -0
- data/lib/schemacop/node_with_block.rb +16 -0
- data/lib/schemacop/root_node.rb +4 -0
- data/lib/schemacop/schema.rb +61 -0
- data/lib/schemacop/scoped_env.rb +18 -0
- data/lib/schemacop/validator/array_validator.rb +30 -0
- data/lib/schemacop/validator/boolean_validator.rb +5 -0
- data/lib/schemacop/validator/float_validator.rb +5 -0
- data/lib/schemacop/validator/hash_validator.rb +18 -0
- data/lib/schemacop/validator/integer_validator.rb +5 -0
- data/lib/schemacop/validator/nil_validator.rb +5 -0
- data/lib/schemacop/validator/number_validator.rb +19 -0
- data/lib/schemacop/validator/object_validator.rb +21 -0
- data/lib/schemacop/validator/string_validator.rb +37 -0
- data/schemacop.gemspec +7 -5
- data/test/custom_check_test.rb +86 -0
- data/test/custom_if_test.rb +95 -0
- data/test/nil_dis_allow_test.rb +41 -0
- data/test/short_forms_test.rb +316 -0
- data/test/test_helper.rb +6 -0
- data/test/types_test.rb +83 -0
- data/test/validator_array_test.rb +97 -0
- data/test/validator_boolean_test.rb +15 -0
- data/test/validator_float_test.rb +57 -0
- data/test/validator_hash_test.rb +71 -0
- data/test/validator_integer_test.rb +46 -0
- data/test/validator_nil_test.rb +13 -0
- data/test/validator_number_test.rb +60 -0
- data/test/validator_object_test.rb +87 -0
- data/test/validator_string_test.rb +76 -0
- metadata +78 -14
- data/doc/Schemacop/Exceptions/Base.html +0 -127
- data/doc/Schemacop/Exceptions/InvalidSchema.html +0 -141
- data/doc/Schemacop/Exceptions/Validation.html +0 -142
- data/doc/Schemacop/MethodValidation.html +0 -120
- data/doc/Schemacop/MethodValidation/ClassMethods.html +0 -196
- data/doc/Schemacop/Validator.html +0 -254
- data/lib/schemacop/validator.rb +0 -145
- data/test/schemacop_validator_test.rb +0 -257
@@ -1,12 +1,12 @@
|
|
1
|
-
<!DOCTYPE html
|
2
|
-
|
3
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
4
3
|
<head>
|
5
|
-
<meta
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
6
|
<title>
|
7
7
|
Top Level Namespace
|
8
8
|
|
9
|
-
— Documentation by YARD 0.
|
9
|
+
— Documentation by YARD 0.9.9
|
10
10
|
|
11
11
|
</title>
|
12
12
|
|
@@ -15,9 +15,8 @@
|
|
15
15
|
<link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
|
16
16
|
|
17
17
|
<script type="text/javascript" charset="utf-8">
|
18
|
-
|
18
|
+
pathId = "";
|
19
19
|
relpath = '';
|
20
|
-
framesUrl = "frames.html#!top-level-namespace.html";
|
21
20
|
</script>
|
22
21
|
|
23
22
|
|
@@ -28,58 +27,56 @@
|
|
28
27
|
|
29
28
|
</head>
|
30
29
|
<body>
|
31
|
-
<div
|
32
|
-
<
|
30
|
+
<div class="nav_wrap">
|
31
|
+
<iframe id="nav" src="class_list.html?1"></iframe>
|
32
|
+
<div id="resizer"></div>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div id="main" tabindex="-1">
|
36
|
+
<div id="header">
|
37
|
+
<div id="menu">
|
33
38
|
|
34
39
|
<a href="_index.html">Index</a> »
|
35
40
|
|
36
41
|
|
37
42
|
<span class="title">Top Level Namespace</span>
|
38
43
|
|
39
|
-
|
40
|
-
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
41
44
|
</div>
|
42
45
|
|
43
|
-
|
46
|
+
<div id="search">
|
44
47
|
|
45
48
|
<a class="full_list_link" id="class_list_link"
|
46
49
|
href="class_list.html">
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
</a>
|
54
|
-
|
55
|
-
<a class="full_list_link" id="file_list_link"
|
56
|
-
href="file_list.html">
|
57
|
-
File List
|
50
|
+
|
51
|
+
<svg width="24" height="24">
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
55
|
+
</svg>
|
58
56
|
</a>
|
59
57
|
|
60
58
|
</div>
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
<iframe id="search_frame"></iframe>
|
59
|
+
<div class="clear"></div>
|
60
|
+
</div>
|
65
61
|
|
66
|
-
|
62
|
+
<div id="content"><h1>Top Level Namespace
|
67
63
|
|
68
64
|
|
69
65
|
|
70
66
|
</h1>
|
67
|
+
<div class="box_info">
|
68
|
+
|
71
69
|
|
72
|
-
<dl class="box">
|
73
70
|
|
74
71
|
|
75
|
-
|
76
72
|
|
77
|
-
|
78
73
|
|
79
74
|
|
75
|
+
|
80
76
|
|
81
|
-
|
82
|
-
|
77
|
+
|
78
|
+
|
79
|
+
</div>
|
83
80
|
|
84
81
|
<h2>Defined Under Namespace</h2>
|
85
82
|
<p class="children">
|
@@ -89,6 +86,8 @@
|
|
89
86
|
|
90
87
|
|
91
88
|
|
89
|
+
<strong class="classes">Classes:</strong> <span class='object_link'><a href="ScopedEnv.html" title="ScopedEnv (class)">ScopedEnv</a></span>
|
90
|
+
|
92
91
|
|
93
92
|
</p>
|
94
93
|
|
@@ -102,11 +101,12 @@
|
|
102
101
|
|
103
102
|
</div>
|
104
103
|
|
105
|
-
|
106
|
-
Generated on
|
104
|
+
<div id="footer">
|
105
|
+
Generated on Mon May 15 17:46:05 2017 by
|
107
106
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
108
|
-
0.
|
107
|
+
0.9.9 (ruby-2.3.1).
|
109
108
|
</div>
|
110
109
|
|
110
|
+
</div>
|
111
111
|
</body>
|
112
112
|
</html>
|
data/lib/schemacop.rb
CHANGED
@@ -1,11 +1,26 @@
|
|
1
1
|
module Schemacop
|
2
|
-
# {include:Schemacop::Validator.validate!}
|
3
|
-
# @see Schemacop::Validator.validate!
|
4
|
-
def self.validate!(schema, data)
|
5
|
-
Validator.validate!(schema, data)
|
6
|
-
end
|
7
2
|
end
|
8
3
|
|
9
|
-
require '
|
4
|
+
require 'set'
|
5
|
+
require 'active_support/core_ext/class/attribute'
|
6
|
+
|
7
|
+
require 'schemacop/scoped_env'
|
10
8
|
require 'schemacop/exceptions'
|
11
|
-
require 'schemacop/
|
9
|
+
require 'schemacop/schema'
|
10
|
+
require 'schemacop/collector'
|
11
|
+
require 'schemacop/node_resolver'
|
12
|
+
require 'schemacop/node'
|
13
|
+
require 'schemacop/node_with_block'
|
14
|
+
require 'schemacop/node_supporting_type'
|
15
|
+
require 'schemacop/field_node'
|
16
|
+
require 'schemacop/root_node'
|
17
|
+
require 'schemacop/node_supporting_field'
|
18
|
+
require 'schemacop/validator/array_validator'
|
19
|
+
require 'schemacop/validator/boolean_validator'
|
20
|
+
require 'schemacop/validator/hash_validator'
|
21
|
+
require 'schemacop/validator/number_validator'
|
22
|
+
require 'schemacop/validator/integer_validator'
|
23
|
+
require 'schemacop/validator/float_validator'
|
24
|
+
require 'schemacop/validator/string_validator'
|
25
|
+
require 'schemacop/validator/nil_validator'
|
26
|
+
require 'schemacop/validator/object_validator' # Matches any object, must be last validator
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Schemacop
|
2
|
+
class Collector
|
3
|
+
attr_reader :current_path
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@exceptions = []
|
7
|
+
@current_path = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid?
|
11
|
+
@exceptions.empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def path(segment)
|
15
|
+
@current_path << segment
|
16
|
+
yield
|
17
|
+
ensure
|
18
|
+
@current_path.pop
|
19
|
+
end
|
20
|
+
|
21
|
+
def exception_message
|
22
|
+
return "Schemacop validation failed:\n" + @exceptions.map do |e|
|
23
|
+
"- #{e[:path].join('')}: #{e[:message]}"
|
24
|
+
end.join("\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
def error(error_msg)
|
28
|
+
@exceptions << {
|
29
|
+
path: current_path.dup,
|
30
|
+
message: error_msg
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/schemacop/exceptions.rb
CHANGED
@@ -1,10 +1,4 @@
|
|
1
1
|
module Schemacop::Exceptions
|
2
|
-
class
|
3
|
-
|
4
|
-
# This exception is thrown when the given schema definition format is invalid.
|
5
|
-
class InvalidSchema < Base; end
|
6
|
-
|
7
|
-
# This exception is thrown when the given data does not comply with the given
|
8
|
-
# schema definition.
|
9
|
-
class Validation < Base; end
|
2
|
+
class ValidationError < RuntimeError; end
|
3
|
+
class InvalidSchemaError < RuntimeError; end
|
10
4
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Schemacop
|
2
|
+
class FieldNode < NodeSupportingType
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name, required, options = {}, &block)
|
6
|
+
if options.any?
|
7
|
+
fail Exceptions::InvalidSchemaError, 'Node does not support options.'
|
8
|
+
end
|
9
|
+
|
10
|
+
super({}, &block)
|
11
|
+
|
12
|
+
@name = name
|
13
|
+
@required = required
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate(data, collector)
|
17
|
+
unless data.key?(name)
|
18
|
+
collector.error "Missing key #{name.inspect}." if @required
|
19
|
+
return
|
20
|
+
end
|
21
|
+
collector.path "/#{name}" do
|
22
|
+
super(data[name], collector)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Schemacop
|
2
|
+
class Node
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
class_attribute :allowed_options
|
6
|
+
self.allowed_options = {}.freeze
|
7
|
+
|
8
|
+
class_attribute :symbols
|
9
|
+
self.symbols = [].freeze
|
10
|
+
|
11
|
+
class_attribute :klasses
|
12
|
+
self.klasses = [].freeze
|
13
|
+
|
14
|
+
def self.option(key, default: nil)
|
15
|
+
self.allowed_options = allowed_options.merge(key => default)
|
16
|
+
end
|
17
|
+
|
18
|
+
option :if
|
19
|
+
option :check
|
20
|
+
|
21
|
+
def type_label
|
22
|
+
str = (symbols.first || 'unknown').to_s
|
23
|
+
str += '*' if option?(:if)
|
24
|
+
return str
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.symbol(symbol)
|
28
|
+
self.symbols += [symbol]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.clear_symbols
|
32
|
+
self.symbols = [].freeze
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.klass(klass)
|
36
|
+
self.klasses += [klass]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.clear_klasses
|
40
|
+
self.klasses = [].freeze
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.register(symbols: [], klasses: [], clear: true)
|
44
|
+
NodeResolver.register(self)
|
45
|
+
symbols = [*symbols]
|
46
|
+
klasses = [*klasses]
|
47
|
+
if clear
|
48
|
+
clear_symbols
|
49
|
+
clear_klasses
|
50
|
+
end
|
51
|
+
symbols.each { |s| symbol s }
|
52
|
+
klasses.each { |k| klass k }
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.type_matches?(type)
|
56
|
+
symbol_matches?(type) || class_matches?(type)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.symbol_matches?(type)
|
60
|
+
return false unless type.is_a?(Symbol)
|
61
|
+
symbols.include?(type)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.class_matches?(type)
|
65
|
+
return false unless type.is_a?(Class)
|
66
|
+
klasses.each do |klass|
|
67
|
+
return true if type <= klass
|
68
|
+
end
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.build(options, &block)
|
73
|
+
new(options, &block)
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize(options = {})
|
77
|
+
# Check and save given options
|
78
|
+
@options = self.class.allowed_options.merge(options)
|
79
|
+
if (obsolete_opts = @options.keys - self.class.allowed_options.keys).any?
|
80
|
+
fail Exceptions::InvalidSchemaError,
|
81
|
+
"Unrecognized option(s) #{obsolete_opts.inspect} for #{self.class.inspect}, allowed options: #{self.class.allowed_options.keys.inspect}."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def option(key)
|
86
|
+
options[key]
|
87
|
+
end
|
88
|
+
|
89
|
+
def option?(key)
|
90
|
+
# rubocop:disable Style/DoubleNegation
|
91
|
+
!!options[key]
|
92
|
+
# rubocop:enable Style/DoubleNegation
|
93
|
+
end
|
94
|
+
|
95
|
+
def exec_block
|
96
|
+
fail Exceptions::InvalidSchemaError, 'Node does not support block.' if block_given?
|
97
|
+
end
|
98
|
+
|
99
|
+
def resolve_type_klass(type)
|
100
|
+
klass = NodeResolver.resolve(type)
|
101
|
+
unless klass
|
102
|
+
fail Exceptions::InvalidSchemaError, "No validation class found for type #{type.inspect}."
|
103
|
+
end
|
104
|
+
return klass
|
105
|
+
end
|
106
|
+
|
107
|
+
def validate(data, collector)
|
108
|
+
validate_custom_check(data, collector)
|
109
|
+
end
|
110
|
+
|
111
|
+
def type_matches?(data)
|
112
|
+
self.class.type_matches?(data.class) && type_filter_matches?(data)
|
113
|
+
end
|
114
|
+
|
115
|
+
def type_filter_matches?(data)
|
116
|
+
!option?(:if) || option(:if).call(data)
|
117
|
+
end
|
118
|
+
|
119
|
+
protected
|
120
|
+
|
121
|
+
def validate_custom_check(data, collector)
|
122
|
+
if option?(:check) && !option(:check).call(data)
|
123
|
+
collector.error 'Custom :check failed.'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Schemacop
|
2
|
+
class NodeResolver
|
3
|
+
class_attribute :node_classes
|
4
|
+
self.node_classes = [].freeze
|
5
|
+
|
6
|
+
def self.register(node_class)
|
7
|
+
self.node_classes += [node_class]
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.resolve(type)
|
11
|
+
node_classes.find { |c| c.type_matches?(type) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Schemacop
|
2
|
+
class NodeSupportingField < NodeWithBlock
|
3
|
+
block_method :req?
|
4
|
+
block_method :req!
|
5
|
+
block_method :req
|
6
|
+
block_method :opt?
|
7
|
+
block_method :opt!
|
8
|
+
block_method :opt
|
9
|
+
|
10
|
+
attr_reader :fields
|
11
|
+
|
12
|
+
def initialize(options = {}, &block)
|
13
|
+
@fields = {}
|
14
|
+
super
|
15
|
+
exec_block(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def req?(*args, &block)
|
19
|
+
field(*args, required: true, allow_nil: true, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def req!(*args, &block)
|
23
|
+
field(*args, required: true, allow_nil: false, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
alias req req!
|
27
|
+
|
28
|
+
def opt?(*args, &block)
|
29
|
+
field(*args, required: false, allow_nil: true, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def opt!(*args, &block)
|
33
|
+
field(*args, required: false, allow_nil: false, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
alias opt opt?
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def field(*args, required:, allow_nil:, &block)
|
41
|
+
# name = args.shift
|
42
|
+
# options = args.last.is_a?(Hash) ? args.pop : {}
|
43
|
+
name = args.shift
|
44
|
+
|
45
|
+
# rubocop: disable Style/IfInsideElse
|
46
|
+
if @fields[name]
|
47
|
+
@fields[name].type(*args, &block)
|
48
|
+
else
|
49
|
+
if args.any?
|
50
|
+
@fields[name] = FieldNode.new(name, required) do
|
51
|
+
type(*args, &block)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
@fields[name] = FieldNode.new(name, required, &block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
# rubocop: enable Style/IfInsideElse
|
58
|
+
|
59
|
+
@fields[name].type(:nil) if allow_nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|