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
data/doc/file.README.html CHANGED
@@ -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
  File: README
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 = "README";
19
19
  relpath = '';
20
- framesUrl = "frames.html#!file.README.html";
21
20
  </script>
22
21
 
23
22
 
@@ -28,63 +27,80 @@
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="file_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
  <span class="title">File: README</span>
36
41
 
37
-
38
- <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
39
42
  </div>
40
43
 
41
- <div id="search">
44
+ <div id="search">
42
45
 
43
46
  <a class="full_list_link" id="class_list_link"
44
47
  href="class_list.html">
45
- Class List
46
- </a>
47
-
48
- <a class="full_list_link" id="method_list_link"
49
- href="method_list.html">
50
- Method List
51
- </a>
52
-
53
- <a class="full_list_link" id="file_list_link"
54
- href="file_list.html">
55
- File List
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
56
54
  </a>
57
55
 
58
56
  </div>
59
- <div class="clear"></div>
60
- </div>
57
+ <div class="clear"></div>
58
+ </div>
61
59
 
62
- <iframe id="search_frame"></iframe>
63
-
64
- <div id="content"><div id='filecontents'><p><a href="https://travis-ci.org/sitrox/schemacop"><img src="https://travis-ci.org/sitrox/schemacop.svg?branch=master" alt="Build Status"></a>
60
+ <div id="content"><div id='filecontents'><p><a href="https://travis-ci.org/sitrox/schemacop"><img src="https://travis-ci.org/sitrox/schemacop.svg?branch=master" alt="Build Status"></a>
65
61
  <a href="https://badge.fury.io/rb/schemacop"><img src="https://badge.fury.io/rb/schemacop.svg" alt="Gem Version"></a></p>
66
62
 
67
63
  <h1>Schemacop</h1>
68
64
 
69
- <p>Schemacop validates ruby structures consisting of nested hashes and arrays
70
- against simple schema definitions.</p>
65
+ <p>This is the README for Schemacop version 2, which <strong>breaks backwards
66
+ compatibility</strong> with version 1.</p>
71
67
 
72
- <p>Example:</p>
73
-
74
- <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_schema'>schema</span> <span class='op'>=</span> <span class='lbrace'>{</span>
75
- <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
76
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
77
- <span class='label'>first_name:</span> <span class='symbol'>:string</span><span class='comma'>,</span>
78
- <span class='label'>last_name:</span> <span class='symbol'>:string</span>
79
- <span class='rbrace'>}</span>
80
- <span class='rbrace'>}</span>
81
-
82
- <span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='lbrace'>{</span>
83
- <span class='label'>first_name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>John</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span>
84
- <span class='label'>last_name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Doe</span><span class='tstring_end'>&#39;</span></span>
85
- <span class='rbrace'>}</span>
68
+ <p>Schemacop validates ruby structures consisting of nested hashes and arrays
69
+ against schema definitions described by a simple DSL.</p>
70
+
71
+ <p>Examples:</p>
72
+
73
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_schema'>schema</span> <span class='op'>=</span> <span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
74
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:naming</span><span class='comma'>,</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
75
+ <span class='id identifier rubyid_opt'>opt</span> <span class='symbol'>:first_name</span><span class='comma'>,</span> <span class='symbol'>:string</span>
76
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:last_name</span><span class='comma'>,</span> <span class='symbol'>:string</span>
77
+ <span class='kw'>end</span>
78
+ <span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:age</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>18</span>
79
+ <span class='id identifier rubyid_req?'>req?</span> <span class='symbol'>:password</span> <span class='kw'>do</span>
80
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>check:</span> <span class='id identifier rubyid_proc'>proc</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_pw'>pw</span><span class='op'>|</span> <span class='id identifier rubyid_pw'>pw</span><span class='period'>.</span><span class='id identifier rubyid_include?'>include?</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>*</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='rbrace'>}</span>
81
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
82
+ <span class='kw'>end</span>
83
+ <span class='kw'>end</span>
84
+
85
+ <span class='id identifier rubyid_schema'>schema</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span>
86
+ <span class='label'>naming:</span> <span class='lbrace'>{</span> <span class='label'>first_name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>John</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span>
87
+ <span class='label'>last_name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Doe</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span><span class='comma'>,</span>
88
+ <span class='label'>age:</span> <span class='int'>34</span><span class='comma'>,</span>
89
+ <span class='label'>password:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>my*pass</span><span class='tstring_end'>&#39;</span></span>
90
+ <span class='rparen'>)</span>
91
+ </code></pre>
86
92
 
87
- <span class='const'>Schemacop</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='id identifier rubyid_schema'>schema</span><span class='comma'>,</span> <span class='id identifier rubyid_data'>data</span><span class='rparen'>)</span>
93
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_schema2'>schema2</span> <span class='op'>=</span> <span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
94
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:description</span><span class='comma'>,</span>
95
+ <span class='symbol'>:string</span><span class='comma'>,</span>
96
+ <span class='label'>if:</span> <span class='id identifier rubyid_proc'>proc</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_str'>str</span><span class='op'>|</span> <span class='id identifier rubyid_str'>str</span><span class='period'>.</span><span class='id identifier rubyid_start_with?'>start_with?</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Abstract: </span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='rbrace'>}</span><span class='comma'>,</span>
97
+ <span class='label'>max:</span> <span class='int'>35</span><span class='comma'>,</span>
98
+ <span class='label'>check:</span> <span class='id identifier rubyid_proc'>proc</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_str'>str</span><span class='op'>|</span> <span class='op'>!</span><span class='id identifier rubyid_str'>str</span><span class='period'>.</span><span class='id identifier rubyid_end_with?'>end_with?</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>.</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='rbrace'>}</span>
99
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:description</span><span class='comma'>,</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>35</span>
100
+ <span class='kw'>end</span>
101
+
102
+ <span class='id identifier rubyid_schema2'>schema2</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='label'>description:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Abstract: a short description</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span>
103
+ <span class='id identifier rubyid_schema2'>schema2</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='label'>description:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Since this is no abstract, we expect it to be longer.</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span>
88
104
  </code></pre>
