schemacop 1.0.2 → 2.0.0

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