schemacop 2.1.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +58 -0
  3. data/LICENSE +1 -1
  4. data/README.md +250 -16
  5. data/RUBY_VERSION +1 -1
  6. data/Rakefile +6 -1
  7. data/VERSION +1 -1
  8. data/doc/Schemacop.html +32 -5
  9. data/doc/Schemacop/ArrayValidator.html +4 -4
  10. data/doc/Schemacop/BooleanValidator.html +4 -4
  11. data/doc/Schemacop/Caster.html +379 -0
  12. data/doc/Schemacop/Collector.html +298 -46
  13. data/doc/Schemacop/Exceptions.html +3 -3
  14. data/doc/Schemacop/Exceptions/InvalidSchemaError.html +3 -3
  15. data/doc/Schemacop/Exceptions/ValidationError.html +3 -3
  16. data/doc/Schemacop/FieldNode.html +19 -7
  17. data/doc/Schemacop/FloatValidator.html +4 -4
  18. data/doc/Schemacop/HashValidator.html +33 -7
  19. data/doc/Schemacop/IntegerValidator.html +4 -4
  20. data/doc/Schemacop/NilValidator.html +4 -4
  21. data/doc/Schemacop/Node.html +97 -85
  22. data/doc/Schemacop/NodeResolver.html +28 -12
  23. data/doc/Schemacop/NodeSupportingField.html +4 -4
  24. data/doc/Schemacop/NodeSupportingType.html +5 -7
  25. data/doc/Schemacop/NodeWithBlock.html +4 -4
  26. data/doc/Schemacop/NumberValidator.html +4 -4
  27. data/doc/Schemacop/ObjectValidator.html +20 -10
  28. data/doc/Schemacop/RootNode.html +4 -4
  29. data/doc/Schemacop/Schema.html +6 -6
  30. data/doc/Schemacop/StringValidator.html +3 -3
  31. data/doc/Schemacop/SymbolValidator.html +4 -4
  32. data/doc/ScopedEnv.html +3 -3
  33. data/doc/_index.html +11 -4
  34. data/doc/class_list.html +1 -1
  35. data/doc/css/style.css +10 -6
  36. data/doc/file.README.html +255 -29
  37. data/doc/frames.html +1 -1
  38. data/doc/index.html +255 -29
  39. data/doc/js/app.js +55 -0
  40. data/doc/method_list.html +99 -51
  41. data/doc/top-level-namespace.html +3 -3
  42. data/lib/schemacop.rb +15 -0
  43. data/lib/schemacop/caster.rb +38 -0
  44. data/lib/schemacop/collector.rb +53 -6
  45. data/lib/schemacop/field_node.rb +25 -3
  46. data/lib/schemacop/node.rb +16 -4
  47. data/lib/schemacop/node_resolver.rb +10 -2
  48. data/lib/schemacop/node_supporting_field.rb +0 -2
  49. data/lib/schemacop/node_supporting_type.rb +21 -1
  50. data/lib/schemacop/schema.rb +3 -3
  51. data/lib/schemacop/validator/array_validator.rb +1 -1
  52. data/lib/schemacop/validator/float_validator.rb +1 -1
  53. data/lib/schemacop/validator/hash_validator.rb +15 -2
  54. data/lib/schemacop/validator/integer_validator.rb +1 -1
  55. data/lib/schemacop/validator/object_validator.rb +7 -1
  56. data/schemacop.gemspec +15 -9
  57. data/test/casting_test.rb +90 -0
  58. data/test/collector_test.rb +45 -0
  59. data/test/custom_check_test.rb +20 -13
  60. data/test/custom_if_test.rb +12 -12
  61. data/test/defaults_test.rb +71 -0
  62. data/test/nil_dis_allow_test.rb +6 -6
  63. data/test/node_resolver_test.rb +26 -0
  64. data/test/short_forms_test.rb +86 -64
  65. data/test/test_helper.rb +7 -0
  66. data/test/types_test.rb +5 -5
  67. data/test/validator_array_test.rb +16 -16
  68. data/test/validator_boolean_test.rb +2 -2
  69. data/test/validator_float_test.rb +15 -15
  70. data/test/validator_hash_test.rb +5 -5
  71. data/test/validator_integer_test.rb +9 -9
  72. data/test/validator_nil_test.rb +1 -1
  73. data/test/validator_number_test.rb +19 -19
  74. data/test/validator_object_test.rb +33 -15
  75. data/test/validator_string_test.rb +12 -12
  76. data/test/validator_symbol_test.rb +2 -2
  77. metadata +43 -6
@@ -43,7 +43,7 @@
43
43
 
44
44
  <ul id="full_list" class="class">
45
45
  <li id="object_" class="odd"><div class="item" style="padding-left:30px"><span class='object_link'><a href="top-level-namespace.html" title="Top Level Namespace (root)">Top Level Namespace</a></span></div></li>