89
105
 
90
106
  <h2>Installation</h2>
@@ -94,278 +110,457 @@ against simple schema definitions.</p>
94
110
  <pre class="code sh"><code class="sh">$ gem install schemacop
95
111
  </code></pre>
96
112
 
97
- <p>To install it using <code>bundler</code> (recommended for any application), add it
98
- to your <code>Gemfile</code>:</p>
113
+ <p>To install it using <code>bundler</code> (recommended for any application), add it to your
114
+ <code>Gemfile</code>:</p>
99
115
 
100
116
  <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>schemacop</span><span class='tstring_end'>&#39;</span></span>
101
117
  </code></pre>
102
118
 
103
- <h2>Basic usage</h2>
119
+ <h2>Basics</h2>
104
120
 
105
- <p>Schemacop&#39;s interface is very simple:</p>
121
+ <p>Since there is no explicit typing in Ruby, it can be hard to make sure that a
122
+ method is recieving exactly the right kind of data it needs. The idea of this
123
+ gem is to define a schema at boot time that will validate the data being passed
124
+ around at runtime. Those two steps look as follows:</p>
106
125
 
107
- <pre class="code ruby"><code class="ruby"><span class='const'>Schemacop</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='id identifier rubyid_schema'>schema</span><span class='comma'>,</span> <span class='id identifier rubyid_data'>data</span><span class='rparen'>)</span>
108
- </code></pre>
126
+ <p>At boot time:</p>
109
127
 
110
- <p>It will throw an exception if either the schema is wrong or the given data does
111
- not comply with the schema. See section <em>Exceptions</em> for more information.</p>
128
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_my_schema'>my_schema</span> <span class='op'>=</span> <span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
129
+ <span class='comment'># Your specification goes here
130
+ </span><span class='kw'>end</span>
131
+ </code></pre>
112
132
 
113
- <h2>Defining schemas</h2>
133
+ <p>At runtime:</p>
114
134
 
115
- <p>Schemacop can validate recursive structures of arrays nested into hashes and
116
- vice-versa. &#39;Leaf-nodes&#39; can be of any data type, but their internal structure
117
- is not validated.</p>
135
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_my_shema'>my_shema</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span>
136
+ <span class='comment'># Your data goes here
137
+ </span><span class='rparen'>)</span>
138
+ </code></pre>
118
139
 
119
- <p>Schema definitions are always a hash, even if they specify an array. Each level
120
- of a definition hash has to define a type.</p>
140
+ <p><code>validate!</code> will fail if the data given to it does not match what was specified
141
+ in the schema.</p>
121
142
 
122
- <p>You can specify any type, but only the types <code>:hash</code> and <code>:array</code> allow you to
123
- specify a sub structure.</p>
143
+ <h3>Type lines vs. Field lines</h3>
124
144
 
125
- <h3>Defining hashes</h3>
145
+ <p>Schemacop uses a DSL (domain-specific language) to let you describe your
146
+ schemas. We distinguish between two kinds of identifiers:</p>
126
147
 
127
- <p>Once a level is defined as a hash (<code>type: :hash</code>), you can provide the key
128
- <code>hash</code> which in turn specifies the keys contained in that hash:</p>
148
+ <ul>
149
+ <li><p>Field Lines: We call a key-value pair (like the contents of a hash) a <em>field</em>.
150
+ A field line typically starts with the keyword <code>req</code> (for a required field) or
151
+ <code>opt</code> (for an optional field).</p></li>
152
+ <li><p>Type Lines: Those start with the keyword <code>type</code> and specify the data type to
153
+ be accepted with a corresponding symbol (e.g. <code>:integer</code> or <code>:boolean</code>). You
154
+ can have multiple Type Lines for a Field Line in order to indicate that the
155
+ field&#39;s value can be of one of the specified types.</p></li>
156
+ </ul>
129
157
 
130
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
131
- <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
132
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
133
- <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span><span class='comma'>,</span>
134
- <span class='label'>last_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span>
135
- <span class='rbrace'>}</span>
136
- <span class='rbrace'>}</span>
158
+ <p>If you don&#39;t use any short forms, a schema definition would be something like
159
+ this:</p>
160
+
161
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_s'>s</span> <span class='op'>=</span> <span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
162
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
163
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
164
+ <span class='id identifier rubyid_req'>req</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>name</span><span class='tstring_end'>&#39;</span></span> <span class='kw'>do</span>
165
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:boolean</span>
166
+ <span class='kw'>end</span>
167
+ <span class='kw'>end</span>
168
+ <span class='kw'>end</span>
137
169
  </code></pre>
138
170
 
