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
@@ -1,12 +1,12 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
1
+ <!DOCTYPE html>
2
+ <html>
4
3
  <head>
5
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
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
- &mdash; Documentation by YARD 0.8.7.6
9
+ &mdash; 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
- hasFrames = window.top.frames.main ? true : false;
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 id="header">
32
- <div id="menu">
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> &raquo;
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
- <div id="search">
46
+ <div id="search">
44
47
 
45
48
  <a class="full_list_link" id="class_list_link"
46
49
  href="class_list.html">
47
- Class List
48
- </a>
49
-
50
- <a class="full_list_link" id="method_list_link"
51
- href="method_list.html">
52
- Method List
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
- <div class="clear"></div>
62
- </div>
63
-
64
- <iframe id="search_frame"></iframe>
59
+ <div class="clear"></div>
60
+ </div>
65
61
 
66
- <div id="content"><h1>Top Level Namespace
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
- </dl>
82
- <div class="clear"></div>
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
- <div id="footer">
106
- Generated on Thu Oct 6 19:45:02 2016 by
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.8.7.6 (ruby-2.3.1).
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 'active_support/all'
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/validator'
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
@@ -1,10 +1,4 @@
1
1
  module Schemacop::Exceptions
2
- class Base < StandardError; end
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