schemacop 1.0.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|