139
- <p>If you don&#39;t provide the <code>:hash</code> key, the hash won&#39;t be validated (other than
140
- the verification that it really is a hash):</p>
171
+ <p>The above schema would accept either an integer or a hash with exactly one field
172
+ with key &#39;present&#39; of type String and value of type Boolean (either TrueClass or
173
+ FalseClass).</p>
141
174
 
142
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:hash</span> <span class='rbrace'>}</span>
143
- </code></pre>
175
+ <p>We will see Type and Field lines in more detail below.</p>
144
176
 
145
- <p>Hash definitions can be nested deeply:</p>
146
-
147
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
148
- <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
149
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
150
- <span class='label'>name:</span> <span class='lbrace'>{</span>
151
- <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
152
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
153
- <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span><span class='comma'>,</span>
154
- <span class='label'>last_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span>
155
- <span class='rbrace'>}</span>
156
- <span class='rbrace'>}</span>
157
- <span class='rbrace'>}</span>
158
- <span class='rbrace'>}</span>
159
- </code></pre>
177
+ <h3><code>validate</code> vs <code>validate!</code> vs <code>valid?</code></h3>
160
178
 
161
- <h3>Defining arrays</h3>
179
+ <p>The method <code>validate</code> will return a <code>Collector</code> object that contains all
180
+ validation errors (if any), whereas <code>validate!</code> will accumulate all violations
181
+ and finally throw an exception describing them.</p>
162
182
 
163
- <p>When you define a level as an array (<code>type: :array</code>), you can provide further
164
- specification of the array&#39;s contents uby supplying the key <code>:array</code>:</p>
183
+ <p>For simply querying the validity of some data, use the methods <code>valid?</code> or
184
+ <code>invalid?</code>.</p>
165
185
 
166
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
167
- <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
168
- <span class='label'>array:</span> <span class='lbrace'>{</span>
169
- <span class='label'>type:</span> <span class='symbol'>:string</span>
170
- <span class='rbrace'>}</span>
171
- <span class='rbrace'>}</span>
172
- </code></pre>
186
+ <h2>Schemacop&#39;s DSL</h2>
173
187
 
174
- <p>This example would define an array of strings.</p>
188
+ <p>In this section, we will ignore <a href="#short-forms">short forms</a> and explicitly
189
+ write out everything.</p>
175
190
 
176
- <p>Arrays can nest hashes and vice-versa:</p>
191
+ <p>Inside the block given at the schema instantiation (<code>Schema.new do ... end</code>),
192
+ the following kinds of method calls are allowed (where the outermost must be a
193
+ Type Line):</p>
177
194
 
178
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
179
- <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
180
- <span class='label'>array:</span> <span class='lbrace'>{</span>
181
- <span class='label'>type:</span> <span class='symbol'>:string</span>
182
- <span class='rbrace'>}</span>
183
- <span class='rbrace'>}</span>
184
- </code></pre>
195
+ <h3>Type Line</h3>
185
196
 
186
- <p>If you don&#39;t provide the <code>:array</code> key, the array contents won&#39;t be validated:</p>
197
+ <p>A Type Line always starts with the identifier <code>type</code> and specifies a possible
198
+ data type for a given field (if inside a Field Line) or the given data structure
199
+ (if directly below the schema instantiation).</p>
187
200
 
188
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:array</span> <span class='rbrace'>}</span>
201
+ <p>Type Lines are generally of the form</p>
202
+
203
+ <pre class="code ruby"><code class="ruby">type :my_type, option_1: value_1, ..., option_n: value_n
189
204
  </code></pre>
190
205
 
191
- <h2>Types</h2>
206
+ <p>where <code>:my_type</code> is a supported symbol (see section <a href="#types">Types</a> below for
207
+ supported types).</p>
208
+
209
+ <h4>General options</h4>
192
210
 
193
- <p>For each level in your schema, you can specify the type in one of the following
194
- manors:</p>
211
+ <p>Some types support specific options that allow additional checks on the nature
212
+ of the data (such as the <code>min</code> option for type <code>:number</code>). The following options
213
+ are supported by all types:</p>
214
+
215
+ <h5>Option <code>if</code></h5>
216
+
217
+ <p>This option takes a proc (or a lambda) as value. The proc will be called when
218
+ checking whether or not the data being analyzed fits a certain type. The data is
219
+ given to the proc, which has to return either true or false. If it returns true,
220
+ the type of the given data is considered correct and the data will be validated
221
+ if further options are given.</p>
222
+
223
+ <p>Note that the proc in <code>if</code> will only get called if the type (<code>:my_type</code> from
224
+ above) fits the data already. You can use the option <code>if</code> in order to say: &quot;Even
225
+ if the data is of type <code>:my_type</code>, I consider it having the wrong type if my
226
+ proc returns false.&quot;</p>
227
+
228
+ <p>Consider a scenario in which you want to have the following rule set:</p>
195
229
 
196
230
  <ul>
197
- <li>A ruby class:</li>
231
+ <li>Only integers may be given</li>
232
+ <li>Odd integers must be no larger than 15</li>
233
+ <li>No limitations for even integers</li>
198
234
  </ul>
199
235
 