46
- <li id='object_Schemacop' class='even'><div class='item' style='padding-left:30px'><a class='toggle'></a> <span class='object_link'><a href="Schemacop.html" title="Schemacop (module)">Schemacop</a></span><small class='search_info'>Top Level Namespace</small></div><ul><li id='object_Schemacop::ArrayValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/ArrayValidator.html" title="Schemacop::ArrayValidator (class)">ArrayValidator</a></span> &lt; NodeSupportingType<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::BooleanValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/BooleanValidator.html" title="Schemacop::BooleanValidator (class)">BooleanValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Collector' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/Collector.html" title="Schemacop::Collector (class)">Collector</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Exceptions' class='collapsed even'><div class='item' style='padding-left:45px'><a class='toggle'></a> <span class='object_link'><a href="Schemacop/Exceptions.html" title="Schemacop::Exceptions (module)">Exceptions</a></span><small class='search_info'>Schemacop</small></div><ul><li id='object_Schemacop::Exceptions::InvalidSchemaError' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="Schemacop/Exceptions/InvalidSchemaError.html" title="Schemacop::Exceptions::InvalidSchemaError (class)">InvalidSchemaError</a></span> &lt; RuntimeError<small class='search_info'>Schemacop::Exceptions</small></div></li><li id='object_Schemacop::Exceptions::ValidationError' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="Schemacop/Exceptions/ValidationError.html" title="Schemacop::Exceptions::ValidationError (class)">ValidationError</a></span> &lt; RuntimeError<small class='search_info'>Schemacop::Exceptions</small></div></li></ul></li><li id='object_Schemacop::FieldNode' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/FieldNode.html" title="Schemacop::FieldNode (class)">FieldNode</a></span> &lt; NodeSupportingType<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::FloatValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/FloatValidator.html" title="Schemacop::FloatValidator (class)">FloatValidator</a></span> &lt; NumberValidator<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::HashValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/HashValidator.html" title="Schemacop::HashValidator (class)">HashValidator</a></span> &lt; NodeSupportingField<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::IntegerValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/IntegerValidator.html" title="Schemacop::IntegerValidator (class)">IntegerValidator</a></span> &lt; NumberValidator<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NilValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NilValidator.html" title="Schemacop::NilValidator (class)">NilValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Node' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/Node.html" title="Schemacop::Node (class)">Node</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeResolver' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeResolver.html" title="Schemacop::NodeResolver (class)">NodeResolver</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeSupportingField' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeSupportingField.html" title="Schemacop::NodeSupportingField (class)">NodeSupportingField</a></span> &lt; NodeWithBlock<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeSupportingType' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeSupportingType.html" title="Schemacop::NodeSupportingType (class)">NodeSupportingType</a></span> &lt; NodeWithBlock<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeWithBlock' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeWithBlock.html" title="Schemacop::NodeWithBlock (class)">NodeWithBlock</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NumberValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NumberValidator.html" title="Schemacop::NumberValidator (class)">NumberValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::ObjectValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/ObjectValidator.html" title="Schemacop::ObjectValidator (class)">ObjectValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::RootNode' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/RootNode.html" title="Schemacop::RootNode (class)">RootNode</a></span> &lt; NodeSupportingType<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Schema' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/Schema.html" title="Schemacop::Schema (class)">Schema</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::StringValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/StringValidator.html" title="Schemacop::StringValidator (class)">StringValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::SymbolValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/SymbolValidator.html" title="Schemacop::SymbolValidator (class)">SymbolValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li></ul></li><li id='object_ScopedEnv' class='odd'><div class='item' style='padding-left:30px'><span class='object_link'><a href="ScopedEnv.html" title="ScopedEnv (class)">ScopedEnv</a></span> &lt; Object<small class='search_info'>Top Level Namespace</small></div></li>
46
+ <li id='object_Schemacop' class='even'><div class='item' style='padding-left:30px'><a class='toggle'></a> <span class='object_link'><a href="Schemacop.html" title="Schemacop (module)">Schemacop</a></span><small class='search_info'>Top Level Namespace</small></div><ul><li id='object_Schemacop::ArrayValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/ArrayValidator.html" title="Schemacop::ArrayValidator (class)">ArrayValidator</a></span> &lt; NodeSupportingType<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::BooleanValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/BooleanValidator.html" title="Schemacop::BooleanValidator (class)">BooleanValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Caster' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/Caster.html" title="Schemacop::Caster (class)">Caster</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Collector' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/Collector.html" title="Schemacop::Collector (class)">Collector</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Exceptions' class='collapsed odd'><div class='item' style='padding-left:45px'><a class='toggle'></a> <span class='object_link'><a href="Schemacop/Exceptions.html" title="Schemacop::Exceptions (module)">Exceptions</a></span><small class='search_info'>Schemacop</small></div><ul><li id='object_Schemacop::Exceptions::InvalidSchemaError' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="Schemacop/Exceptions/InvalidSchemaError.html" title="Schemacop::Exceptions::InvalidSchemaError (class)">InvalidSchemaError</a></span> &lt; RuntimeError<small class='search_info'>Schemacop::Exceptions</small></div></li><li id='object_Schemacop::Exceptions::ValidationError' class='collapsed'><div class='item' style='padding-left:60px'><span class='object_link'><a href="Schemacop/Exceptions/ValidationError.html" title="Schemacop::Exceptions::ValidationError (class)">ValidationError</a></span> &lt; RuntimeError<small class='search_info'>Schemacop::Exceptions</small></div></li></ul></li><li id='object_Schemacop::FieldNode' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/FieldNode.html" title="Schemacop::FieldNode (class)">FieldNode</a></span> &lt; NodeSupportingType<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::FloatValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/FloatValidator.html" title="Schemacop::FloatValidator (class)">FloatValidator</a></span> &lt; NumberValidator<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::HashValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/HashValidator.html" title="Schemacop::HashValidator (class)">HashValidator</a></span> &lt; NodeSupportingField<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::IntegerValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/IntegerValidator.html" title="Schemacop::IntegerValidator (class)">IntegerValidator</a></span> &lt; NumberValidator<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NilValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NilValidator.html" title="Schemacop::NilValidator (class)">NilValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Node' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/Node.html" title="Schemacop::Node (class)">Node</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeResolver' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeResolver.html" title="Schemacop::NodeResolver (class)">NodeResolver</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeSupportingField' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeSupportingField.html" title="Schemacop::NodeSupportingField (class)">NodeSupportingField</a></span> &lt; NodeWithBlock<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeSupportingType' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeSupportingType.html" title="Schemacop::NodeSupportingType (class)">NodeSupportingType</a></span> &lt; NodeWithBlock<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NodeWithBlock' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NodeWithBlock.html" title="Schemacop::NodeWithBlock (class)">NodeWithBlock</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::NumberValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/NumberValidator.html" title="Schemacop::NumberValidator (class)">NumberValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::ObjectValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/ObjectValidator.html" title="Schemacop::ObjectValidator (class)">ObjectValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::RootNode' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/RootNode.html" title="Schemacop::RootNode (class)">RootNode</a></span> &lt; NodeSupportingType<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::Schema' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/Schema.html" title="Schemacop::Schema (class)">Schema</a></span> &lt; Object<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::StringValidator' class='collapsed even'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/StringValidator.html" title="Schemacop::StringValidator (class)">StringValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li><li id='object_Schemacop::SymbolValidator' class='collapsed odd'><div class='item' style='padding-left:45px'><span class='object_link'><a href="Schemacop/SymbolValidator.html" title="Schemacop::SymbolValidator (class)">SymbolValidator</a></span> &lt; Node<small class='search_info'>Schemacop</small></div></li></ul></li><li id='object_ScopedEnv' class='even'><div class='item' style='padding-left:30px'><span class='object_link'><a href="ScopedEnv.html" title="ScopedEnv (class)">ScopedEnv</a></span> &lt; Object<small class='search_info'>Top Level Namespace</small></div></li>
47
47
 
48
48
  </ul>
49
49
  </div>
@@ -245,6 +245,7 @@ ul.toplevel { list-style: none; padding-left: 0; font-size: 1.1em; }
245
245
 
246
246
  dl.constants { margin-left: 10px; }
247
247
  dl.constants dt { font-weight: bold; font-size: 1.1em; margin-bottom: 5px; }
248
+ dl.constants.compact dt { display: inline-block; font-weight: normal }
248
249
  dl.constants dd { width: 75%; white-space: pre; font-family: monospace; margin-bottom: 18px; }
249
250
  dl.constants .docstring .note:first-child { margin-top: 5px; }
250
251
 
@@ -326,13 +327,9 @@ ul.summary a, ul.summary a:visited {
326
327
  text-decoration: none; font-size: 1.1em;
327
328
  }
328
329
  ul.summary li { margin-bottom: 5px; }