200
- <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='const'>String</span> <span class='rbrace'>}</span>
236
+ <p>The corresponding schema would look as follows:</p>
237
+
238
+ <pre class="code ruby"><code class="ruby"><span class='const'>Schma</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
239
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>if:</span> <span class='id identifier rubyid_proc'>proc</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_data'>data</span><span class='op'>|</span> <span class='id identifier rubyid_data'>data</span><span class='period'>.</span><span class='id identifier rubyid_odd?'>odd?</span> <span class='rbrace'>}</span><span class='comma'>,</span> <span class='label'>max:</span> <span class='int'>15</span>
240
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
241
+ <span class='kw'>end</span>
201
242
  </code></pre>
202
243
 
244
+ <p>Here, the first type line will only accept odd numbers and the option <code>max: 15</code>
245
+ provided by the <code>:integer</code> validator will discard numbers higher than 15.</p>
246
+
247
+ <p>Since the first line only accepts odd numbers, it doesn&#39;t apply for even numbers
248
+ (due to the proc given to <code>if</code> they are considered to be of the wrong type) and
249
+ control falls through to the second type line accepting any integer.</p>
250
+
251
+ <h5>Option <code>check</code></h5>
252
+
253
+ <p>This option allows you to perform arbitrary custom checks for a given data type.
254
+ Just like <code>if</code>, <code>check</code> takes a proc or lambda as a value, but it runs <em>after</em>
255
+ the type checking, meaning that it only gets executed if the data has the right
256
+ type and the proc in <code>if</code> (if any) has returned true.</p>
257
+
258
+ <p>The proc passed to the <code>check</code> option is given the data being analyzed. It is to
259
+ return true if the data passes the custom check. If it returns false, Schemacop
260
+ considers the data to be invalid.</p>
261
+
262
+ <p>The following example illustrates the use of the option <code>check</code>: Consider a
263
+ scenario in which you want the following rule set:</p>
264
+
203
265
  <ul>
204
- <li>A type alias (see <span class='object_link'><a href="Schemacop/Validator.html#TYPE_ALIASES-constant" title="Schemacop::Validator::TYPE_ALIASES (constant)">Schemacop::Validator::TYPE_ALIASES</a></span> for a full list of
205
- available type aliasses):</li>
266
+ <li>Data must be of type String</li>
267
+ <li>The string must be longer than 5 characters</li>
268
+ <li>The second character must be an &#39;r&#39;</li>
206
269
  </ul>
207
270
 
208
- <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:boolean</span> <span class='rbrace'>}</span>
271
+ <p>The corresponding schema would look as follows:</p>
272
+
273
+ <pre class="code ruby"><code class="ruby"><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
274
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>5</span><span class='comma'>,</span> <span class='label'>check:</span> <span class='id identifier rubyid_proc'>proc</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_data'>data</span><span class='op'>|</span> <span class='id identifier rubyid_data'>data</span><span class='lbracket'>[</span><span class='int'>1</span><span class='rbracket'>]</span> <span class='op'>==</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>r</span><span class='tstring_end'>&#39;</span></span><span class='rbrace'>}</span>
275
+ <span class='kw'>end</span>
209
276
  </code></pre>
210
277
 
278
+ <p>The above Type Line has type <code>:string</code> and two options (<code>min</code> and <code>check</code>). The
279
+ option <code>min</code> is supported by the <code>:string</code> validator (covered later).</p>
280
+
281
+ <h3>Field Line</h3>
282
+
283
+ <p>Inside a Type Line of type <code>:hash</code> or <code>Hash</code>, you may specify an arbitrary
284
+ number of field lines (one for each key-value pair you want to be in the hash).</p>
285
+
286
+ <p>Field Lines start with one of the following six identifiers: <code>req</code>, <code>req?</code>,
287
+ <code>req!</code>, <code>opt</code>, <code>opt?</code> or <code>opt!</code>:</p>
288
+
211
289
  <ul>
212
- <li>A list of ruby classes or type aliases:</li>
290
+ <li><p>The suffix <code>-!</code> means that the field must not be nil.</p></li>
291
+ <li><p>The suffix <code>-?</code> means that the field may be nil.</p></li>
292
+ <li><p>The prefix <code>req-</code> denotes a required field (validation fails if the given data
293
+ hash doesn&#39;t define it). <code>req</code> is a shorthand notation for <code>req!</code> (meaning
294
+ that by default, a required field cannot be nil).</p></li>
295
+ <li><p>The prefix <code>opt-</code> denotes an optional field. <code>opt</code> is a shorthand notation for
296
+ <code>opt?</code> (meaning that by default, an optional field may be nil).</p></li>
213
297
  </ul>
214
298
 
215
- <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='lbracket'>[</span><span class='const'>String</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='rbracket'>]</span> <span class='rbrace'>}</span>
216
- </code></pre>
299
+ <p>To summarize:</p>
300
+
301
+ <ul>
302
+ <li><code>req</code> or <code>req!</code>: required and non-nil</li>
303
+ <li><code>req?</code>: required but may be nil</li>
304
+ <li><code>opt</code> or <code>opt?</code>: optional and may be nil</li>
305
+ <li><code>opt!</code>: optional but non-nil</li>
306
+ </ul>
217
307
 
218
- <p>When specifying more than one type, it is validated that the given data
219
- structure matches <em>one</em> of the given types.</p>
220
-
221
- <p>If you specify both <code>:array</code> and <code>:hash</code> in such a type array, you can provide
222
- a specification for both <code>array</code> and <code>hash</code> types:</p>
223
-
224
- <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span>
225
- <span class='label'>type:</span> <span class='lbracket'>[</span><span class='symbol'>:array</span><span class='comma'>,</span> <span class='symbol'>:hash</span><span class='rbracket'>]</span><span class='comma'>,</span>
226
- <span class='label'>array:</span> <span class='lbrace'>{</span>
227
- <span class='label'>type:</span> <span class='symbol'>:string</span>
228
- <span class='rbrace'>}</span><span class='comma'>,</span>
229
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
230
- <span class='label'>first_name:</span> <span class='symbol'>:string</span>
231
- <span class='rbrace'>}</span>
232
- <span class='rbrace'>}</span>
308
+ <p>You then pass a block with a single or multiple Type Lines to the field.</p>
309
+
310
+ <p>Example: The following schema defines a hash that has a required non-nil field
311
+ of type String under the key <code>:name</code> (of type Symbol) and an optional but
312
+ non-nil field of type Integer or Date under the key <code>:age</code>.</p>
313
+
314
+ <pre class="code ruby"><code class="ruby"><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
315
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
316
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:name</span> <span class='kw'>do</span>
317
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
318
+ <span class='kw'>end</span>
319
+ <span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:age</span> <span class='kw'>do</span>
320
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
321
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:object</span><span class='comma'>,</span> <span class='label'>classes:</span> <span class='const'>Date</span>
322
+ <span class='kw'>end</span>
323
+ <span class='kw'>end</span>
324
+ <span class='kw'>end</span>
233
325
  </code></pre>
234
326
 
235
- <p>It will then determine which specification to use based on the actual data.</p>
327
+ <p>You might find the notation cumbersome, and you&#39;d be right to say so. Luckily
328
+ there are plenty of short forms available which we will see below.</p>
236
329
 
237
- <h2>Null and required</h2>
330
+ <h2>Types</h2>
238
331
 
239
- <p>Using the optional parameters <code>required</code> and <code>null</code>, you can control whether a
240
- specific substructure must be provided (<code>required</code>) and if it can be <code>nil</code>
241
- (<code>null</code>).</p>
332
+ <p>The following types are supported by Schemacop:</p>
242
333
 
243
- <p>These two parameters can be combined in any way.</p>
334
+ <!-- TODO: Test the following statement: (you can easily extend them by writing
335
+ another `your_validator.rb` class under `validator/`): -->
244
336
 
245
- <h3>Required validation</h3>
337
+ <ul>
338
+ <li><p><code>:boolean</code> accepts a Ruby TrueClass or FalseClass instance.</p></li>
339
+ <li><p><code>:integer</code> accepts a Ruby Integer.</p>
246
340
 
247
- <p>When validating with <code>required = false</code>, it means that the whole key can be
248
- omitted. As an example:</p>
341
+ <ul>
342
+ <li>supported options: <code>min</code>, <code>max</code> (lower / upper bound)</li>
343
+ </ul></li>
344
+ <li><p><code>:float</code> accepts a Ruby Float.</p>
249
345
 
250
- <pre class="code ruby"><code class="ruby"><span class='comment'># Successfully validates data hash: {}
251
- </span><span class='lbrace'>{</span>
252
- <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
253
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
254
- <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>required:</span> <span class='kw'>false</span> <span class='rbrace'>}</span>
255
- <span class='rbrace'>}</span>
256
- <span class='rbrace'>}</span>
257
- </code></pre>
346
+ <ul>
347
+ <li>supported options: <code>min</code>, <code>max</code> (lower / upper bound)</li>
348
+ </ul></li>
349
+ <li><p><code>:number</code> accepts a Ruby Integer or Float.</p>
350
+
351
+ <ul>
352
+ <li>supported options: <code>min</code>, <code>max</code> (lower / upper bound)</li>
353
+ </ul></li>
354
+ <li><p><code>:string</code> accepts a Ruby String.</p>
355
+
356
+ <ul>
357
+ <li>supported options: <code>min</code>, <code>max</code> (bounds for string length)</li>
358
+ </ul></li>
359
+ <li><p><code>:object</code> accepts an arbitrary Ruby object (any object if no option is given).</p>
360
+
361
+ <ul>
362
+ <li>supported option: <code>classes</code>: Ruby class (or an array of them) that will be
363
+ the only recognized filters. Unlike other options, this one affects not the
364
+ validation but the type recognition, meaning that you can have multiple Type
365
+ Lines with different <code>classes</code> option for the same field, each having its
366
+ own validation (e.g. through the option <code>check</code>).</li>
367
+ </ul></li>
368
+ <li><p><code>:array</code> accepts a Ruby Array.</p>
369
+
370
+ <ul>
371
+ <li>supported options: <code>min</code>, <code>max</code> (bounds for array size) and <code>nil</code>: TODO</li>
372
+ <li>accepts a block with an arbitrary number of Type Lines.</li>
373
+ <li>TODO no lookahead for different arrays, see
374
+ validator_array_test#test_multiple_arrays</li>
375
+ </ul></li>
376
+ <li><p><code>:hash</code> accepts a Ruby Hash.</p>
377
+
378
+ <ul>
379
+ <li>accepts a block with an arbitrary number of Field Lines.</li>
380
+ </ul></li>
381
+ <li><p><code>:nil</code>: accepts a Ruby NilClass instance. If you want to allow <code>nil</code> as a
382
+ value in a field, see above for the usage of the suffixes <code>-!</code> and <code>-?</code> for
383
+ Field Lines.</p></li>
384
+ </ul>
258
385
 