329
- .summary .summary_signature {
330
- padding: 4px 8px;
331
- background: #f8f8f8;
332
- border: 1px solid #f0f0f0;
333
- border-radius: 5px;
334
- }
330
+ .summary_signature { padding: 4px 8px; background: #f8f8f8; border: 1px solid #f0f0f0; border-radius: 5px; }
335
331
  .summary_signature:hover { background: #CFEBFF; border-color: #A4CCDA; cursor: pointer; }
332
+ .summary_signature.deprecated { background: #ffe5e5; border-color: #e9dada; }
336
333
  ul.summary.compact li { display: inline-block; margin: 0px 5px 0px 0px; line-height: 2.6em;}
337
334
  ul.summary.compact .summary_signature { padding: 5px 7px; padding-right: 4px; }
338
335
  #content .summary_signature:hover a,
@@ -484,6 +481,13 @@ pre.code .rubyid_backref,
484
481
  pre.code .rubyid_nth_ref { color: #6D79DE; }
485
482
  pre.code .regexp, .dregexp { color: #036A07; }
486
483
  pre.code a { border-bottom: 1px dotted #bbf; }
484
+ /* inline code */
485
+ *:not(pre) > code {
486
+ padding: 1px 3px 1px 3px;
487
+ border: 1px solid #E1E1E8;
488
+ background: #F7F7F9;
489
+ border-radius: 4px;
490
+ }
487
491
 
488
492
  /* Color fix for links */
489
493
  #content .summary_desc pre.code .id > .object_link a, /* identifier */
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  File: README
8
8
 
9
- &mdash; Documentation by YARD 0.9.9
9
+ &mdash; Documentation by YARD 0.9.20
10
10
 
11
11
  </title>
12
12
 
@@ -132,7 +132,7 @@ around at runtime. Those two steps look as follows:</p>
132
132
 
133
133
  <p>At runtime:</p>
134
134
 
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>
135
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_my_schema'>my_schema</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span>
136
136
  <span class='comment'># Your data goes here
137
137
  </span><span class='rparen'>)</span>
138
138
  </code></pre>
@@ -161,7 +161,7 @@ this:</p>
161
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
162
  <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
163
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>
164
+ <span class='id identifier rubyid_req'>req</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>present</span><span class='tstring_end'>&#39;</span></span> <span class='kw'>do</span>
165
165
  <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:boolean</span>
166
166
  <span class='kw'>end</span>
167
167
  <span class='kw'>end</span>
@@ -177,12 +177,38 @@ FalseClass).</p>
177
177
  <h3><code>validate</code> vs <code>validate!</code> vs <code>valid?</code></h3>
178
178
 
179
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>
180
+ validation errors (if any) as well as a deep copy of your data with applied
181
+ defaults and castings, whereas <code>validate!</code> will accumulate all violations
182
+ and finally throw an exception describing them or, if the validation was
183
+ successful, a deep-copy of your supplied data with defaults and castings
184
+ applied.</p>
182
185
 
183
186
  <p>For simply querying the validity of some data, use the methods <code>valid?</code> or
184
187
  <code>invalid?</code>.</p>
185
188
 
189
+ <p>Examples:</p>
190
+
191
+ <pre class="code ruby"><code class="ruby"><span class='comment'># validate! returns your modified data or throws a validation error
192
+ </span><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>
193
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='int'>42</span>
194
+ <span class='kw'>end</span>
195
+ <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='lbrace'>{</span><span class='rbrace'>}</span><span class='rparen'>)</span> <span class='comment'># =&gt; { foo: 42 }
196
+ </span>
197
+ <span class='comment'># validate returns a collector
198
+ </span><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>
199
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='int'>42</span>
200
+ <span class='kw'>end</span>
201
+
202
+ <span class='id identifier rubyid_collector'>collector</span> <span class='op'>=</span> <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate'>validate</span><span class='lparen'>(</span><span class='lbrace'>{</span><span class='rbrace'>}</span><span class='rparen'>)</span>
203
+ <span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_valid?'>valid?</span> <span class='comment'># true
204
+ </span><span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_data'>data</span> <span class='comment'># =&gt; { foo: 42 }
205
+ </span>
206
+ <span class='id identifier rubyid_collector'>collector</span> <span class='op'>=</span> <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate'>validate</span><span class='lparen'>(</span><span class='lbrace'>{</span> <span class='label'>foo:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>invalid</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span><span class='rparen'>)</span>
207
+ <span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_valid?'>valid?</span> <span class='comment'># false
208
+ </span><span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_data'>data</span> <span class='comment'># =&gt; nil
209
+ </span><span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_exceptions'>exceptions</span> <span class='comment'># =&gt; Validation error
210
+ </span></code></pre>
211
+
186
212
  <h2>Schemacop&#39;s DSL</h2>
187
213
 
188
214
  <p>In this section, we will ignore <a href="#short-forms">short forms</a> and explicitly
@@ -235,7 +261,7 @@ proc returns false.&quot;</p>
235
261
 
236
262
  <p>The corresponding schema would look as follows:</p>
237
263
 
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>
264
+ <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>
239
265
  <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
266
  <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
241
267
  <span class='kw'>end</span>
@@ -256,8 +282,8 @@ the type checking, meaning that it only gets executed if the data has the right
256
282
  type and the proc in <code>if</code> (if any) has returned true.</p>
257
283
 
258
284
  <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>
285
+ return true if the data passes the custom check. If it returns false or an error
286
+ message as a string, Schemacop considers the data to be invalid.</p>
261
287
 
262
288
  <p>The following example illustrates the use of the option <code>check</code>: Consider a
263
289
  scenario in which you want the following rule set:</p>
@@ -278,10 +304,19 @@ scenario in which you want the following rule set:</p>
278
304
  <p>The above Type Line has type <code>:string</code> and two options (<code>min</code> and <code>check</code>). The
279
305
  option <code>min</code> is supported by the <code>:string</code> validator (covered later).</p>
280
306
 
307
+ <p>You can also specify a custom error message by returning a string:</p>
308
+
309
+ <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>
310
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</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_i'>i</span><span class='op'>|</span> <span class='id identifier rubyid_i'>i</span><span class='period'>.</span><span class='id identifier rubyid_even?'>even?</span> <span class='op'>?</span> <span class='kw'>true</span> <span class='op'>:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Custom error</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span>
311
+ <span class='kw'>end</span>
312
+ </code></pre>
313
+
314
+ <p>This will include <code>Custom error</code> in the validation error message.</p>
315
+
281
316
  <h3>Field Line</h3>
282
317
 
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>
318
+ <p>Inside a Type Line of type <code>:hash</code>, you may specify an arbitrary number of field
319
+ lines (one for each key-value pair you want to be in the hash).</p>
285
320
 
286
321
  <p>Field Lines start with one of the following six identifiers: <code>req</code>, <code>req?</code>,
287
322
  <code>req!</code>, <code>opt</code>, <code>opt?</code> or <code>opt!</code>:</p>
@@ -327,6 +362,35 @@ non-nil field of type Integer or Date under the key <code>:age</code>.</p>
327
362
  <p>You might find the notation cumbersome, and you&#39;d be right to say so. Luckily
328
363
  there are plenty of short forms available which we will see below.</p>
329
364
 
365
+ <h4>Handling hashes with indifferent access</h4>
366
+
367
+ <p>Schemacop has special handling for objects of the class
368
+ <code>ActiveSupport::HashWithIndifferentAccess</code>: You may specify the keys as symbols
369
+ or strings, and Schemacop will handle the conversion necessary for proper
370
+ validation internally. Note that if you define the same key as string and
371
+ symbol, it will throw a <code>ValidationError</code> <a href="#exceptions">exception</a> when asked to
372
+ validate a hash with indifferent access.</p>
373
+
374
+ <p>Thus, the following two schema definitions are equivalent when validating a hash
375
+ with indifferent access:</p>
376
+
377
+ <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>
378
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
379
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:name</span> <span class='kw'>do</span>
380
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
381
+ <span class='kw'>end</span>
382
+ <span class='kw'>end</span>
383
+ <span class='kw'>end</span>
384
+
385
+ <span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
386
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
387
+ <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>
388
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
389
+ <span class='kw'>end</span>
390
+ <span class='kw'>end</span>
391
+ <span class='kw'>end</span>
392
+ </code></pre>
393
+
330
394
  <h2>Types</h2>
331
395
 
332
396
  <p>Types are defined via their validators, which is a class under <code>validator/</code>.
@@ -357,31 +421,38 @@ Each validator is sourced by <code>schemacop.rb</code>.</p>
357
421
  <li>supported options: <code>min</code>, <code>max</code> (bounds for string length)</li>
358
422
  </ul></li>
359
423
  <li><p><code>:symbol</code> accepts a Ruby Symbol.</p></li>
360
- <li><p><code>:object</code> accepts an arbitrary Ruby object (any object if no option is given).</p>
424
+ <li><p><code>:object</code> accepts an arbitrary Ruby object (any object if no option is given).</p></li>
425
+ </ul>
426
+
427
+ <p>Supported options:</p>
361
428
 
362
429
  <ul>
363
- <li>supported option: <code>classes</code>: Ruby class (or an array of them) that will be
364
- the only recognized filters. Unlike other options, this one affects not the
365
- validation but the type recognition, meaning that you can have multiple Type
366
- Lines with different <code>classes</code> option for the same field, each having its
367
- own validation (e.g. through the option <code>check</code>).</li>
368
- </ul></li>
369
- <li><p><code>:array</code> accepts a Ruby Array.</p>
430
+ <li><p><code>classes</code>: Ruby class (or an array of them) that will be the only recognized
431
+ filters. Unlike other options, this one affects not the validation but the
432
+ type recognition, meaning that you can have multiple Type Lines with
433
+ different <code>classes</code> option for the same field, each having its own
434
+ validation (e.g. through the option <code>check</code>).</p></li>
435
+ <li><p><code>strict</code>: Boolean option, defaults to true. If set to false, the validator
436
+ also allows derived classes of those specified with <code>classes</code>.</p>
370
437
 
371
438
  <ul>
372
- <li>supported options: <code>min</code>, <code>max</code> (bounds for array size) and <code>nil</code>: TODO</li>
373
- <li>accepts a block with an arbitrary number of Type Lines.</li>
374
- <li>TODO no lookahead for different arrays, see
375
- validator_array_test#test_multiple_arrays</li>
439
+ <li><code>:array</code> accepts a Ruby Array.</li>
376
440
  </ul></li>
377
- <li><p><code>:hash</code> accepts a Ruby Hash.</p>
441
+ <li><p>supported options: <code>min</code>, <code>max</code> (bounds for array size) and <code>nil</code>: TODO</p></li>
442
+ <li><p>accepts a block with an arbitrary number of Type Lines.</p></li>
443
+ <li><p>TODO no lookahead for different arrays, see
444
+ validator_array_test#test_multiple_arrays</p>
378
445
 
379
446
  <ul>
380
- <li>accepts a block with an arbitrary number of Field Lines.</li>
447
+ <li><code>:hash</code> accepts a Ruby Hash or an <code>ActiveSupport::HashWithIndifferentAccess</code>.</li>
381
448
  </ul></li>
382
- <li><p><code>:nil</code>: accepts a Ruby NilClass instance. If you want to allow <code>nil</code> as a
449
+ <li><p>accepts a block with an arbitrary number of Field Lines.</p>
450
+
451
+ <ul>
452
+ <li><code>:nil</code>: accepts a Ruby NilClass instance. If you want to allow <code>nil</code> as a
383
453
  value in a field, see above for the usage of the suffixes <code>-!</code> and <code>-?</code> for
384
- Field Lines.</p></li>
454
+ Field Lines.</li>
455
+ </ul></li>
385
456
  </ul>
386
457
 
387
458
  <p>All types support the options <code>if</code> and <code>check</code> (see the section about Type Lines
@@ -495,6 +566,10 @@ write Field Lines in the schema instantiation:</p>
495
566
  <span class='kw'>end</span>
496
567
  </code></pre>
497
568
 
569
+ <p>Note that this does not allow you to specify any options for the hash itself.
570
+ You still need to specify <code>:hash</code> as a type if you want to pass any options to
571
+ the hash (i.e. a <code>default</code>).</p>
572
+
498
573
  <h3>Shortform for subtypes</h3>
499
574
 
500
575
  <p>In case of nested arrays, you can group all Type Lines to a single one.</p>
@@ -550,6 +625,145 @@ of type Array with children of type Array with children of type Hash in which at
550
625
  least one of the Symbol keys <code>:food</code> and <code>:drink</code> (with any non-nil value type)
551
626
  is present.</p>
552
627
 
628
+ <h2>Defaults</h2>
629
+
630
+ <p>Starting from version 2.4.0, Schemacop allows you to define default values at
631
+ any point in your schema. If the validated data contains a nil value, it will be
632
+ substituted by the given default value.</p>
633
+
634
+ <p>Note that Schemacop never modifies the data you pass to it. If you want to
635
+ benefit from Schemacop-applied defaults, you need to access the cloned, modified
636
+ data returned by <code>validate</code> or <code>validate!</code>.</p>
637
+
638
+ <p>Applying defaults is done before validating the substructure and before any type
639
+ casting. The provided default will be validated same as user-supplied data, so
640
+ if your given default does not validate properly, a validation error is thrown.
641
+ Make sure your default values always match the underlying schema.</p>
642
+
643
+ <p>Defaults can be specified at any point:</p>
644
+
645
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Basic usage
646
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
647
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Hello World</span><span class='tstring_end'>&#39;</span></span>
648
+ <span class='kw'>end</span>
649
+
650
+ <span class='comment'># The default given for the first type will match
651
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
652
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Hello World</span><span class='tstring_end'>&#39;</span></span> <span class='comment'># This will always be applied of no value is supplied
653
+ </span> <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='int'>42</span>
654
+ <span class='kw'>end</span>
655
+
656
+ <span class='comment'># You can also pass entire hashes or arrays to your defaults
657
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
658
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='symbol'>:hash</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='lbrace'>{</span> <span class='label'>foo:</span> <span class='symbol'>:bar</span> <span class='rbrace'>}</span> <span class='kw'>do</span>
659
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='symbol'>:symbol</span>
660
+ <span class='kw'>end</span>
661
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:bar</span><span class='comma'>,</span> <span class='symbol'>:array</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>default:</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>
662
+ <span class='kw'>end</span>
663
+
664
+ <span class='comment'># Defaults must match the given schema. The following will fail.
665
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
666
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='lbrace'>{</span> <span class='label'>bar:</span> <span class='symbol'>:baz</span> <span class='rbrace'>}</span> <span class='kw'>do</span>
667
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span>
668
+ <span class='kw'>end</span>
669
+ <span class='kw'>end</span>
670
+ </code></pre>
671
+
672
+ <h3>Required data points</h3>
673
+
674
+ <p>Note that any <em>required</em> validation is done before applying the defaults. If you
675
+ specify a <code>req</code> field, it must always be given, no matter if you have specified
676
+ a default or not. Therefore, specifying <code>req</code> fields do not make sense in
677
+ conjunction with defaults, as the default is always ignored.</p>
678
+
679
+ <h2>Type casting</h2>
680
+
681
+ <p>Starting from version 2.4.0, Schemacop allows you to specify type castings that
682
+ can alter the validated data. Consider the following:</p>
683
+
684
+ <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>
685
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:id</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>cast:</span> <span class='lbracket'>[</span><span class='const'>String</span><span class='rbracket'>]</span>
686
+ <span class='kw'>end</span>
687
+
688
+ <span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='label'>id:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>42</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span>
689
+ <span class='id identifier rubyid_data'>data</span> <span class='comment'># =&gt; { id: 42 }
690
+ </span></code></pre>
691
+
692
+ <p>Note that Schemacop never modifies the data you pass to it. If you want to
693
+ benefit from Schemacop-applied castings, you need to access the cloned, modified
694
+ data returned by <code>validate</code> or <code>validate!</code>.</p>
695
+
696
+ <h3>Specifying type castings</h3>
697
+
698
+ <p>Type castings can be specified using two forms: Either as a hash or as an array.
699
+ While using an array only allows you to specify the supported source types to be
700
+ casted, using a hash allows you to specify custom casting logic as blocks.</p>
701
+
702
+ <p>For hashes, the key must be a class and the value must be either <code>:default</code> for
703
+ using a built-in caster or a callable object (proc or lambda) that receives the
704
+ value and is supposed to cast it. If the value can&#39;t be casted, the proc must
705
+ fail with an exception. The exception message will then be contained in the
706
+ collected validation errors.</p>
707
+
708
+ <p>Example:</p>
709
+
710
+ <pre class="code ruby"><code class="ruby">Schema.new do
711
+ # Pass array to `cast`. This enables casting from String or Float to Integer
712
+ # using the built-in casters.
713
+ req: id_1, :integer, cast: [String, Float]
714
+
715
+ # Pass hash to `cast`. This enables casting from Float to Integer using the
716
+ # built-in caster and from String to Integer using a custom callback.
717
+ req :id_2, :integer, cast: { Float =&gt; :default, String =&gt; proc { |s| Integer(s) }
718
+ end
719
+ </code></pre>
720
+
721
+ <h3>Built-in casters</h3>
722
+
723
+ <p>Schemacop comes with the following casters:</p>
724
+
725
+ <ul>
726
+ <li><code>String</code> to <code>Integer</code> and <code>Float</code></li>
727
+ <li><code>Float</code> to <code>Integer</code></li>
728
+ <li><code>Integer</code> to <code>Float</code></li>
729
+ </ul>
730
+
731
+ <p>Note that all built-in casters are precise, so the string <code>foo</code> will fail with
732
+ an error if casted to an Integer. When casting float values and strings
733
+ containing float values to integers, the decimal places will be discarded
734
+ however.</p>
735
+
736
+ <h3>Execution order</h3>
737
+
738
+ <p>The casting is done <em>before</em> the options <code>if</code> and <code>check</code> are evaluated.
739
+ Example:</p>
740
+
741
+ <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>
742
+ <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_i'>i</span><span class='op'>|</span> <span class='id identifier rubyid_i'>i</span> <span class='op'>==</span> <span class='int'>42</span> <span class='rbrace'>}</span> <span class='comment'># 1
743
+ </span> <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</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_i'>i</span><span class='op'>|</span> <span class='id identifier rubyid_i'>i</span> <span class='op'>&lt;</span> <span class='int'>3</span> <span class='rbrace'>}</span> <span class='comment'># 2
744
+ </span> <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
745
+ <span class='kw'>end</span>
746
+
747
+ <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>42</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='comment'># 1 will match
748
+ </span><span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>2</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='comment'># 2 will match
749
+ </span><span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>234</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='comment'># 3 will match
750
+ </span><span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='int'>5</span><span class='rparen'>)</span> <span class='comment'># Will fail, as nothing matches
751
+ </span></code></pre>
752
+
753
+ <h3>Caveats</h3>
754
+
755
+ <p>Casting only works with type definitions that only include one type. For
756
+ instance, the <code>Numeric</code> validator includes both <code>Integer</code> and <code>Float</code>, which
757
+ would made it unclear what to cast a string into:</p>
758
+
759
+ <pre class="code ruby"><code class="ruby"><span class='comment'># This does not work, as it is unclear whether to cast the String into an
760
+ </span><span class='comment'># Integer or a Float.
761
+ </span><span class='id identifier rubyid_type'>type</span> <span class='symbol'>:number</span><span class='comma'>,</span> <span class='label'>cast:</span> <span class='lbracket'>[</span><span class='const'>String</span><span class='rbracket'>]</span>
762
+ </code></pre>
763
+
764
+ <p>The same also applies to booleans, as they compound both <code>TrueClass</code> and
765
+ <code>FalseClass</code>. This may be tackled in future releases.</p>
766
+
553
767
  <h2>Exceptions</h2>
554
768
 
555
769
  <p>Schemacop will throw one of the following checked exceptions:</p>
@@ -578,6 +792,18 @@ needs to be given only if field <code>b</code> is present).</p></li>
578
792
  <li><p>Schemacop does not yet support string regex matching.</p></li>
579
793
  </ul>
580
794
 
795
+ <h2>Development</h2>
796
+
797
+ <p>To run tests:</p>
798
+
799
+ <ul>
800
+ <li><p>Check out the source</p></li>
801
+ <li><p>Run <code>bundle install</code></p></li>
802
+ <li><p>Run <code>bundle exec rake test</code> to run all tests</p></li>
803
+ <li><p>Run <code>bundle exec rake test TEST=test/unit/some/file.rb</code> to run a single test
804
+ file</p></li>
805
+ </ul>
806
+
581
807
  <h2>Contributors</h2>
582
808
 
583
809
  <p>Thanks to <a href="https://github.com/bbatsov/rubocop">Rubocop</a> for great inspiration
@@ -586,13 +812,13 @@ to <a href="http://www.subgit.com/">SubGit</a> for their great open source licen
586
812
 
587
813
  <h2>Copyright</h2>
588
814
 
589
- <p>Copyright (c) 2017 Sitrox. See <code>LICENSE</code> for further details.</p>
815
+ <p>Copyright (c) 2019 Sitrox. See <code>LICENSE</code> for further details.</p>
590
816
  </div></div>
591
817
 
592
818
  <div id="footer">
593
- Generated on Tue May 16 11:56:24 2017 by
819
+ Generated on Mon Oct 28 16:21:59 2019 by
594
820
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
595
- 0.9.9 (ruby-2.3.1).
821
+ 0.9.20 (ruby-2.6.2).
596
822
  </div>
597
823
 
598
824
  </div>
@@ -2,7 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Documentation by YARD 0.9.9</title>
5
+ <title>Documentation by YARD 0.9.20</title>
6
6
  </head>
7
7
  <script type="text/javascript" charset="utf-8">
8
8
  var match = unescape(window.location.hash).match(/^#!(.+)/);
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  File: README
8
8
 
9
- &mdash; Documentation by YARD 0.9.9
9
+ &mdash; Documentation by YARD 0.9.20
10
10
 
11
11
  </title>
12
12
 
@@ -132,7 +132,7 @@ around at runtime. Those two steps look as follows:</p>
132
132
 
133
133
  <p>At runtime:</p>
134
134
 
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>
135
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_my_schema'>my_schema</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span>
136
136
  <span class='comment'># Your data goes here
137
137
  </span><span class='rparen'>)</span>
138
138
  </code></pre>
@@ -161,7 +161,7 @@ this:</p>
161
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
162
  <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
163
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>
164
+ <span class='id identifier rubyid_req'>req</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>present</span><span class='tstring_end'>&#39;</span></span> <span class='kw'>do</span>
165
165
  <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:boolean</span>
166
166
  <span class='kw'>end</span>
167
167
  <span class='kw'>end</span>
@@ -177,12 +177,38 @@ FalseClass).</p>
177
177
  <h3><code>validate</code> vs <code>validate!</code> vs <code>valid?</code></h3>
178
178
 
179
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>
180
+ validation errors (if any) as well as a deep copy of your data with applied
181
+ defaults and castings, whereas <code>validate!</code> will accumulate all violations
182
+ and finally throw an exception describing them or, if the validation was
183
+ successful, a deep-copy of your supplied data with defaults and castings
184
+ applied.</p>
182
185
 
183
186
  <p>For simply querying the validity of some data, use the methods <code>valid?</code> or
184
187
  <code>invalid?</code>.</p>
185
188
 
189
+ <p>Examples:</p>
190
+
191
+ <pre class="code ruby"><code class="ruby"><span class='comment'># validate! returns your modified data or throws a validation error
192
+ </span><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>
193
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='int'>42</span>
194
+ <span class='kw'>end</span>
195
+ <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='lbrace'>{</span><span class='rbrace'>}</span><span class='rparen'>)</span> <span class='comment'># =&gt; { foo: 42 }
196
+ </span>
197
+ <span class='comment'># validate returns a collector
198
+ </span><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>
199
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='int'>42</span>
200
+ <span class='kw'>end</span>
201
+
202
+ <span class='id identifier rubyid_collector'>collector</span> <span class='op'>=</span> <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate'>validate</span><span class='lparen'>(</span><span class='lbrace'>{</span><span class='rbrace'>}</span><span class='rparen'>)</span>
203
+ <span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_valid?'>valid?</span> <span class='comment'># true
204
+ </span><span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_data'>data</span> <span class='comment'># =&gt; { foo: 42 }
205
+ </span>
206
+ <span class='id identifier rubyid_collector'>collector</span> <span class='op'>=</span> <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate'>validate</span><span class='lparen'>(</span><span class='lbrace'>{</span> <span class='label'>foo:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>invalid</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span><span class='rparen'>)</span>
207
+ <span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_valid?'>valid?</span> <span class='comment'># false
208
+ </span><span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_data'>data</span> <span class='comment'># =&gt; nil
209
+ </span><span class='id identifier rubyid_collector'>collector</span><span class='period'>.</span><span class='id identifier rubyid_exceptions'>exceptions</span> <span class='comment'># =&gt; Validation error
210
+ </span></code></pre>
211
+
186
212
  <h2>Schemacop&#39;s DSL</h2>
187
213
 
188
214
  <p>In this section, we will ignore <a href="#short-forms">short forms</a> and explicitly
@@ -235,7 +261,7 @@ proc returns false.&quot;</p>
235
261
 
236
262
  <p>The corresponding schema would look as follows:</p>
237
263
 
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>
264
+ <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>
239
265
  <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
266
  <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span>
241
267
  <span class='kw'>end</span>
@@ -256,8 +282,8 @@ the type checking, meaning that it only gets executed if the data has the right
256
282
  type and the proc in <code>if</code> (if any) has returned true.</p>
257
283
 
258
284
  <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>
285
+ return true if the data passes the custom check. If it returns false or an error
286
+ message as a string, Schemacop considers the data to be invalid.</p>
261
287
 
262
288
  <p>The following example illustrates the use of the option <code>check</code>: Consider a
263
289
  scenario in which you want the following rule set:</p>
@@ -278,10 +304,19 @@ scenario in which you want the following rule set:</p>
278
304
  <p>The above Type Line has type <code>:string</code> and two options (<code>min</code> and <code>check</code>). The
279
305
  option <code>min</code> is supported by the <code>:string</code> validator (covered later).</p>
280
306
 
307
+ <p>You can also specify a custom error message by returning a string:</p>
308
+
309
+ <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>
310
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</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_i'>i</span><span class='op'>|</span> <span class='id identifier rubyid_i'>i</span><span class='period'>.</span><span class='id identifier rubyid_even?'>even?</span> <span class='op'>?</span> <span class='kw'>true</span> <span class='op'>:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Custom error</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span>
311
+ <span class='kw'>end</span>
312
+ </code></pre>
313
+
314
+ <p>This will include <code>Custom error</code> in the validation error message.</p>
315
+
281
316
  <h3>Field Line</h3>
282
317
 
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>
318
+ <p>Inside a Type Line of type <code>:hash</code>, you may specify an arbitrary number of field
319
+ lines (one for each key-value pair you want to be in the hash).</p>
285
320
 
286
321
  <p>Field Lines start with one of the following six identifiers: <code>req</code>, <code>req?</code>,
287
322
  <code>req!</code>, <code>opt</code>, <code>opt?</code> or <code>opt!</code>:</p>
@@ -327,6 +362,35 @@ non-nil field of type Integer or Date under the key <code>:age</code>.</p>
327
362
  <p>You might find the notation cumbersome, and you&#39;d be right to say so. Luckily
328
363
  there are plenty of short forms available which we will see below.</p>
329
364
 
365
+ <h4>Handling hashes with indifferent access</h4>
366
+
367
+ <p>Schemacop has special handling for objects of the class
368
+ <code>ActiveSupport::HashWithIndifferentAccess</code>: You may specify the keys as symbols
369
+ or strings, and Schemacop will handle the conversion necessary for proper
370
+ validation internally. Note that if you define the same key as string and
371
+ symbol, it will throw a <code>ValidationError</code> <a href="#exceptions">exception</a> when asked to
372
+ validate a hash with indifferent access.</p>
373
+
374
+ <p>Thus, the following two schema definitions are equivalent when validating a hash
375
+ with indifferent access:</p>
376
+
377
+ <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>
378
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
379
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:name</span> <span class='kw'>do</span>
380
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
381
+ <span class='kw'>end</span>
382
+ <span class='kw'>end</span>
383
+ <span class='kw'>end</span>
384
+
385
+ <span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
386
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
387
+ <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>
388
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
389
+ <span class='kw'>end</span>
390
+ <span class='kw'>end</span>
391
+ <span class='kw'>end</span>
392
+ </code></pre>
393
+
330
394
  <h2>Types</h2>
331
395
 
332
396
  <p>Types are defined via their validators, which is a class under <code>validator/</code>.
@@ -357,31 +421,38 @@ Each validator is sourced by <code>schemacop.rb</code>.</p>
357
421
  <li>supported options: <code>min</code>, <code>max</code> (bounds for string length)</li>
358
422
  </ul></li>
359
423
  <li><p><code>:symbol</code> accepts a Ruby Symbol.</p></li>
360
- <li><p><code>:object</code> accepts an arbitrary Ruby object (any object if no option is given).</p>
424
+ <li><p><code>:object</code> accepts an arbitrary Ruby object (any object if no option is given).</p></li>
425
+ </ul>
426
+
427
+ <p>Supported options:</p>
361
428
 
362
429
  <ul>
363
- <li>supported option: <code>classes</code>: Ruby class (or an array of them) that will be
364
- the only recognized filters. Unlike other options, this one affects not the
365
- validation but the type recognition, meaning that you can have multiple Type
366
- Lines with different <code>classes</code> option for the same field, each having its
367
- own validation (e.g. through the option <code>check</code>).</li>
368
- </ul></li>
369
- <li><p><code>:array</code> accepts a Ruby Array.</p>
430
+ <li><p><code>classes</code>: Ruby class (or an array of them) that will be the only recognized
431
+ filters. Unlike other options, this one affects not the validation but the
432
+ type recognition, meaning that you can have multiple Type Lines with
433
+ different <code>classes</code> option for the same field, each having its own
434
+ validation (e.g. through the option <code>check</code>).</p></li>
435
+ <li><p><code>strict</code>: Boolean option, defaults to true. If set to false, the validator
436
+ also allows derived classes of those specified with <code>classes</code>.</p>
370
437
 
371
438
  <ul>
372
- <li>supported options: <code>min</code>, <code>max</code> (bounds for array size) and <code>nil</code>: TODO</li>
373
- <li>accepts a block with an arbitrary number of Type Lines.</li>
374
- <li>TODO no lookahead for different arrays, see
375
- validator_array_test#test_multiple_arrays</li>
439
+ <li><code>:array</code> accepts a Ruby Array.</li>
376
440
  </ul></li>
377
- <li><p><code>:hash</code> accepts a Ruby Hash.</p>
441
+ <li><p>supported options: <code>min</code>, <code>max</code> (bounds for array size) and <code>nil</code>: TODO</p></li>
442
+ <li><p>accepts a block with an arbitrary number of Type Lines.</p></li>
443
+ <li><p>TODO no lookahead for different arrays, see
444
+ validator_array_test#test_multiple_arrays</p>
378
445
 
379
446
  <ul>
380
- <li>accepts a block with an arbitrary number of Field Lines.</li>
447
+ <li><code>:hash</code> accepts a Ruby Hash or an <code>ActiveSupport::HashWithIndifferentAccess</code>.</li>
381
448
  </ul></li>
382
- <li><p><code>:nil</code>: accepts a Ruby NilClass instance. If you want to allow <code>nil</code> as a
449
+ <li><p>accepts a block with an arbitrary number of Field Lines.</p>
450
+
451
+ <ul>
452
+ <li><code>:nil</code>: accepts a Ruby NilClass instance. If you want to allow <code>nil</code> as a
383
453
  value in a field, see above for the usage of the suffixes <code>-!</code> and <code>-?</code> for
384
- Field Lines.</p></li>
454
+ Field Lines.</li>
455
+ </ul></li>
385
456
  </ul>
386
457
 
387
458
  <p>All types support the options <code>if</code> and <code>check</code> (see the section about Type Lines
@@ -495,6 +566,10 @@ write Field Lines in the schema instantiation:</p>
495
566
  <span class='kw'>end</span>
496
567
  </code></pre>
497
568
 
569
+ <p>Note that this does not allow you to specify any options for the hash itself.
570
+ You still need to specify <code>:hash</code> as a type if you want to pass any options to
571
+ the hash (i.e. a <code>default</code>).</p>
572
+
498
573
  <h3>Shortform for subtypes</h3>
499
574
 
500
575
  <p>In case of nested arrays, you can group all Type Lines to a single one.</p>
@@ -550,6 +625,145 @@ of type Array with children of type Array with children of type Hash in which at
550
625
  least one of the Symbol keys <code>:food</code> and <code>:drink</code> (with any non-nil value type)
551
626
  is present.</p>
552
627
 
628
+ <h2>Defaults</h2>
629
+
630
+ <p>Starting from version 2.4.0, Schemacop allows you to define default values at
631
+ any point in your schema. If the validated data contains a nil value, it will be
632
+ substituted by the given default value.</p>
633
+
634
+ <p>Note that Schemacop never modifies the data you pass to it. If you want to
635
+ benefit from Schemacop-applied defaults, you need to access the cloned, modified
636
+ data returned by <code>validate</code> or <code>validate!</code>.</p>
637
+
638
+ <p>Applying defaults is done before validating the substructure and before any type
639
+ casting. The provided default will be validated same as user-supplied data, so
640
+ if your given default does not validate properly, a validation error is thrown.
641
+ Make sure your default values always match the underlying schema.</p>
642
+
643
+ <p>Defaults can be specified at any point:</p>
644
+
645
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Basic usage
646
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
647
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Hello World</span><span class='tstring_end'>&#39;</span></span>
648
+ <span class='kw'>end</span>
649
+
650
+ <span class='comment'># The default given for the first type will match
651
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
652
+ <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Hello World</span><span class='tstring_end'>&#39;</span></span> <span class='comment'># This will always be applied of no value is supplied
653
+ </span> <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='int'>42</span>
654
+ <span class='kw'>end</span>
655
+
656
+ <span class='comment'># You can also pass entire hashes or arrays to your defaults
657
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
658
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='symbol'>:hash</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='lbrace'>{</span> <span class='label'>foo:</span> <span class='symbol'>:bar</span> <span class='rbrace'>}</span> <span class='kw'>do</span>
659
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='symbol'>:symbol</span>
660
+ <span class='kw'>end</span>
661
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:bar</span><span class='comma'>,</span> <span class='symbol'>:array</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>default:</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>
662
+ <span class='kw'>end</span>
663
+
664
+ <span class='comment'># Defaults must match the given schema. The following will fail.
665
+ </span><span class='const'>Schema</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span> <span class='kw'>do</span>
666
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='lbrace'>{</span> <span class='label'>bar:</span> <span class='symbol'>:baz</span> <span class='rbrace'>}</span> <span class='kw'>do</span>
667
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:foo</span>
668
+ <span class='kw'>end</span>
669
+ <span class='kw'>end</span>
670
+ </code></pre>
671
+
672
+ <h3>Required data points</h3>
673
+
674
+ <p>Note that any <em>required</em> validation is done before applying the defaults. If you
675
+ specify a <code>req</code> field, it must always be given, no matter if you have specified
676
+ a default or not. Therefore, specifying <code>req</code> fields do not make sense in
677
+ conjunction with defaults, as the default is always ignored.</p>
678
+
679
+ <h2>Type casting</h2>
680
+
681
+ <p>Starting from version 2.4.0, Schemacop allows you to specify type castings that
682
+ can alter the validated data. Consider the following:</p>
683
+
684
+ <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>
685
+ <span class='id identifier rubyid_req'>req</span> <span class='symbol'>:id</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>cast:</span> <span class='lbracket'>[</span><span class='const'>String</span><span class='rbracket'>]</span>
686
+ <span class='kw'>end</span>
687
+
688
+ <span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='label'>id:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>42</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span>
689
+ <span class='id identifier rubyid_data'>data</span> <span class='comment'># =&gt; { id: 42 }
690
+ </span></code></pre>
691
+
692
+ <p>Note that Schemacop never modifies the data you pass to it. If you want to
693
+ benefit from Schemacop-applied castings, you need to access the cloned, modified
694
+ data returned by <code>validate</code> or <code>validate!</code>.</p>
695
+
696
+ <h3>Specifying type castings</h3>
697
+
698
+ <p>Type castings can be specified using two forms: Either as a hash or as an array.
699
+ While using an array only allows you to specify the supported source types to be
700
+ casted, using a hash allows you to specify custom casting logic as blocks.</p>
701
+
702
+ <p>For hashes, the key must be a class and the value must be either <code>:default</code> for
703
+ using a built-in caster or a callable object (proc or lambda) that receives the
704
+ value and is supposed to cast it. If the value can&#39;t be casted, the proc must
705
+ fail with an exception. The exception message will then be contained in the
706
+ collected validation errors.</p>
707
+
708
+ <p>Example:</p>
709
+
710
+ <pre class="code ruby"><code class="ruby">Schema.new do
711
+ # Pass array to `cast`. This enables casting from String or Float to Integer
712
+ # using the built-in casters.
713
+ req: id_1, :integer, cast: [String, Float]
714
+
715
+ # Pass hash to `cast`. This enables casting from Float to Integer using the
716
+ # built-in caster and from String to Integer using a custom callback.
717
+ req :id_2, :integer, cast: { Float =&gt; :default, String =&gt; proc { |s| Integer(s) }
718
+ end
719
+ </code></pre>
720
+
721
+ <h3>Built-in casters</h3>
722
+
723
+ <p>Schemacop comes with the following casters:</p>
724
+
725
+ <ul>
726
+ <li><code>String</code> to <code>Integer</code> and <code>Float</code></li>
727
+ <li><code>Float</code> to <code>Integer</code></li>
728
+ <li><code>Integer</code> to <code>Float</code></li>
729
+ </ul>
730
+
731
+ <p>Note that all built-in casters are precise, so the string <code>foo</code> will fail with
732
+ an error if casted to an Integer. When casting float values and strings
733
+ containing float values to integers, the decimal places will be discarded
734
+ however.</p>
735
+
736
+ <h3>Execution order</h3>
737
+
738
+ <p>The casting is done <em>before</em> the options <code>if</code> and <code>check</code> are evaluated.
739
+ Example:</p>
740
+
741
+ <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>
742
+ <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_i'>i</span><span class='op'>|</span> <span class='id identifier rubyid_i'>i</span> <span class='op'>==</span> <span class='int'>42</span> <span class='rbrace'>}</span> <span class='comment'># 1
743
+ </span> <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:integer</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_i'>i</span><span class='op'>|</span> <span class='id identifier rubyid_i'>i</span> <span class='op'>&lt;</span> <span class='int'>3</span> <span class='rbrace'>}</span> <span class='comment'># 2
744
+ </span> <span class='id identifier rubyid_type'>type</span> <span class='symbol'>:string</span>
745
+ <span class='kw'>end</span>
746
+
747
+ <span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>42</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='comment'># 1 will match
748
+ </span><span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>2</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='comment'># 2 will match
749
+ </span><span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>234</span><span class='tstring_end'>&#39;</span></span><span class='rparen'>)</span> <span class='comment'># 3 will match
750
+ </span><span class='id identifier rubyid_s'>s</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='int'>5</span><span class='rparen'>)</span> <span class='comment'># Will fail, as nothing matches
751
+ </span></code></pre>
752
+
753
+ <h3>Caveats</h3>
754
+
755
+ <p>Casting only works with type definitions that only include one type. For
756
+ instance, the <code>Numeric</code> validator includes both <code>Integer</code> and <code>Float</code>, which
757
+ would made it unclear what to cast a string into:</p>
758
+
759
+ <pre class="code ruby"><code class="ruby"><span class='comment'># This does not work, as it is unclear whether to cast the String into an
760
+ </span><span class='comment'># Integer or a Float.
761
+ </span><span class='id identifier rubyid_type'>type</span> <span class='symbol'>:number</span><span class='comma'>,</span> <span class='label'>cast:</span> <span class='lbracket'>[</span><span class='const'>String</span><span class='rbracket'>]</span>
762
+ </code></pre>
763
+
764
+ <p>The same also applies to booleans, as they compound both <code>TrueClass</code> and
765
+ <code>FalseClass</code>. This may be tackled in future releases.</p>
766
+
553
767
  <h2>Exceptions</h2>
554
768
 
555
769
  <p>Schemacop will throw one of the following checked exceptions:</p>
@@ -578,6 +792,18 @@ needs to be given only if field <code>b</code> is present).</p></li>
578
792
  <li><p>Schemacop does not yet support string regex matching.</p></li>
579
793
  </ul>
580
794
 
795
+ <h2>Development</h2>
796
+
797
+ <p>To run tests:</p>
798
+
799
+ <ul>
800
+ <li><p>Check out the source</p></li>
801
+ <li><p>Run <code>bundle install</code></p></li>
802
+ <li><p>Run <code>bundle exec rake test</code> to run all tests</p></li>
803
+ <li><p>Run <code>bundle exec rake test TEST=test/unit/some/file.rb</code> to run a single test
804
+ file</p></li>
805
+ </ul>
806
+
581
807
  <h2>Contributors</h2>
582
808
 
583
809
  <p>Thanks to <a href="https://github.com/bbatsov/rubocop">Rubocop</a> for great inspiration
@@ -586,13 +812,13 @@ to <a href="http://www.subgit.com/">SubGit</a> for their great open source licen
586
812
 
587
813
  <h2>Copyright</h2>
588
814
 
589
- <p>Copyright (c) 2017 Sitrox. See <code>LICENSE</code> for further details.</p>
815
+ <p>Copyright (c) 2019 Sitrox. See <code>LICENSE</code> for further details.</p>
590
816
  </div></div>
591
817
 
592
818
  <div id="footer">
593
- Generated on Tue May 16 11:56:24 2017 by
819
+ Generated on Mon Oct 28 16:21:59 2019 by
594
820
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
595
- 0.9.9 (ruby-2.3.1).
821
+ 0.9.20 (ruby-2.6.2).
596
822
  </div>
597
823
 
598
824
  </div>