259
- <h3>Null validation</h3>
386
+ <p>All types support the options <code>if</code> and <code>check</code> (see the section about Type Lines
387
+ above).</p>
260
388
 
261
- <p>When validating with <code>null = true</code>, the key must still be present, but it can
262
- also be <code>nil</code>.</p>
389
+ <h2>Short forms</h2>
263
390
 
264
- <pre class="code ruby"><code class="ruby"><span class='comment'># Successfully validates data hash: { first_name: nil }
265
- </span><span class='lbrace'>{</span>
266
- <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
267
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
268
- <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>null:</span> <span class='kw'>false</span> <span class='rbrace'>}</span>
269
- <span class='rbrace'>}</span>
270
- <span class='rbrace'>}</span>
391
+ <p>For convenience, the following short forms may be used (and combined if
392
+ possible).</p>
393
+
394
+ <h3>Passing a type to a Field Line or schema</h3>
395
+
396
+ <p>Instead of adding a Type Line in the block of a Field Line, you can omit <code>do
397
+ type ... end</code> and directly write the type after the key of the field.</p>
398
+
399
+ <p>Note that when using this short form, you may not give a block to the Field
400
+ Line.</p>
401
+
402
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Long form
403
+ </span><span class='id identifier rubyid_req'>req</span> <span class='symbol'>:name</span> <span class='kw'>do</span>
404
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>2</span><span class='comma'>,</span> <span class='label'>max:</span> <span class='int'>5</span>
405
+ <span class='kw'>end</span>
406
+
407
+ <span class='comment'># Short form
408
+ </span><span class='id identifier rubyid_req'>req</span> <span class='symbol'>:name</span><span class='comma'>,</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>2</span><span class='comma'>,</span> <span class='label'>max:</span> <span class='int'>5</span>
271
409
  </code></pre>
272
410
 
273
- <h2>Allowed values</h2>
411
+ <p>This means that the value under the key <code>:name</code> of type Symbol must be a String
412
+ containing 2 to 5 characters.</p>
274
413
 
275
- <p>For any level, you can optionally specify an array of values that are allowed.</p>
414
+ <p>The short form also works in the schema instantiation:</p>
276
415
 
277
- <p>For example:</p>
416
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Long form
417
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
418
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>2</span><span class='comma'>,</span> <span class='label'>max:</span> <span class='int'>5</span>
419
+ <span class='kw'>end</span>
278
420
 
279
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
280
- <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
281
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
282
- <span class='label'>category:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>allowed_values:</span> <span class='lbracket'>[</span><span class='int'>1</span><span class='comma'>,</span> <span class='int'>2</span><span class='comma'>,</span> <span class='int'>3</span><span class='rbracket'>]</span> <span class='rbrace'>}</span>
283
- <span class='rbrace'>}</span>
284
- <span class='rbrace'>}</span>
421
+ <span class='comment'># Short form
422
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>2</span><span class='comma'>,</span> <span class='label'>max:</span> <span class='int'>5</span><span class='rparen'>)</span>
285
423
  </code></pre>
286
424
 
287
- <h2>Shortcuts</h2>
425
+ <p>This means that the data given to the schema must be a String that is between 2
426
+ and 5 characters long.</p>
288
427
 
289
- <h3>Type shortcut</h3>
428
+ <h3>Passing multiple types at once</h3>
290
429
 
291
- <p>If you&#39;d just like to define a type for a level but don&#39;t need to supply any
292
- additional information, you can just skip passing an extra hash and just pass
293
- the type instead.</p>
430
+ <p>You can specify several types at once by putting them in an array.</p>
294
431
 
295
- <p>For example, the following</p>
432
+ <p>Note that when using this short form, you may not give any options.</p>
296
433
 
297
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
298
- <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
299
- <span class='label'>array:</span> <span class='lbrace'>{</span>
300
- <span class='label'>type:</span> <span class='symbol'>:string</span>
301
- <span class='rbrace'>}</span>
302
- <span class='rbrace'>}</span>
434
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Long form
435
+ </span><span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:age</span> <span class='kw'>do</span>
436
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
437
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
438
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:boolean</span>
439
+ <span class='kw'>end</span>
440
+
441
+ <span class='comment'># Short form
442
+ </span><span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:age</span> <span class='kw'>do</span>
443
+ <span class='id identifier rubyid_type'>type</span> <span class='lbracket'>[</span><span class='symbol'>:string</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='symbol'>:boolean</span><span class='rbracket'>]</span>
444
+ <span class='kw'>end</span>
303
445
  </code></pre>
304
446
 
305
- <p>can also be written as:</p>
447
+ <p>Combined with previous short form:</p>
306
448
 
307
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
308
- <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
309
- <span class='label'>array:</span> <span class='symbol'>:string</span>
310
- <span class='rbrace'>}</span>
449
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:age</span><span class='comma'>,</span> <span class='lbracket'>[</span><span class='symbol'>:string</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='symbol'>:boolean</span><span class='rbracket'>]</span>
311
450
  </code></pre>
312
451
 
313
- <h3>Quick hash and array</h3>
452
+ <p>This also works in the schema instantiation:</p>
453
+
454
+ <pre class="code ruby"><code class="ruby"><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='lbracket'>[</span><span class='symbol'>:string</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='symbol'>:boolean</span><span class='rbracket'>]</span><span class='rparen'>)</span>
455
+ </code></pre>
456
+
457
+ <p>This means that the schema will validate any data of type String, Integer,
458
+ TrueClass or FalseClass.</p>
459
+
460
+ <h3>Omitting the Type Line in a Field Line</h3>
314
461
 
315
- <p>When specifying a level as hash or array and you&#39;re further specifying the
316
- hashe&#39;s fields or the array&#39;s content types, you can omit the <code>type</code> key.</p>
462
+ <p>If you don&#39;t specify the type of a field, it will default to <code>:object</code> with no
463
+ options, meaning that the field will accept any kind of data:</p>
317
464
 
318
- <p>For example, the following</p>
465
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Long form
466
+ </span><span class='id identifier rubyid_req?'>req?</span> <span class='symbol'>:child</span> <span class='kw'>do</span>
467
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:object</span>
468
+ <span class='kw'>end</span>
319
469
 
320
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
321
- <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
322
- <span class='label'>array:</span> <span class='lbrace'>{</span>
323
- <span class='label'>type:</span> <span class='symbol'>:string</span>
324
- <span class='rbrace'>}</span>
325
- <span class='rbrace'>}</span>
470
+ <span class='comment'># Short form
471
+ </span><span class='id identifier rubyid_req?'>req?</span> <span class='symbol'>:child</span>
326
472
  </code></pre>
327
473
 
328
- <p>can also be written as:</p>
474
+ <h3>Omitting the Type Line in schema instantiation</h3>
475
+
476
+ <p>If you don&#39;t give a Type Line to a schema, it will accept data of type Hash.
477
+ Therefore, if you validate Hashes only, you can omit the Type Line and directly
478
+ write Field Lines in the schema instantiation:</p>
479
+
480
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Long form
481
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
482
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
483
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:name</span> <span class='kw'>do</span>
484
+ <span class='comment'># ...
485
+ </span> <span class='kw'>end</span>
486
+ <span class='kw'>end</span>
487
+ <span class='kw'>end</span>
488
+
489
+ <span class='comment'># Short form
490
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
491
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:name</span> <span class='kw'>do</span>
492
+ <span class='comment'># ...
493
+ </span> <span class='kw'>end</span>
494
+ <span class='kw'>end</span>
495
+ </code></pre>
496
+
497
+ <h3>Shortform for subtypes</h3>
498
+
499
+ <p>In case of nested arrays, you can group all Type Lines to a single one.</p>
500
+
501
+ <p>Note that any options or block passed to the grouped Type Line will be given to
502
+ the innermost (last) type.</p>
503
+
504
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Long form
505
+ </span><span class='id identifier rubyid_type'>type</span> <span class='symbol'>:array</span> <span class='kw'>do</span>
506
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>3</span>
507
+ <span class='kw'>end</span>
329
508
 
330
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
331
- <span class='label'>array:</span> <span class='symbol'>:string</span>
332
- <span class='rbrace'>}</span>
509
+ <span class='comment'># Short form
510
+ </span><span class='id identifier rubyid_type'>type</span> <span class='symbol'>:array</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>min:</span> <span class='int'>3</span>
333
511
  </code></pre>
334
512
 
335
- <h2>Example schema</h2>
336
-
337
- <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
338
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
339
- <span class='label'>id:</span> <span class='lbracket'>[</span><span class='const'>Integer</span><span class='comma'>,</span> <span class='const'>String</span><span class='rbracket'>]</span><span class='comma'>,</span>
340
- <span class='label'>name:</span> <span class='symbol'>:string</span><span class='comma'>,</span>
341
- <span class='label'>meta:</span> <span class='lbrace'>{</span>
342
- <span class='label'>hash:</span> <span class='lbrace'>{</span>
343
- <span class='label'>groups:</span> <span class='lbrace'>{</span> <span class='label'>array:</span> <span class='symbol'>:integer</span> <span class='rbrace'>}</span><span class='comma'>,</span>
344
- <span class='label'>birthday:</span> <span class='const'>Date</span><span class='comma'>,</span>
345
- <span class='label'>comment:</span> <span class='lbrace'>{</span>
346
- <span class='label'>type:</span> <span class='symbol'>:string</span><span class='comma'>,</span>
347
- <span class='label'>required:</span> <span class='kw'>false</span><span class='comma'>,</span>
348
- <span class='label'>null:</span> <span class='kw'>true</span>
349
- <span class='rbrace'>}</span><span class='comma'>,</span>
350
- <span class='label'>ar_object:</span> <span class='const'>User</span>
351
- <span class='rbrace'>}</span>
352
- <span class='rbrace'>}</span>
353
- <span class='rbrace'>}</span><span class='comma'>,</span>
354
- <span class='rbrace'>}</span>
513
+ <p>A more complex example:</p>
514
+
515
+ <p>Long form:</p>
516
+
517
+ <pre class="code ruby"><code class="ruby"><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
518
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
519
+ <span class='id identifier rubyid_req'>req</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>nutrition</span><span class='tstring_end'>&#39;</span></span> <span class='kw'>do</span>
520
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:array</span> <span class='kw'>do</span>
521
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:array</span> <span class='kw'>do</span>
522
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span><span class='comma'>,</span> <span class='label'>check:</span> <span class='id identifier rubyid_proc'>proc</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_h'>h</span><span class='op'>|</span> <span class='id identifier rubyid_h'>h</span><span class='period'>.</span><span class='id identifier rubyid_member?'>member?</span><span class='lparen'>(</span><span class='symbol'>:food</span><span class='rparen'>)</span> <span class='op'>||</span> <span class='id identifier rubyid_h'>h</span><span class='period'>.</span><span class='id identifier rubyid_member?'>member?</span><span class='lparen'>(</span><span class='symbol'>:drink</span><span class='rparen'>)</span> <span class='rbrace'>}</span> <span class='kw'>do</span>
523
+ <span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:food</span> <span class='kw'>do</span>
524
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:object</span>
525
+ <span class='kw'>end</span>
526
+ <span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:drink</span> <span class='kw'>do</span>
527
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:object</span>
528
+ <span class='kw'>end</span>
529
+ <span class='kw'>end</span>
530
+ <span class='kw'>end</span>
531
+ <span class='kw'>end</span>
532
+ <span class='kw'>end</span>
533
+ <span class='kw'>end</span>
534
+ <span class='kw'>end</span>
355
535
  </code></pre>
356
536
 
537
+ <p>Short form (with this short form others from above):</p>
538
+
539
+ <pre class="code ruby"><code class="ruby"><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
540
+ <span class='id identifier rubyid_req'>req</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>nutrition</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span> <span class='symbol'>:array</span><span class='comma'>,</span> <span class='symbol'>:array</span><span class='comma'>,</span> <span class='symbol'>:hash</span><span class='comma'>,</span> <span class='label'>check:</span> <span class='id identifier rubyid_proc'>proc</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_h'>h</span><span class='op'>|</span> <span class='id identifier rubyid_h'>h</span><span class='period'>.</span><span class='id identifier rubyid_member?'>member?</span><span class='lparen'>(</span><span class='symbol'>:food</span><span class='rparen'>)</span> <span class='op'>||</span> <span class='id identifier rubyid_h'>h</span><span class='period'>.</span><span class='id identifier rubyid_member?'>member?</span><span class='lparen'>(</span><span class='symbol'>:drink</span><span class='rparen'>)</span> <span class='rbrace'>}</span> <span class='kw'>do</span>
541
+ <span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:food</span>
542
+ <span class='id identifier rubyid_opt!'>opt!</span> <span class='symbol'>:drink</span>
543
+ <span class='kw'>end</span>
544
+ <span class='kw'>end</span>
545
+ </code></pre>
546
+
547
+ <p>This example accepts a hash with exactly one String key &#39;nutrition&#39; with value
548
+ of type Array with children of type Array with children of type Hash in which at
549
+ least one of the Symbol keys <code>:food</code> and <code>:drink</code> (with any non-nil value type)
550
+ is present.</p>
551
+
357
552
  <h2>Exceptions</h2>
358
553
 
359
554
  <p>Schemacop will throw one of the following checked exceptions:</p>
360
555
 
361
556
  <ul>
362
- <li><span class='object_link'><a href="Schemacop/Exceptions/InvalidSchema.html" title="Schemacop::Exceptions::InvalidSchema (class)">Schemacop::Exceptions::InvalidSchema</a></span></li>
557
+ <li><span class='object_link'><a href="Schemacop/Exceptions/InvalidSchemaError.html" title="Schemacop::Exceptions::InvalidSchemaError (class)">Schemacop::Exceptions::InvalidSchemaError</a></span></li>
363
558
  </ul>
364
559
 
365
560
  <p>This exception is thrown when the given schema definition format is invalid.</p>
366
561
 
367
562
  <ul>
368
- <li><span class='object_link'><a href="Schemacop/Exceptions/Validation.html" title="Schemacop::Exceptions::Validation (class)">Schemacop::Exceptions::Validation</a></span></li>
563
+ <li><span class='object_link'><a href="Schemacop/Exceptions/ValidationError.html" title="Schemacop::Exceptions::ValidationError (class)">Schemacop::Exceptions::ValidationError</a></span></li>
369
564
  </ul>
370
565
 
371
566
  <p>This exception is thrown when the given data does not comply with the given
@@ -385,19 +580,20 @@ needs to be given only if field <code>b</code> is present).</p></li>
385
580
  <h2>Contributors</h2>
386
581
 
387
582
  <p>Thanks to <a href="https://github.com/bbatsov/rubocop">Rubocop</a> for great inspiration
388
- concerning their name and the structure of their README file. And special thanks to
389
- <a href="http://www.subgit.com/">SubGit</a> for their great open source licensing.</p>
583
+ concerning their name and the structure of their README file. And special thanks
584
+ to <a href="http://www.subgit.com/">SubGit</a> for their great open source licensing.</p>
390
585
 
391
586
  <h2>Copyright</h2>
392
587
 
393
- <p>Copyright (c) 2016 Sitrox. See <code>LICENSE</code> for further details.</p>
588
+ <p>Copyright (c) 2017 Sitrox. See <code>LICENSE</code> for further details.</p>
394
589
  </div></div>
395
590
 
396
- <div id="footer">
397
- Generated on Thu Oct 6 19:45:02 2016 by
591
+ <div id="footer">
592
+ Generated on Mon May 15 17:46:05 2017 by
398
593
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
399
- 0.8.7.6 (ruby-2.3.1).
594
+ 0.9.9 (ruby-2.3.1).
400
595
  </div>
401
596
 
597
+ </div>
402
598
  </body>
403
599
  </html>