rkwalify 1.4.0.pre.preview1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +39 -0
  3. data/.gitignore +61 -0
  4. data/.overcommit.yml +33 -0
  5. data/.rubocop.yml +9 -0
  6. data/.rubocop_todo.yml +1369 -0
  7. data/.ruby-version +1 -0
  8. data/Attic/README-0.7.2.md +53 -0
  9. data/Attic/features/cli.feature +9 -0
  10. data/Attic/features/step_definitions/validation_steps.rb +20 -0
  11. data/Attic/features/support/env.rb +4 -0
  12. data/Attic/features/validate_schema.feature +12 -0
  13. data/Attic/s+h +53 -0
  14. data/Attic/setup.rb +1556 -0
  15. data/Attic/spec/my_cli_tool_spec.rb +52 -0
  16. data/Attic/spec/rspec-ex_spec.rb +10 -0
  17. data/Attic/spec/spec_helper.rb +104 -0
  18. data/Attic/test-15.1.rb +28 -0
  19. data/CHANGELOG.md +292 -0
  20. data/CONTRIBUTING.md +23 -0
  21. data/CONTRIBUTORS.md +8 -0
  22. data/Gemfile +16 -0
  23. data/Gemfile.lock +146 -0
  24. data/MIT-LICENSE +21 -0
  25. data/README.md +53 -0
  26. data/ROLL-OUT-STRATEGY.md +77 -0
  27. data/Rakefile +11 -0
  28. data/bin/kwalify.rb +4167 -0
  29. data/bin/kwalify.schema.yaml +59 -0
  30. data/contrib/inline-require +181 -0
  31. data/contrib/kwalify +4167 -0
  32. data/contrib/kwalify-0.7.2 +4160 -0
  33. data/devbin/README.md +22 -0
  34. data/devbin/chk-rad-repo.sh +20 -0
  35. data/devbin/chkcopyrights.sh +42 -0
  36. data/devbin/chkspelling.sh +16 -0
  37. data/devbin/got-all-rel-numbers.sh +5 -0
  38. data/devbin/mkbig-rkwalify.sh +7 -0
  39. data/devbin/mkgem_file.sh +5 -0
  40. data/devbin/runtests.sh +6 -0
  41. data/devbin/ug-tests.golden +242 -0
  42. data/devbin/ug-tests.sh +145 -0
  43. data/devbin/update-rel-numbers.sh +7 -0
  44. data/doc/docstyle.css +188 -0
  45. data/doc/img/fig01.png +0 -0
  46. data/doc/users-guide.html +2051 -0
  47. data/doc-api/classes/CommandOptionError.html +184 -0
  48. data/doc-api/classes/CommandOptionParser.html +325 -0
  49. data/doc-api/classes/Kwalify/AssertionError.html +148 -0
  50. data/doc-api/classes/Kwalify/BaseError.html +297 -0
  51. data/doc-api/classes/Kwalify/BaseParser.html +461 -0
  52. data/doc-api/classes/Kwalify/CommandOptionError.html +168 -0
  53. data/doc-api/classes/Kwalify/ErrorHelper.html +223 -0
  54. data/doc-api/classes/Kwalify/HashInterface.html +118 -0
  55. data/doc-api/classes/Kwalify/Json.html +105 -0
  56. data/doc-api/classes/Kwalify/KwalifyError.html +111 -0
  57. data/doc-api/classes/Kwalify/Main.html +339 -0
  58. data/doc-api/classes/Kwalify/MetaValidator.html +448 -0
  59. data/doc-api/classes/Kwalify/Parser.html +155 -0
  60. data/doc-api/classes/Kwalify/PlainYamlParser/Alias.html +165 -0
  61. data/doc-api/classes/Kwalify/PlainYamlParser.html +523 -0
  62. data/doc-api/classes/Kwalify/Rule.html +433 -0
  63. data/doc-api/classes/Kwalify/SchemaError.html +148 -0
  64. data/doc-api/classes/Kwalify/SyntaxError.html +185 -0
  65. data/doc-api/classes/Kwalify/Types.html +302 -0
  66. data/doc-api/classes/Kwalify/Util/HashLike.html +246 -0
  67. data/doc-api/classes/Kwalify/Util/OrderedHash.html +330 -0
  68. data/doc-api/classes/Kwalify/Util.html +390 -0
  69. data/doc-api/classes/Kwalify/ValidationError.html +148 -0
  70. data/doc-api/classes/Kwalify/Validator.html +381 -0
  71. data/doc-api/classes/Kwalify/Yaml/Parser.html +1538 -0
  72. data/doc-api/classes/Kwalify/Yaml.html +194 -0
  73. data/doc-api/classes/Kwalify/YamlParser.html +542 -0
  74. data/doc-api/classes/Kwalify/YamlSyntaxError.html +119 -0
  75. data/doc-api/classes/Kwalify.html +292 -0
  76. data/doc-api/classes/Test/Unit.html +101 -0
  77. data/doc-api/classes/Test.html +107 -0
  78. data/doc-api/created.rid +1 -0
  79. data/doc-api/files/__/README_txt.html +153 -0
  80. data/doc-api/files/kwalify/errors_rb.html +114 -0
  81. data/doc-api/files/kwalify/main_rb.html +118 -0
  82. data/doc-api/files/kwalify/messages_rb.html +107 -0
  83. data/doc-api/files/kwalify/meta-validator_rb.html +117 -0
  84. data/doc-api/files/kwalify/parser/base_rb.html +116 -0
  85. data/doc-api/files/kwalify/parser/yaml_rb.html +117 -0
  86. data/doc-api/files/kwalify/rule_rb.html +116 -0
  87. data/doc-api/files/kwalify/types_rb.html +114 -0
  88. data/doc-api/files/kwalify/util/assert-text-equal_rb.html +115 -0
  89. data/doc-api/files/kwalify/util/hash-interface_rb.html +114 -0
  90. data/doc-api/files/kwalify/util/hashlike_rb.html +107 -0
  91. data/doc-api/files/kwalify/util/option-parser_rb.html +107 -0
  92. data/doc-api/files/kwalify/util/ordered-hash_rb.html +107 -0
  93. data/doc-api/files/kwalify/util/testcase-helper_rb.html +115 -0
  94. data/doc-api/files/kwalify/util_rb.html +107 -0
  95. data/doc-api/files/kwalify/validator_rb.html +117 -0
  96. data/doc-api/files/kwalify/yaml-parser_rb.html +117 -0
  97. data/doc-api/files/kwalify_rb.html +121 -0
  98. data/doc-api/fr_class_index.html +57 -0
  99. data/doc-api/fr_file_index.html +45 -0
  100. data/doc-api/fr_method_index.html +168 -0
  101. data/doc-api/index.html +24 -0
  102. data/doc-api/rdoc-style.css +208 -0
  103. data/examples/address-book/Makefile +10 -0
  104. data/examples/address-book/address-book.schema.yaml +45 -0
  105. data/examples/address-book/address-book.yaml +36 -0
  106. data/examples/data-binding/BABEL.data.yaml +63 -0
  107. data/examples/data-binding/BABEL.schema.yaml +31 -0
  108. data/examples/data-binding/Makefile +8 -0
  109. data/examples/data-binding/Rakefile +13 -0
  110. data/examples/data-binding/main.rb +25 -0
  111. data/examples/invoice/Makefile +9 -0
  112. data/examples/invoice/invoice.schema.yaml +43 -0
  113. data/examples/invoice/invoice.yaml +32 -0
  114. data/examples/tapkit/Makefile +10 -0
  115. data/examples/tapkit/main.rb +7 -0
  116. data/examples/tapkit/tapkit.schema.yaml +146 -0
  117. data/examples/tapkit/tapkit.yaml +85 -0
  118. data/lib/kwalify/errors.rb +127 -0
  119. data/lib/kwalify/kwalify.schema.yaml +58 -0
  120. data/lib/kwalify/main.rb +442 -0
  121. data/lib/kwalify/messages.rb +173 -0
  122. data/lib/kwalify/meta-validator.rb +276 -0
  123. data/lib/kwalify/parser/base.rb +128 -0
  124. data/lib/kwalify/parser/yaml.rb +841 -0
  125. data/lib/kwalify/rule.rb +562 -0
  126. data/lib/kwalify/templates/genclass-java.eruby +222 -0
  127. data/lib/kwalify/templates/genclass-php.eruby +104 -0
  128. data/lib/kwalify/templates/genclass-ruby.eruby +113 -0
  129. data/lib/kwalify/types.rb +156 -0
  130. data/lib/kwalify/util/assert-text-equal.rb +46 -0
  131. data/lib/kwalify/util/hash-interface.rb +18 -0
  132. data/lib/kwalify/util/hashlike.rb +51 -0
  133. data/lib/kwalify/util/option-parser.rb +220 -0
  134. data/lib/kwalify/util/ordered-hash.rb +57 -0
  135. data/lib/kwalify/util/testcase-helper.rb +112 -0
  136. data/lib/kwalify/util.rb +159 -0
  137. data/lib/kwalify/validator.rb +282 -0
  138. data/lib/kwalify/version.rb +5 -0
  139. data/lib/kwalify/yaml-parser.rb +871 -0
  140. data/lib/kwalify.rb +61 -0
  141. data/rkwalify.gemspec +26 -0
  142. data/test/Rookbook.yaml +15 -0
  143. data/test/data/users-guide/AddressBook.java.expected +40 -0
  144. data/test/data/users-guide/BABEL.data.yaml +24 -0
  145. data/test/data/users-guide/BABEL.schema.yaml +30 -0
  146. data/test/data/users-guide/ExampleAddressBook.java +47 -0
  147. data/test/data/users-guide/Group.java.expected +24 -0
  148. data/test/data/users-guide/Person.java.expected +44 -0
  149. data/test/data/users-guide/address_book.rb +52 -0
  150. data/test/data/users-guide/address_book.schema.yaml +28 -0
  151. data/test/data/users-guide/address_book.yaml +27 -0
  152. data/test/data/users-guide/answers-schema.yaml +12 -0
  153. data/test/data/users-guide/answers-validator.rb +53 -0
  154. data/test/data/users-guide/babel_genclass.result +26 -0
  155. data/test/data/users-guide/config.schema.yaml +7 -0
  156. data/test/data/users-guide/config.yaml +4 -0
  157. data/test/data/users-guide/document01a.yaml +3 -0
  158. data/test/data/users-guide/document01b.yaml +3 -0
  159. data/test/data/users-guide/document02a.yaml +4 -0
  160. data/test/data/users-guide/document02b.yaml +4 -0
  161. data/test/data/users-guide/document03a.yaml +6 -0
  162. data/test/data/users-guide/document03b.yaml +6 -0
  163. data/test/data/users-guide/document04a.yaml +9 -0
  164. data/test/data/users-guide/document04b.yaml +9 -0
  165. data/test/data/users-guide/document05a.yaml +11 -0
  166. data/test/data/users-guide/document05b.yaml +12 -0
  167. data/test/data/users-guide/document06a.yaml +15 -0
  168. data/test/data/users-guide/document06b.yaml +16 -0
  169. data/test/data/users-guide/document07a.yaml +9 -0
  170. data/test/data/users-guide/document07b.yaml +7 -0
  171. data/test/data/users-guide/document12a.json +10 -0
  172. data/test/data/users-guide/document12b.json +6 -0
  173. data/test/data/users-guide/document13a.yaml +17 -0
  174. data/test/data/users-guide/document14a.yaml +3 -0
  175. data/test/data/users-guide/document14b.yaml +3 -0
  176. data/test/data/users-guide/document15a.yaml +6 -0
  177. data/test/data/users-guide/document15b.yaml +5 -0
  178. data/test/data/users-guide/example_address_book.rb +11 -0
  179. data/test/data/users-guide/example_address_book_java.result +32 -0
  180. data/test/data/users-guide/example_address_book_ruby.result +31 -0
  181. data/test/data/users-guide/genclass_java.result +4 -0
  182. data/test/data/users-guide/howto-validation-with-parsing.rb +28 -0
  183. data/test/data/users-guide/howto-validation.rb +25 -0
  184. data/test/data/users-guide/howto3.rb +6 -0
  185. data/test/data/users-guide/howto3.result +5 -0
  186. data/test/data/users-guide/howto3.yaml +8 -0
  187. data/test/data/users-guide/howto5_databinding.result +111 -0
  188. data/test/data/users-guide/invalid01.result +3 -0
  189. data/test/data/users-guide/invalid02.result +5 -0
  190. data/test/data/users-guide/invalid03.result +5 -0
  191. data/test/data/users-guide/invalid04.result +4 -0
  192. data/test/data/users-guide/invalid05.result +11 -0
  193. data/test/data/users-guide/invalid06.result +4 -0
  194. data/test/data/users-guide/invalid07.result +3 -0
  195. data/test/data/users-guide/invalid08.result +3 -0
  196. data/test/data/users-guide/invalid12.json +8 -0
  197. data/test/data/users-guide/invalid14.result +4 -0
  198. data/test/data/users-guide/invalid15.result +4 -0
  199. data/test/data/users-guide/loadbabel.rb +27 -0
  200. data/test/data/users-guide/loadconfig.rb +17 -0
  201. data/test/data/users-guide/loadconfig.result +6 -0
  202. data/test/data/users-guide/models.rb +24 -0
  203. data/test/data/users-guide/option_ha.result +6 -0
  204. data/test/data/users-guide/option_ha_genclass_java.result +7 -0
  205. data/test/data/users-guide/schema01.yaml +3 -0
  206. data/test/data/users-guide/schema02.yaml +12 -0
  207. data/test/data/users-guide/schema03.yaml +9 -0
  208. data/test/data/users-guide/schema04.yaml +20 -0
  209. data/test/data/users-guide/schema05.yaml +29 -0
  210. data/test/data/users-guide/schema06.yaml +11 -0
  211. data/test/data/users-guide/schema12.json +12 -0
  212. data/test/data/users-guide/schema13.yaml +13 -0
  213. data/test/data/users-guide/schema14.yaml +5 -0
  214. data/test/data/users-guide/schema15.yaml +21 -0
  215. data/test/data/users-guide/valid01.result +2 -0
  216. data/test/data/users-guide/valid02.result +2 -0
  217. data/test/data/users-guide/valid03.result +2 -0
  218. data/test/data/users-guide/valid04.result +2 -0
  219. data/test/data/users-guide/valid05.result +2 -0
  220. data/test/data/users-guide/valid06.result +2 -0
  221. data/test/data/users-guide/valid07.result +2 -0
  222. data/test/data/users-guide/valid08.result +2 -0
  223. data/test/data/users-guide/valid12.result +2 -0
  224. data/test/data/users-guide/valid13.result +2 -0
  225. data/test/data/users-guide/valid14.result +2 -0
  226. data/test/data/users-guide/valid15.result +2 -0
  227. data/test/data/users-guide/validate08.rb +37 -0
  228. data/test/test-action.rb +73 -0
  229. data/test/test-action.yaml +738 -0
  230. data/test/test-databinding.rb +84 -0
  231. data/test/test-databinding.yaml +339 -0
  232. data/test/test-main.rb +156 -0
  233. data/test/test-main.yaml +409 -0
  234. data/test/test-metavalidator.rb +80 -0
  235. data/test/test-metavalidator.yaml +1179 -0
  236. data/test/test-parser-yaml.rb +57 -0
  237. data/test/test-parser-yaml.yaml +1750 -0
  238. data/test/test-rule.rb +26 -0
  239. data/test/test-rule.yaml +317 -0
  240. data/test/test-users-guide.rb +82 -0
  241. data/test/test-util.rb +125 -0
  242. data/test/test-validator.rb +95 -0
  243. data/test/test-validator.yaml +986 -0
  244. data/test/test-yaml-parser.rb +47 -0
  245. data/test/test-yaml-parser.yaml +1226 -0
  246. data/test/test.rb +75 -0
  247. metadata +293 -0
@@ -0,0 +1,2051 @@
1
+
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html">
6
+ <title>Kwalify User's Guide (for Ruby)</title>
7
+ <meta name="author" content="makoto kuwata &lt;kwa(at)kuwata-lab.com&gt;">
8
+ <meta name="generator" content="kwaser">
9
+ <meta http-equiv="Content-Style-Type" content="text/css">
10
+ <link rel="stylesheet" href="docstyle.css" type="text/css">
11
+ </head>
12
+ <body>
13
+
14
+ <div class="mainbody">
15
+
16
+ <div align="left"><h1>Kwalify User's Guide (for Ruby)</h1></div>
17
+ <div align="left">
18
+ makoto kuwata &lt;kwa(at)kuwata-lab.com&gt;<br>
19
+ last update: $Date$<br>
20
+ </div>
21
+
22
+ <a name="preface"></a>
23
+ <h2 class="section1">Preface</h2>
24
+ <p>Kwalify<sup>(<a href="#fnref:1" name="fnlink:1">*1</a>)</sup> is a parser, schema validator, and data binding tool for YAML and JSON.
25
+ Kwalify enables you to handle YAML and JSON more easily and strictly.
26
+ </p>
27
+ <p>Topics:
28
+ </p>
29
+ <ul type="disc">
30
+ <li><a href="#schema">Schema validation for YAML</a> and <a href="#tips-json">JSON</a>
31
+ </li>
32
+ <li><a href="#actions">Class definition generation for Ruby, PHP, and Java</a>
33
+ </li>
34
+ <li><a href="#howto-databinding">Data binding</a>
35
+ </li>
36
+ <li><a href="#howto-preceding">Preceding alias</a>
37
+ </li>
38
+ </ul>
39
+ <div class="footnote">
40
+ <dl compact>
41
+ <dt>(<a name="fnref:1" href="#fnlink:1">*1</a>)</dt>
42
+ <dd>Pronounce as 'Qualify'.</dd>
43
+ </dl>
44
+ </div>
45
+ <a name="toc"></a>
46
+ <h3 class="section2">Table of Contents</h3>
47
+ <ul>
48
+ <li><a href="#preface">Preface</a>
49
+ <ul>
50
+ <li><a href="#toc">Table of Contents</a>
51
+ </li>
52
+ </ul>
53
+ </li>
54
+ <li><a href="#schema">Schema Definition</a>
55
+ <ul>
56
+ <li><a href="#schema-seq">Sequence</a>
57
+ </li>
58
+ <li><a href="#schema-map">Mapping</a>
59
+ </li>
60
+ <li><a href="#schema-seq-of-map">Sequence of Mapping</a>
61
+ </li>
62
+ <li><a href="#schema-map-of-seq">Mapping of Sequence</a>
63
+ </li>
64
+ <li><a href="#schema-rules">Rule and Constraint</a>
65
+ </li>
66
+ <li><a href="#schema-unique">Unique constraint</a>
67
+ </li>
68
+ </ul>
69
+ </li>
70
+ <li><a href="#tips">Tips</a>
71
+ <ul>
72
+ <li><a href="#tips-json">JSON</a>
73
+ </li>
74
+ <li><a href="#tips-anchor">Anchor and Alias</a>
75
+ </li>
76
+ <li><a href="#tips-default">Default of Mapping</a>
77
+ </li>
78
+ <li><a href="#tips-merge">Merging Mappings</a>
79
+ </li>
80
+ </ul>
81
+ </li>
82
+ <li><a href="#howto">How to in Ruby</a>
83
+ <ul>
84
+ <li><a href="#howot-validate">Validation</a>
85
+ </li>
86
+ <li><a href="#howto-parse">Parsing with Validation</a>
87
+ </li>
88
+ <li><a href="#howto-meta">Meta Validation</a>
89
+ </li>
90
+ <li><a href="#howto-hook">Validator#validator_hook()</a>
91
+ </li>
92
+ <li><a href="#howto-preceding">Preceding Alias</a>
93
+ </li>
94
+ <li><a href="#howto-databinding">Data Binding</a>
95
+ </li>
96
+ </ul>
97
+ </li>
98
+ <li><a href="#actions">Actions</a>
99
+ <ul>
100
+ <li><a href="#action-genclass">Class Definition Generation</a>
101
+ <ul>
102
+ <li><a href="#action-genclass-ruby">Ruby Class Definition</a>
103
+ </li>
104
+ <li><a href="#action-genclass-java">Java Class Definition</a>
105
+ </li>
106
+ </ul>
107
+ </li>
108
+ </ul>
109
+ </li>
110
+ <li><a href="#ref">References</a>
111
+ <ul>
112
+ <li><a href="#ref-usage">Usage in Command-Line</a>
113
+ </li>
114
+ </ul>
115
+ </li>
116
+ </ul>
117
+ <br>
118
+
119
+
120
+ <br>
121
+
122
+
123
+ <a name="schema"></a>
124
+ <h2 class="section1">Schema Definition</h2>
125
+ <p>This section describes how to define schema definition of YAML.
126
+ </p>
127
+ <a name="schema-seq"></a>
128
+ <h3 class="section2">Sequence</h3>
129
+ <a name="schema01.yaml"></a>
130
+ <div class="program_caption">
131
+ <code>schema01.yaml</code> : sequence of string</div>
132
+ <pre class="program">type: seq
133
+ sequence:
134
+ - type: str
135
+ </pre>
136
+ <a name="document01a.yaml"></a>
137
+ <div class="program_caption">
138
+ <code>document01a.yaml</code> : valid document example</div>
139
+ <pre class="program">- foo
140
+ - bar
141
+ - baz
142
+ </pre>
143
+ <a name="valid01.result"></a>
144
+ <div class="terminal_caption">
145
+ validate</div>
146
+ <pre class="terminal">$ kwalify -lf schema01.yaml document01a.yaml
147
+ document01a.yaml#0: valid.
148
+ </pre>
149
+ <a name="document01b.yaml"></a>
150
+ <div class="program_caption">
151
+ <code>document01b.yaml</code> : invalid document example</div>
152
+ <pre class="program">- foo
153
+ - 123
154
+ - baz
155
+ </pre>
156
+ <a name="invalid01.result"></a>
157
+ <div class="terminal_caption">
158
+ validate</div>
159
+ <pre class="terminal">$ kwalify -lf schema01.yaml document01b.yaml
160
+ document01b.yaml#0: INVALID
161
+ - (line 2) [/1] '123': not a string.
162
+ </pre>
163
+ <p>Default '<code>type:</code>' is <code>str</code> so you can omit '<code>type: str</code>'.
164
+ </p>
165
+ <br>
166
+
167
+
168
+ <a name="schema-map"></a>
169
+ <h3 class="section2">Mapping</h3>
170
+ <a name="schema02.yaml"></a>
171
+ <div class="program_caption">
172
+ <code>schema02.yaml</code> : mapping of scalar</div>
173
+ <pre class="program">type: map
174
+ mapping:
175
+ "name":
176
+ type: str
177
+ required: yes
178
+ "email":
179
+ type: str
180
+ pattern: /@/
181
+ "age":
182
+ type: int
183
+ "birth":
184
+ type: date
185
+ </pre>
186
+ <a name="document02a.yaml"></a>
187
+ <div class="program_caption">
188
+ <code>document02a.yaml</code> : valid document example</div>
189
+ <pre class="program">name: foo
190
+ email: foo@mail.com
191
+ age: 20
192
+ birth: 1985-01-01
193
+ </pre>
194
+ <a name="valid02.result"></a>
195
+ <div class="terminal_caption">
196
+ validate</div>
197
+ <pre class="terminal">$ kwalify -lf schema02.yaml document02a.yaml
198
+ document02a.yaml#0: valid.
199
+ </pre>
200
+ <a name="document02b.yaml"></a>
201
+ <div class="program_caption">
202
+ <code>document02b.yaml</code> : invalid document example</div>
203
+ <pre class="program">name: foo
204
+ email: foo(at)mail.com
205
+ age: twenty
206
+ birth: Jun 01, 1985
207
+ </pre>
208
+ <a name="invalid02.result"></a>
209
+ <div class="terminal_caption">
210
+ validate</div>
211
+ <pre class="terminal">$ kwalify -lf schema02.yaml document02b.yaml
212
+ document02b.yaml#0: INVALID
213
+ - (line 2) [/email] 'foo(at)mail.com': not matched to pattern /@/.
214
+ - (line 3) [/age] 'twenty': not a integer.
215
+ - (line 4) [/birth] 'Jun 01, 1985': not a date.
216
+ </pre>
217
+ <br>
218
+
219
+
220
+ <a name="schema-seq-of-map"></a>
221
+ <h3 class="section2">Sequence of Mapping</h3>
222
+ <a name="schema03.yaml"></a>
223
+ <div class="program_caption">
224
+ <code>schema03.yaml</code> : sequence of mapping</div>
225
+ <pre class="program">type: seq
226
+ sequence:
227
+ - type: map
228
+ mapping:
229
+ "name":
230
+ type: str
231
+ required: true
232
+ "email":
233
+ type: str
234
+ </pre>
235
+ <a name="document03a.yaml"></a>
236
+ <div class="program_caption">
237
+ <code>document03a.yaml</code> : valid document example</div>
238
+ <pre class="program">- name: foo
239
+ email: foo@mail.com
240
+ - name: bar
241
+ email: bar@mail.net
242
+ - name: baz
243
+ email: baz@mail.org
244
+ </pre>
245
+ <a name="valid03.result"></a>
246
+ <div class="terminal_caption">
247
+ validate</div>
248
+ <pre class="terminal">$ kwalify -lf schema03.yaml document03a.yaml
249
+ document03a.yaml#0: valid.
250
+ </pre>
251
+ <a name="document03b.yaml"></a>
252
+ <div class="program_caption">
253
+ <code>document03b.yaml</code> : invalid document example</div>
254
+ <pre class="program">- name: foo
255
+ email: foo@mail.com
256
+ - naem: bar
257
+ email: bar@mail.net
258
+ - name: baz
259
+ mail: baz@mail.org
260
+ </pre>
261
+ <a name="invalid03.result"></a>
262
+ <div class="terminal_caption">
263
+ validate</div>
264
+ <pre class="terminal">$ kwalify -lf schema03.yaml document03b.yaml
265
+ document03b.yaml#0: INVALID
266
+ - (line 3) [/1] key 'name:' is required.
267
+ - (line 3) [/1/naem] key 'naem:' is undefined.
268
+ - (line 6) [/2/mail] key 'mail:' is undefined.
269
+ </pre>
270
+ <br>
271
+
272
+
273
+ <a name="schema-map-of-seq"></a>
274
+ <h3 class="section2">Mapping of Sequence</h3>
275
+ <a name="schema04.yaml"></a>
276
+ <div class="program_caption">
277
+ <code>schema04.yaml</code> : mapping of sequence of mapping</div>
278
+ <pre class="program">type: map
279
+ mapping:
280
+ "company":
281
+ type: str
282
+ required: yes
283
+ "email":
284
+ type: str
285
+ "employees":
286
+ type: seq
287
+ sequence:
288
+ - type: map
289
+ mapping:
290
+ "code":
291
+ type: int
292
+ required: yes
293
+ "name":
294
+ type: str
295
+ required: yes
296
+ "email":
297
+ type: str
298
+ </pre>
299
+ <a name="document04a.yaml"></a>
300
+ <div class="program_caption">
301
+ <code>document04a.yaml</code> : valid document example</div>
302
+ <pre class="program">company: Kuwata lab.
303
+ email: webmaster@kuwata-lab.com
304
+ employees:
305
+ - code: 101
306
+ name: foo
307
+ email: foo@kuwata-lab.com
308
+ - code: 102
309
+ name: bar
310
+ email: bar@kuwata-lab.com
311
+ </pre>
312
+ <a name="valid04.result"></a>
313
+ <div class="terminal_caption">
314
+ validate</div>
315
+ <pre class="terminal">$ kwalify -lf schema04.yaml document04a.yaml
316
+ document04a.yaml#0: valid.
317
+ </pre>
318
+ <a name="document04b.yaml"></a>
319
+ <div class="program_caption">
320
+ <code>document04b.yaml</code> : invalid document example</div>
321
+ <pre class="program">company: Kuwata Lab.
322
+ email: webmaster@kuwata-lab.com
323
+ employees:
324
+ - code: A101
325
+ name: foo
326
+ email: foo@kuwata-lab.com
327
+ - code: 102
328
+ name: bar
329
+ mail: bar@kuwata-lab.com
330
+ </pre>
331
+ <a name="invalid04.result"></a>
332
+ <div class="terminal_caption">
333
+ validate</div>
334
+ <pre class="terminal">$ kwalify -lf schema04.yaml document04b.yaml
335
+ document04b.yaml#0: INVALID
336
+ - (line 4) [/employees/0/code] 'A101': not a integer.
337
+ - (line 9) [/employees/1/mail] key 'mail:' is undefined.
338
+ </pre>
339
+ <br>
340
+
341
+
342
+ <a name="schema-rules"></a>
343
+ <h3 class="section2">Rule and Constraint</h3>
344
+ <p><code>type:</code>, <code>required:</code>, <code>length</code>, ... are called <strong>constraint</strong> and set of constraints are called <strong>rule</strong>.
345
+ </p>
346
+ <ul type="disc">
347
+ <li>Rule contains 'type:' constraint. If 'type:' is omitted, 'type: str' is used as default.
348
+ </li>
349
+ <li>'sequence:' constraint takes a sequence of rule (the sequence can contain only a rule).
350
+ </li>
351
+ <li>'mapping:' constraint takes a mapping which values are rules.
352
+ </li>
353
+ </ul>
354
+ <div style="align:center;">
355
+ <img src="img/fig01.png" alt="constraints and rules of schema definition." />
356
+ </div>
357
+ <p>The following is a list of constraints.
358
+ </p>
359
+ <dl class="dl3">
360
+ <dt class="dt3"><strong>
361
+ <code>required:</code> </strong></dt>
362
+ <dd class="dd3">
363
+ Value is required when true (default is false).
364
+ This is similar to not-null constraint in RDBMS.
365
+ </dd>
366
+ <dt class="dt3"><strong>
367
+ <code>enum:</code> </strong></dt>
368
+ <dd class="dd3">
369
+ List of available values.
370
+ </dd>
371
+ <dt class="dt3"><strong>
372
+ <code>pattern:</code> </strong></dt>
373
+ <dd class="dd3">
374
+ Specifies regular expression pattern of value.
375
+ </dd>
376
+ <dt class="dt3"><strong>
377
+ <code>type:</code> </strong></dt>
378
+ <dd class="dd3">
379
+ Type of value. The followings are available:
380
+ <ul type="circle">
381
+ <li><code>str</code>
382
+ </li>
383
+ <li><code>int</code>
384
+ </li>
385
+ <li><code>float</code>
386
+ </li>
387
+ <li><code>number</code> (== int or float)
388
+ </li>
389
+ <li><code>text</code> (== str or number)
390
+ </li>
391
+ <li><code>bool</code>
392
+ </li>
393
+ <li><code>date</code>
394
+ </li>
395
+ <li><code>time</code>
396
+ </li>
397
+ <li><code>timestamp</code>
398
+ </li>
399
+ <li><code>seq</code>
400
+ </li>
401
+ <li><code>map</code>
402
+ </li>
403
+ <li><code>scalar</code> (all but seq and map)
404
+ </li>
405
+ <li><code>any</code> (means any data)
406
+ </li>
407
+ </ul>
408
+ </dd>
409
+ <dt class="dt3"><strong>
410
+ <code>range:</code> </strong></dt>
411
+ <dd class="dd3">
412
+ Range of value between max/max-ex and min/min-ex.
413
+ <ul type="circle">
414
+ <li>'max' means 'max-inclusive'.
415
+ </li>
416
+ <li>'min' means 'min-inclusive'.
417
+ </li>
418
+ <li>'max-ex' means 'max-exclusive'.
419
+ </li>
420
+ <li>'min-ex' means 'min-exclusive'.
421
+ </li>
422
+ </ul>
423
+ Type <code>seq</code>, <code>map</code>, <code>bool</code> and <code>any</code> are not available with <code>range:</code>.
424
+ </dd>
425
+ <dt class="dt3"><strong>
426
+ <code>length:</code> </strong></dt>
427
+ <dd class="dd3">
428
+ Range of length of value between max/max-ex and min/min-ex.
429
+ Only type <code>str</code> and <code>text</code> are available with <code>length:</code>.
430
+ </dd>
431
+ <dt class="dt3"><strong>
432
+ <code>assert:</code> </strong></dt>
433
+ <dd class="dd3">
434
+ String which represents validation expression.
435
+ String should contain variable name <code>val</code> which represents value.
436
+ (This is an experimental function and not supported in Kwartz-java).
437
+ </dd>
438
+ <dt class="dt3"><strong>
439
+ <code>unique:</code> </strong></dt>
440
+ <dd class="dd3">
441
+ Value is unique for mapping or sequence.
442
+ This is similar to unique constraint of RDBMS.
443
+ See the next subsection for detail.
444
+ </dd>
445
+ <dt class="dt3"><strong>
446
+ <code>name:</code> </strong></dt>
447
+ <dd class="dd3">
448
+ Name of schema.
449
+ </dd>
450
+ <dt class="dt3"><strong>
451
+ <code>desc:</code> </strong></dt>
452
+ <dd class="dd3">
453
+ Description. This is not used for validation.
454
+ </dd>
455
+ <dt class="dt3"><strong>
456
+ <code>class:</code> </strong></dt>
457
+ <dd class="dd3">
458
+ Class name. This is for data-binding and is available only with type 'map'.
459
+ This is also used in 'genclass' action.
460
+ </dd>
461
+ <dt class="dt3"><strong>
462
+ <code>default:</code> </strong></dt>
463
+ <dd class="dd3">
464
+ Default value.
465
+ This is only for 'genclass' action, and have no effect to validation and parsing.
466
+ Default value should be scalar and it is not available if <code>type:</code> is <code>map</code> or <code>seq</code>, and also not available when <code>required:</code> is true.
467
+ </dd>
468
+ </dl>
469
+ <a name="schema05.yaml"></a>
470
+ <div class="program_caption">
471
+ <code>schema05.yaml</code> : rule examples</div>
472
+ <pre class="program">type: seq
473
+ sequence:
474
+ -
475
+ type: map
476
+ mapping:
477
+ "name":
478
+ type: str
479
+ required: yes
480
+ "email":
481
+ type: str
482
+ required: yes
483
+ pattern: /@/
484
+ "password":
485
+ type: text
486
+ length: { max: 16, min: 8 }
487
+ "age":
488
+ type: int
489
+ range: { max: 30, min: 18 }
490
+ # or assert: 18 &lt;= val &amp;&amp; val &lt;= 30
491
+ "blood":
492
+ type: str
493
+ enum: [A, B, O, AB]
494
+ "birth":
495
+ type: date
496
+ "memo":
497
+ type: any
498
+ "deleted":
499
+ type: bool
500
+ default: false
501
+ </pre>
502
+ <a name="document05a.yaml"></a>
503
+ <div class="program_caption">
504
+ <code>document05a.yaml</code> : valid document example</div>
505
+ <pre class="program">- name: foo
506
+ email: foo@mail.com
507
+ password: xxx123456
508
+ age: 20
509
+ blood: A
510
+ birth: 1985-01-01
511
+ - name: bar
512
+ email: bar@mail.net
513
+ age: 25
514
+ blood: AB
515
+ birth: 1980-01-01
516
+ </pre>
517
+ <a name="valid05.result"></a>
518
+ <div class="terminal_caption">
519
+ validate</div>
520
+ <pre class="terminal">$ kwalify -lf schema05.yaml document05a.yaml
521
+ document05a.yaml#0: valid.
522
+ </pre>
523
+ <a name="document05b.yaml"></a>
524
+ <div class="program_caption">
525
+ <code>document05b.yaml</code> : invalid document example</div>
526
+ <pre class="program">- name: foo
527
+ email: foo(at)mail.com
528
+ password: xxx123
529
+ age: twenty
530
+ blood: a
531
+ birth: 1985-01-01
532
+ - given-name: bar
533
+ family-name: Bar
534
+ email: bar@mail.net
535
+ age: 15
536
+ blood: AB
537
+ birth: 1980/01/01
538
+ </pre>
539
+ <a name="invalid05.result"></a>
540
+ <div class="terminal_caption">
541
+ validate</div>
542
+ <pre class="terminal">$ kwalify -lf schema05.yaml document05b.yaml
543
+ document05b.yaml#0: INVALID
544
+ - (line 2) [/0/email] 'foo(at)mail.com': not matched to pattern /@/.
545
+ - (line 3) [/0/password] 'xxx123': too short (length 6 &lt; min 8).
546
+ - (line 4) [/0/age] 'twenty': not a integer.
547
+ - (line 5) [/0/blood] 'a': invalid blood value.
548
+ - (line 7) [/1] key 'name:' is required.
549
+ - (line 7) [/1/given-name] key 'given-name:' is undefined.
550
+ - (line 8) [/1/family-name] key 'family-name:' is undefined.
551
+ - (line 10) [/1/age] '15': too small (&lt; min 18).
552
+ - (line 12) [/1/birth] '1980/01/01': not a date.
553
+ </pre>
554
+ <br>
555
+
556
+
557
+ <a name="schema-unique"></a>
558
+ <h3 class="section2">Unique constraint</h3>
559
+ <p>'<code>unique:</code>' constraint is available with elements of sequence or mapping.
560
+ This is equivalent to unique constraint of RDBMS.
561
+ </p>
562
+ <ul type="disc">
563
+ <li>Type of rule which has '<code>unique:</code>' entry must be scalar (str, int, float, ...).
564
+ </li>
565
+ <li>Type of parent rule must be sequence or mapping.
566
+ </li>
567
+ </ul>
568
+ <a name="schema06.yaml"></a>
569
+ <div class="program_caption">
570
+ <code>schema06.yaml</code> : unique constraint entry with mapping and sequence</div>
571
+ <pre class="program">type: seq
572
+ sequence:
573
+ - type: map
574
+ required: yes
575
+ mapping:
576
+ "name": { type: str, required: yes, <strong>unique: yes</strong> }
577
+ "email": { type: str }
578
+ "groups":
579
+ type: seq
580
+ sequence:
581
+ - { type: str, <strong>unique: yes</strong> }
582
+ </pre>
583
+ <a name="document06a.yaml"></a>
584
+ <div class="program_caption">
585
+ <code>document06a.yaml</code> : valid document example</div>
586
+ <pre class="program">- name: foo
587
+ email: admin@mail.com
588
+ groups:
589
+ - users
590
+ - foo
591
+ - admin
592
+ - name: bar
593
+ email: admin@mail.com
594
+ groups:
595
+ - users
596
+ - admin
597
+ - name: baz
598
+ email: baz@mail.com
599
+ groups:
600
+ - users
601
+ </pre>
602
+ <a name="valid06.result"></a>
603
+ <div class="terminal_caption">
604
+ validate</div>
605
+ <pre class="terminal">$ kwalify -lf schema06.yaml document06a.yaml
606
+ document06a.yaml#0: valid.
607
+ </pre>
608
+ <a name="document06b.yaml"></a>
609
+ <div class="program_caption">
610
+ <code>document06b.yaml</code> : invalid document example</div>
611
+ <pre class="program">- name: foo
612
+ email: admin@mail.com
613
+ groups:
614
+ - foo
615
+ - users
616
+ - admin
617
+ - foo
618
+ - name: bar
619
+ email: admin@mail.com
620
+ groups:
621
+ - admin
622
+ - users
623
+ - name: bar
624
+ email: baz@mail.com
625
+ groups:
626
+ - users
627
+ </pre>
628
+ <a name="invalid06.result"></a>
629
+ <div class="terminal_caption">
630
+ validate</div>
631
+ <pre class="terminal">$ kwalify -lf schema06.yaml document06b.yaml
632
+ document06b.yaml#0: INVALID
633
+ - (line 7) [/0/groups/3] 'foo': is already used at '/0/groups/0'.
634
+ - (line 13) [/2/name] 'bar': is already used at '/1/name'.
635
+ </pre>
636
+ <br>
637
+
638
+
639
+ <br>
640
+
641
+
642
+ <a name="tips"></a>
643
+ <h2 class="section1">Tips</h2>
644
+ <a name="tips-json"></a>
645
+ <h3 class="section2">JSON</h3>
646
+ <p><a href="http://www.json.org">JSON</a> is a lightweight data-interchange format, especially useful for JavaScript.
647
+ JSON can be considered as a subset of YAML. It means that YAML parser can parse JSON and Kwalify can validate JSON document.
648
+ </p>
649
+ <a name="schema12.json"></a>
650
+ <div class="program_caption">
651
+ <code>schema12.json</code> : an example schema definition written in JSON format</div>
652
+ <pre class="program">{ "type": "map",
653
+ "required": true,
654
+ "mapping": {
655
+ "name": { "type": "str", "required": true },
656
+ "email": { "type": "str" },
657
+ "age": { "type": "int" },
658
+ "gender": { "type": "str", "enum": ["M", "F"] },
659
+ "favorite": { "type": "seq",
660
+ "sequence": [ { "type": "str" } ]
661
+ }
662
+ }
663
+ }
664
+ </pre>
665
+ <a name="document12a.json"></a>
666
+ <div class="program_caption">
667
+ <code>document12a.json</code> : valid JSON document example</div>
668
+ <pre class="program">{ "name": "Foo",
669
+ "email": "foo@mail.com",
670
+ "age": 20,
671
+ "gender": "F",
672
+ "favorite": [
673
+ "football",
674
+ "basketball",
675
+ "baseball"
676
+ ]
677
+ }
678
+ </pre>
679
+ <a name="valid12.result"></a>
680
+ <div class="terminal_caption">
681
+ validate</div>
682
+ <pre class="terminal">$ kwalify -lf schema12.json document12a.json
683
+ document12a.json#0: valid.
684
+ </pre>
685
+ <a name="document12b.json"></a>
686
+ <div class="program_caption">
687
+ <code>document12b.json</code> : invalid JSON document example</div>
688
+ <pre class="program">{
689
+ "mail": "foo@mail.com",
690
+ "age": twenty,
691
+ "gender": "X",
692
+ "favorite": [ 123, 456 ]
693
+ }
694
+ </pre>
695
+ <a name="invalid12.json"></a>
696
+ <div class="terminal_caption">
697
+ validate</div>
698
+ <pre class="terminal">$ kwalify -lf schema12.json document12b.json
699
+ document12b.json#0: INVALID
700
+ - (line 1) [/] key 'name:' is required.
701
+ - (line 2) [/mail] key 'mail:' is undefined.
702
+ - (line 3) [/age] 'twenty': not a integer.
703
+ - (line 4) [/gender] 'X': invalid gender value.
704
+ - (line 5) [/favorite/0] '123': not a string.
705
+ - (line 5) [/favorite/1] '456': not a string.
706
+ </pre>
707
+ <br>
708
+
709
+
710
+ <a name="tips-anchor"></a>
711
+ <h3 class="section2">Anchor and Alias</h3>
712
+ <p>You can share rules by YAML anchor and alias.
713
+ </p>
714
+ <a name="schema13.yaml"></a>
715
+ <div class="program_caption">
716
+ <code>schema13.yaml</code> : anchor example</div>
717
+ <pre class="program">type: seq
718
+ sequence:
719
+ - <strong>&amp;employee</strong>
720
+ type: map
721
+ mapping:
722
+ "given-name": <strong>&amp;name</strong>
723
+ type: str
724
+ required: yes
725
+ "family-name": <strong>*name</strong>
726
+ "post":
727
+ type: str
728
+ enum: [executive, manager, clerk]
729
+ "supervisor": <strong>*employee</strong>
730
+ </pre>
731
+ <p>Anchor and alias is also available in YAML document.
732
+ </p>
733
+ <a name="document13a.yaml"></a>
734
+ <div class="program_caption">
735
+ <code>document13a.yaml</code> : valid document example</div>
736
+ <pre class="program">- <strong>&amp;foo</strong>
737
+ given-name: foo
738
+ family-name: Foo
739
+ post: executive
740
+ - <strong>&amp;bar</strong>
741
+ given-name: bar
742
+ family-name: Bar
743
+ post: manager
744
+ supervisor: <strong>*foo</strong>
745
+ - given-name: baz
746
+ family-name: Baz
747
+ post: clerk
748
+ supervisor: <strong>*bar</strong>
749
+ - given-name: zak
750
+ family-name: Zak
751
+ post: clerk
752
+ supervisor: <strong>*bar</strong>
753
+ </pre>
754
+ <a name="valid13.result"></a>
755
+ <div class="terminal_caption">
756
+ validate</div>
757
+ <pre class="terminal">$ kwalify -lf schema13.yaml document13a.yaml
758
+ document13a.yaml#0: valid.
759
+ </pre>
760
+ <br>
761
+
762
+
763
+ <a name="tips-default"></a>
764
+ <h3 class="section2">Default of Mapping</h3>
765
+ <p>YAML allows user to specify default value of mapping.
766
+ </p>
767
+ <p>For example, the following YAML document uses default value of mapping.
768
+ </p>
769
+ <pre class="program">A: 10
770
+ B: 20
771
+ <strong>=: -1</strong> # default value
772
+ </pre>
773
+ <p>This is equal to the following Ruby code.
774
+ </p>
775
+ <pre class="program">map = ["A"=&gt;10, "B"=&gt;20]
776
+ map.default = -1
777
+ map
778
+ </pre>
779
+ <p>Kwalify allows user to specify default rule using default value of mapping.
780
+ It is useful when key names are unknown.
781
+ </p>
782
+ <a name="schema14.yaml"></a>
783
+ <div class="program_caption">
784
+ <code>schema14.yaml</code> : default rule example</div>
785
+ <pre class="program">type: map
786
+ mapping:
787
+ <strong>=:</strong> # default rule
788
+ type: number
789
+ range: { max: 1, min: -1 }
790
+ </pre>
791
+ <a name="document14a.yaml"></a>
792
+ <div class="program_caption">
793
+ <code>document14a.yaml</code> : valid document example</div>
794
+ <pre class="program">value1: 0
795
+ value2: 0.5
796
+ value3: -0.9
797
+ </pre>
798
+ <a name="valid14.result"></a>
799
+ <div class="terminal_caption">
800
+ validate</div>
801
+ <pre class="terminal">$ kwalify -lf schema14.yaml document14a.yaml
802
+ document14a.yaml#0: valid.
803
+ </pre>
804
+ <a name="document14b.yaml"></a>
805
+ <div class="program_caption">
806
+ <code>document14b.yaml</code> : invalid document example</div>
807
+ <pre class="program">value1: 0
808
+ value2: 1.1
809
+ value3: -2.0
810
+ </pre>
811
+ <a name="invalid14.result"></a>
812
+ <div class="terminal_caption">
813
+ validate</div>
814
+ <pre class="terminal">$ kwalify -lf schema14.yaml document14b.yaml
815
+ document14b.yaml#0: INVALID
816
+ - (line 2) [/value2] '1.1': too large (&gt; max 1).
817
+ - (line 3) [/value3] '-2.0': too small (&lt; min -1).
818
+ </pre>
819
+ <br>
820
+
821
+
822
+ <a name="tips-merge"></a>
823
+ <h3 class="section2">Merging Mappings</h3>
824
+ <p>YAML allows user to merge mappings.
825
+ </p>
826
+ <pre class="program">- <strong>&amp;a1</strong>
827
+ A: 10
828
+ B: 20
829
+ - <strong>&lt;&lt;: *a1</strong> # merge
830
+ A: 15 # override
831
+ C: 30 # add
832
+ </pre>
833
+ <p>This is equal to the following Ruby code.
834
+ </p>
835
+ <pre class="program">a1 = {"A"=&gt;10, "B"=&gt;20}
836
+ tmp = {}
837
+ tmp.update(a1) # merge
838
+ tmp["A"] = 15 # override
839
+ tmp["C"] = 30 # add
840
+ </pre>
841
+ <p>This feature allows Kwalify to merge rule entries.
842
+ </p>
843
+ <a name="schema15.yaml"></a>
844
+ <div class="program_caption">
845
+ <code>schema15.yaml</code> : merging rule entries example</div>
846
+ <pre class="program">type: map
847
+ mapping:
848
+ "group":
849
+ type: map
850
+ mapping:
851
+ "name": <strong>&amp;name</strong>
852
+ type: str
853
+ required: yes
854
+ "email": <strong>&amp;email</strong>
855
+ type: str
856
+ pattern: /@/
857
+ required: no
858
+ "user":
859
+ type: map
860
+ mapping:
861
+ "name":
862
+ <strong>&lt;&lt;: *name</strong> # merge
863
+ <strong>length: { max: 16 }</strong> # add
864
+ "email":
865
+ <strong>&lt;&lt;: *email</strong> # merge
866
+ <strong>required: yes</strong> # override
867
+ </pre>
868
+ <a name="document15a.yaml"></a>
869
+ <div class="program_caption">
870
+ <code>document15a.yaml</code> : valid document example</div>
871
+ <pre class="program">group:
872
+ name: foo
873
+ email: foo@mail.com
874
+ user:
875
+ name: bar
876
+ email: bar@mail.com
877
+ </pre>
878
+ <a name="valid15.result"></a>
879
+ <div class="terminal_caption">
880
+ validate</div>
881
+ <pre class="terminal">$ kwalify -lf schema15.yaml document15a.yaml
882
+ document15a.yaml#0: valid.
883
+ </pre>
884
+ <a name="document15b.yaml"></a>
885
+ <div class="program_caption">
886
+ <code>document15b.yaml</code> : invalid document example</div>
887
+ <pre class="program">group:
888
+ name: foo
889
+ email: foo@mail.com
890
+ user:
891
+ name: toooooo-looooong-name
892
+ </pre>
893
+ <a name="invalid15.result"></a>
894
+ <div class="terminal_caption">
895
+ validate</div>
896
+ <pre class="terminal">$ kwalify -lf schema15.yaml document15b.yaml
897
+ document15b.yaml#0: INVALID
898
+ - (line 5) [/user] key 'email:' is required.
899
+ - (line 5) [/user/name] 'toooooo-looooong-name': too long (length 21 &gt; max 16).
900
+ </pre>
901
+ <br>
902
+
903
+
904
+ <br>
905
+
906
+
907
+ <a name="howto"></a>
908
+ <h2 class="section1">How to in Ruby</h2>
909
+ <p>This section describes how to use Kwalify in Ruby.
910
+ </p>
911
+ <a name="howot-validate"></a>
912
+ <h3 class="section2">Validation</h3>
913
+ <a name="howto-validation.rb"></a>
914
+ <pre class="program">require 'kwalify'
915
+ #require 'yaml'
916
+
917
+ ## load schema data
918
+ schema = Kwalify::Yaml.load_file('kwalify.schema.yaml')
919
+ ## or
920
+ #schema = YAML.load_file('kwalify.schema.yaml')
921
+
922
+ ## create validator
923
+ validator = Kwalify::Validator.new(schema)
924
+
925
+ ## load document
926
+ document = Kwalify::Yaml.load_file('document.yaml')
927
+ ## or
928
+ #document = YAML.load_file('document.yaml')
929
+
930
+ ## validate
931
+ errors = validator.validate(document)
932
+
933
+ ## show errors
934
+ if errors &amp;&amp; !errors.empty?
935
+ for e in errors
936
+ puts "[#{e.path}] #{e.message}"
937
+ end
938
+ end
939
+ </pre>
940
+ <br>
941
+
942
+
943
+ <a name="howto-parse"></a>
944
+ <h3 class="section2">Parsing with Validation</h3>
945
+ <p>From version 0.7, Kwalify supports parsing with validation.
946
+ </p>
947
+ <a name="howto-validation-with-parsing.rb"></a>
948
+ <pre class="program">require 'kwalify'
949
+ #require 'yaml'
950
+
951
+ ## load schema data
952
+ schema = Kwalify::Yaml.load_file('kwalify.schema.yaml')
953
+ ## or
954
+ #schema = YAML.load_file('kwalify.schema.yaml')
955
+
956
+ ## create validator
957
+ validator = Kwalify::Validator.new(schema)
958
+
959
+ ## create parser with validator
960
+ ## (if validator is ommitted, no validation executed.)
961
+ parser = Kwalify::Yaml::Parser.new(validator)
962
+
963
+ ## parse document with validation
964
+ filename = 'document.yaml'
965
+ document = parser.parse_file(filename)
966
+ ## or
967
+ #document = parser.parse(File.read(filename), filename)
968
+
969
+ ## show errors if exist
970
+ errors = parser.errors()
971
+ if errors &amp;&amp; !errors.empty?
972
+ for e in errors
973
+ puts "#{e.linenum}:#{e.column} [#{e.path}] #{e.message}"
974
+ end
975
+ end
976
+ </pre>
977
+ <br>
978
+
979
+
980
+ <a name="howto-meta"></a>
981
+ <h3 class="section2">Meta Validation</h3>
982
+ <p>Meta validator is a validator which validates schema definition.
983
+ The schema definition is placed at 'kwalify/kwalify.schema.yaml'.
984
+ </p>
985
+ <p>Kwalify also provides Kwalify::MetaValidator class which validates
986
+ schema definition.
987
+ </p>
988
+ <pre class="program">require 'kwalify'
989
+
990
+ ## meta validator
991
+ metavalidator = Kwalify::MetaValidator.instance
992
+
993
+ ## validate schema definition
994
+ parser = Kwalify::Yaml::Parser.new(metavalidator)
995
+ errors = parser.parse_file('kwalify.schema.yaml')
996
+ for e in errors
997
+ puts "#{e.linenum}:#{e.column} [#{e.path}] #{e.message}"
998
+ end if errors &amp;&amp; !errors.empty?
999
+ </pre>
1000
+ <p>Meta validation is also available with command-line option '-m'.
1001
+ </p>
1002
+ <pre class="terminal">$ kwalify -m schema1.yaml schema2.yaml ...
1003
+ </pre>
1004
+ <br>
1005
+
1006
+
1007
+ <a name="howto-hook"></a>
1008
+ <h3 class="section2">Validator#validator_hook()</h3>
1009
+ <p>You can extend Kwalify::Validator and override Kwalify::Validator#validator_hook() method.
1010
+ This method is called by Kwalify::Validator#validate().
1011
+ </p>
1012
+ <a name="answers-schema.yaml"></a>
1013
+ <div class="program_caption">
1014
+ answers-schema.yaml : 'name:' is important.</div>
1015
+ <pre class="program">type: map
1016
+ mapping:
1017
+ "answers":
1018
+ type: seq
1019
+ sequence:
1020
+ - type: map
1021
+ <strong>name: Answer</strong>
1022
+ mapping:
1023
+ "name": { type: str, required: yes }
1024
+ "answer": { type: str, required: yes,
1025
+ enum: [good, not bad, bad] }
1026
+ "reason": { type: str }
1027
+ </pre>
1028
+ <a name="answers-validator.rb"></a>
1029
+ <div class="program_caption">
1030
+ answers-validator.rb : validate script for Ruby</div>
1031
+ <pre class="program">#!/usr/bin/env ruby
1032
+
1033
+ require 'kwalify'
1034
+
1035
+ ## validator class for answers
1036
+ class AnswersValidator &lt; Kwalify::Validator
1037
+
1038
+ ## load schema definition
1039
+ @@schema = Kwalify::Yaml.load_file('answers-schema.yaml')
1040
+ ## or
1041
+ ## require 'yaml'
1042
+ ## @@schema = YAML.load_file('answers-schema.yaml')
1043
+
1044
+ def initialize()
1045
+ super(@@schema)
1046
+ end
1047
+
1048
+ ## hook method called by Validator#validate()
1049
+ <strong>def validate_hook(value, rule, path, errors)</strong>
1050
+ <strong>case rule.name</strong>
1051
+ <strong>when 'Answer'</strong>
1052
+ if value['answer'] == 'bad'
1053
+ reason = value['reason']
1054
+ if !reason || reason.empty?
1055
+ msg = "reason is required when answer is 'bad'."
1056
+ errors &lt;&lt; Kwalify::ValidationError.new(msg, path)
1057
+ end
1058
+ end
1059
+ end
1060
+ end
1061
+
1062
+ end
1063
+
1064
+ ## create validator
1065
+ validator = AnswersValidator.new
1066
+
1067
+ ## parse and validate YAML document
1068
+ input = ARGF.read()
1069
+ parser = Kwalify::Yaml::Parser.new(validator)
1070
+ document = parser.parse(input)
1071
+
1072
+ ## show errors
1073
+ errors = parser.errors()
1074
+ if !errors || errors.empty?
1075
+ puts "Valid."
1076
+ else
1077
+ puts "*** INVALID!"
1078
+ for e in errors
1079
+ # e.class == Kwalify::ValidationError
1080
+ puts "#{e.linenum}:#{e.column} [#{e.path}] #{e.message}"
1081
+ end
1082
+ end
1083
+ </pre>
1084
+ <a name="document07a.yaml"></a>
1085
+ <div class="program_caption">
1086
+ <code>document07a.yaml</code> : valid document example</div>
1087
+ <pre class="program">answers:
1088
+ - name: Foo
1089
+ answer: good
1090
+ reason: I like this style.
1091
+ - name: Bar
1092
+ answer: not bad
1093
+ - name: Baz
1094
+ answer: bad
1095
+ reason: I don't like this style.
1096
+ </pre>
1097
+ <a name="valid07.result"></a>
1098
+ <div class="terminal_caption">
1099
+ validate</div>
1100
+ <pre class="terminal">$ ruby answers-validator.rb document07a.yaml
1101
+ Valid.
1102
+ </pre>
1103
+ <a name="document07b.yaml"></a>
1104
+ <div class="program_caption">
1105
+ <code>document07b.yaml</code> : invalid document example</div>
1106
+ <pre class="program">answers:
1107
+ - name: Foo
1108
+ answer: good
1109
+ - name: Bar
1110
+ answer: bad
1111
+ - name: Baz
1112
+ answer: not bad
1113
+ </pre>
1114
+ <a name="invalid07.result"></a>
1115
+ <div class="terminal_caption">
1116
+ validate</div>
1117
+ <pre class="terminal">$ ruby answers-validator.rb document07b.yaml
1118
+ *** INVALID!
1119
+ 4:3 [/answers/1] reason is required when answer is 'bad'.
1120
+ </pre>
1121
+ <p>You can validate some document by a Validator instance because Validator class and Validator#validate() method are stateless. If you use instance variables in custom validator_hook() method, it becomes to be stateful.
1122
+ </p>
1123
+ <br>
1124
+
1125
+
1126
+ <a name="howto-preceding"></a>
1127
+ <h3 class="section2">Preceding Alias</h3>
1128
+ <p>From version 0.7, Kwalify allows aliases to appear before corresponding anchors are now appeared.
1129
+ These aliases are called as 'preceding alias'.
1130
+ </p>
1131
+ <a name="howto3.yaml"></a>
1132
+ <div class="program_caption">
1133
+ howto3.yaml</div>
1134
+ <pre class="program">- name: Foo
1135
+ parent: *bar # preceding alias
1136
+ - &amp;bar
1137
+ name: Bar
1138
+ parent: *baz # preceding alias
1139
+ - &amp;baz
1140
+ name: Baz
1141
+ parent: null
1142
+ </pre>
1143
+ <p>To enable preceding alias, set Kwalify::Yaml::Parser#preceding_alias to true.
1144
+ </p>
1145
+ <a name="howto3.rb"></a>
1146
+ <div class="program_caption">
1147
+ howto3.rb</div>
1148
+ <pre class="program">require 'kwalify'
1149
+ parser = Kwalify::Yaml::Parser.new
1150
+ <strong>parser.preceding_alias = true</strong> # enable preceding alias
1151
+ ydoc = parser.parse_file('howto3.yaml')
1152
+ require 'pp'
1153
+ pp ydoc
1154
+ </pre>
1155
+ <a name="howto3.result"></a>
1156
+ <div class="terminal_caption">
1157
+ result</div>
1158
+ <pre class="terminal">$ ruby howto3.rb
1159
+ [{"name"=&gt;"Foo",
1160
+ "parent"=&gt;{"name"=&gt;"Bar", "parent"=&gt;{"name"=&gt;"Baz", "parent"=&gt;nil}}},
1161
+ {"name"=&gt;"Bar", "parent"=&gt;{"name"=&gt;"Baz", "parent"=&gt;nil}},
1162
+ {"name"=&gt;"Baz", "parent"=&gt;nil}]
1163
+ </pre>
1164
+ <p>Command-line option '-P' also enables preceding alias.
1165
+ </p>
1166
+ <p>Preceding alias is very useful when document is complex.
1167
+ </p>
1168
+ <br>
1169
+
1170
+
1171
+ <a name="howto-databinding"></a>
1172
+ <h3 class="section2">Data Binding</h3>
1173
+ <p>From version 0.7, Kwalify supports data binding.
1174
+ * To enable data binding, set Kwalify::Yaml::Parser#data_binding to true.
1175
+ * It is required to specify class name in schema definition.
1176
+ (Notice that 'class:' constraint is available only with rule which type is 'map'.)
1177
+ * Also instance methods '[]', '[]=', and 'keys?' must be defined in the classes.
1178
+ (Including Kwalify::Util::HashLike modules is easy way to define them.)
1179
+ </p>
1180
+ <a name="config.schema.yaml"></a>
1181
+ <div class="program_caption">
1182
+ config.schema.yaml: schema definition file</div>
1183
+ <pre class="program">type: map
1184
+ <strong>class: Config</strong>
1185
+ mapping:
1186
+ "host": { type: str, required: true }
1187
+ "port": { type: int }
1188
+ "user": { type: str, required: true }
1189
+ "pass": { type: str, required: true }
1190
+ </pre>
1191
+ <a name="config.yaml"></a>
1192
+ <div class="program_caption">
1193
+ config.yaml: data file</div>
1194
+ <pre class="program">host: localhost
1195
+ port: 8080
1196
+ user: user1
1197
+ pass: password1
1198
+ </pre>
1199
+ <a name="loadconfig.rb"></a>
1200
+ <div class="program_caption">
1201
+ loadconfig.rb: ruby program</div>
1202
+ <pre class="program">## class definition
1203
+ require 'kwalify/util/hashlike'
1204
+ <strong>class Config</strong>
1205
+ <strong>include Kwalify::Util::HashLike</strong> # defines [], []=, and keys?
1206
+ attr_accessor :host, :posrt, :user, :pass
1207
+ <strong>end</strong>
1208
+ ## create validator object
1209
+ require 'kwalify'
1210
+ schema = Kwalify::Yaml.load_file('config.schema.yaml')
1211
+ validator = Kwalify::Validator.new(schema)
1212
+ ## parse configuration file with data binding
1213
+ parser = Kwalify::Yaml::Parser.new(validator)
1214
+ <strong>parser.data_binding = true</strong> # enable data binding
1215
+ config = parser.parse_file('config.yaml')
1216
+ require 'pp'
1217
+ pp config
1218
+ </pre>
1219
+ <a name="loadconfig.result"></a>
1220
+ <div class="terminal_caption">
1221
+ result</div>
1222
+ <pre class="terminal">$ ruby loadconfig.rb
1223
+ #&lt;Config:
1224
+ @host="localhost",
1225
+ @pass="password1",
1226
+ @port=8080,
1227
+ @user="user1"&gt;
1228
+ </pre>
1229
+ <p>Data binding is available even when data is more complex.
1230
+ Preceding alias is also available.
1231
+ </p>
1232
+ <p>For example, the following data is complex because it uses anchor and alias (including preceding alias).
1233
+ </p>
1234
+ <a name="BABEL.data.yaml"></a>
1235
+ <div class="program_caption">
1236
+ BABEL.data.yaml</div>
1237
+ <pre class="program">teams:
1238
+ - &amp;thechildren
1239
+ name: The Children
1240
+ desc: Level 7 ESPers
1241
+ chief: *minamoto # preceding alias
1242
+ members: [*kaoru, *aoi, *shiho] # preceding aliases
1243
+
1244
+ members:
1245
+ - &amp;minamoto
1246
+ name: Kohichi Minamoto
1247
+ desc: Scientist
1248
+ team: *thechildren
1249
+ - &amp;kaoru
1250
+ name: Kaoru Akashi
1251
+ desc: Psychokino
1252
+ team: *thechildren
1253
+ - &amp;aoi
1254
+ name: Aoi Nogami
1255
+ desc: Teleporter
1256
+ team: *thechildren
1257
+ - &amp;shiho
1258
+ name: Shiho Sannomiya
1259
+ desc: Psycometrer
1260
+ team: *thechildren
1261
+ </pre>
1262
+ <p>Here is the schema definition.
1263
+ (Notice that 'class:' constraint is available only with rule which type is 'map'.)
1264
+ </p>
1265
+ <a name="BABEL.schema.yaml"></a>
1266
+ <div class="program_caption">
1267
+ BABEL.schema.yaml</div>
1268
+ <pre class="program">type: map
1269
+ required: yes
1270
+ mapping:
1271
+ "teams":
1272
+ type: seq
1273
+ required: yes
1274
+ sequence:
1275
+ - &amp;team
1276
+ type: map
1277
+ required: yes
1278
+ <strong>class: Team</strong>
1279
+ mapping:
1280
+ "name": {type: str, required: yes, unique: yes}
1281
+ "desc": {type: str}
1282
+ "chief": *member # preceding alias
1283
+ "members":
1284
+ type: seq
1285
+ sequence: [*member] # preceding alias
1286
+ "members":
1287
+ type: seq
1288
+ required: yes
1289
+ sequence:
1290
+ - &amp;member
1291
+ type: map
1292
+ required: yes
1293
+ <strong>class: Member</strong>
1294
+ mapping:
1295
+ "name": {type: str, required: yes, unique: yes}
1296
+ "desc": {type: str}
1297
+ "team": *team
1298
+ </pre>
1299
+ <p>It is required to define class 'Team' and 'Member' for data-binding.
1300
+ Command-line option '-a genclass-ruby' will help you to generate class definitions from schema definition.
1301
+ Try 'kwalify -ha genclass-ruby' for more details about 'genclass-ruby' action.
1302
+ </p>
1303
+ <a name="babel_genclass.result"></a>
1304
+ <pre class="terminal">$ kwalify -a genclass-ruby -P -f BABEL.schema.yaml \
1305
+ --hashlike --initialize=false --module=Babel
1306
+ require 'kwalify/util/hashlike'
1307
+
1308
+ module Babel
1309
+
1310
+ ##
1311
+ class Team
1312
+ include Kwalify::Util::HashLike
1313
+ attr_accessor :name # str
1314
+ attr_accessor :desc # str
1315
+ attr_accessor :chief # map
1316
+ attr_accessor :members # seq
1317
+ end
1318
+
1319
+ ##
1320
+ class Member
1321
+ include Kwalify::Util::HashLike
1322
+ attr_accessor :name # str
1323
+ attr_accessor :desc # str
1324
+ attr_accessor :team # map
1325
+ end
1326
+
1327
+ end
1328
+ $ kwalify -a genclass-ruby -P -f BABEL.schema.yaml \
1329
+ --hashlike --initialize=false --module=Babel &gt; models.rb
1330
+ </pre>
1331
+ <p>Here is the ruby program.
1332
+ </p>
1333
+ <a name="loadbabel.rb"></a>
1334
+ <div class="program_caption">
1335
+ loadbabel.rb</div>
1336
+ <pre class="program">require 'kwalify'
1337
+ <strong>require 'models'</strong>
1338
+
1339
+ ## load schema definition
1340
+ schema = Kwalify::Yaml.load_file('BABEL.schema.yaml',
1341
+ :untabify=&gt;true,
1342
+ :preceding_alias=&gt;true)
1343
+
1344
+ ## add module name to 'class:'
1345
+ Kwalify::Util.traverse_schema(schema) do |rulehash|
1346
+ if rulehash['class']
1347
+ rulehash['class'] = 'Babel::' + rulehash['class']
1348
+ end
1349
+ end
1350
+
1351
+ ## create validator
1352
+ validator = Kwalify::Validator.new(schema)
1353
+
1354
+ ## parse with data-binding
1355
+ parser = Kwalify::Yaml::Parser.new(validator)
1356
+ parser.preceding_alias = true
1357
+ <strong>parser.data_binding = true</strong>
1358
+ ydoc = parser.parse_file('BABEL.data.yaml', :untabify=&gt;true)
1359
+
1360
+ ## show document
1361
+ require 'pp'
1362
+ pp ydoc
1363
+ </pre>
1364
+ <a name="howto5_databinding.result"></a>
1365
+ <div class="terminal_caption">
1366
+ result</div>
1367
+ <pre class="terminal">$ ruby loadbabel.rb
1368
+ {"teams"=&gt;
1369
+ [#&lt;Babel::Team:0x53e0f8
1370
+ @chief=
1371
+ #&lt;Babel::Member:0x53d5e0
1372
+ @desc="Scientist",
1373
+ @name="Kohichi Minamoto",
1374
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1375
+ @desc="Level 7 ESPers",
1376
+ @members=
1377
+ [#&lt;Babel::Member:0x53d018
1378
+ @desc="Psychokino",
1379
+ @name="Kaoru Akashi",
1380
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1381
+ #&lt;Babel::Member:0x53ca50
1382
+ @desc="Teleporter",
1383
+ @name="Aoi Nogami",
1384
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1385
+ #&lt;Babel::Member:0x53c488
1386
+ @desc="Psycometrer",
1387
+ @name="Shiho Sannomiya",
1388
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;],
1389
+ @name="The Children"&gt;],
1390
+ "members"=&gt;
1391
+ [#&lt;Babel::Member:0x53d5e0
1392
+ @desc="Scientist",
1393
+ @name="Kohichi Minamoto",
1394
+ @team=
1395
+ #&lt;Babel::Team:0x53e0f8
1396
+ @chief=#&lt;Babel::Member:0x53d5e0 ...&gt;,
1397
+ @desc="Level 7 ESPers",
1398
+ @members=
1399
+ [#&lt;Babel::Member:0x53d018
1400
+ @desc="Psychokino",
1401
+ @name="Kaoru Akashi",
1402
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1403
+ #&lt;Babel::Member:0x53ca50
1404
+ @desc="Teleporter",
1405
+ @name="Aoi Nogami",
1406
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1407
+ #&lt;Babel::Member:0x53c488
1408
+ @desc="Psycometrer",
1409
+ @name="Shiho Sannomiya",
1410
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;],
1411
+ @name="The Children"&gt;&gt;,
1412
+ #&lt;Babel::Member:0x53d018
1413
+ @desc="Psychokino",
1414
+ @name="Kaoru Akashi",
1415
+ @team=
1416
+ #&lt;Babel::Team:0x53e0f8
1417
+ @chief=
1418
+ #&lt;Babel::Member:0x53d5e0
1419
+ @desc="Scientist",
1420
+ @name="Kohichi Minamoto",
1421
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1422
+ @desc="Level 7 ESPers",
1423
+ @members=
1424
+ [#&lt;Babel::Member:0x53d018 ...&gt;,
1425
+ #&lt;Babel::Member:0x53ca50
1426
+ @desc="Teleporter",
1427
+ @name="Aoi Nogami",
1428
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1429
+ #&lt;Babel::Member:0x53c488
1430
+ @desc="Psycometrer",
1431
+ @name="Shiho Sannomiya",
1432
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;],
1433
+ @name="The Children"&gt;&gt;,
1434
+ #&lt;Babel::Member:0x53ca50
1435
+ @desc="Teleporter",
1436
+ @name="Aoi Nogami",
1437
+ @team=
1438
+ #&lt;Babel::Team:0x53e0f8
1439
+ @chief=
1440
+ #&lt;Babel::Member:0x53d5e0
1441
+ @desc="Scientist",
1442
+ @name="Kohichi Minamoto",
1443
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1444
+ @desc="Level 7 ESPers",
1445
+ @members=
1446
+ [#&lt;Babel::Member:0x53d018
1447
+ @desc="Psychokino",
1448
+ @name="Kaoru Akashi",
1449
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1450
+ #&lt;Babel::Member:0x53ca50 ...&gt;,
1451
+ #&lt;Babel::Member:0x53c488
1452
+ @desc="Psycometrer",
1453
+ @name="Shiho Sannomiya",
1454
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;],
1455
+ @name="The Children"&gt;&gt;,
1456
+ #&lt;Babel::Member:0x53c488
1457
+ @desc="Psycometrer",
1458
+ @name="Shiho Sannomiya",
1459
+ @team=
1460
+ #&lt;Babel::Team:0x53e0f8
1461
+ @chief=
1462
+ #&lt;Babel::Member:0x53d5e0
1463
+ @desc="Scientist",
1464
+ @name="Kohichi Minamoto",
1465
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1466
+ @desc="Level 7 ESPers",
1467
+ @members=
1468
+ [#&lt;Babel::Member:0x53d018
1469
+ @desc="Psychokino",
1470
+ @name="Kaoru Akashi",
1471
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1472
+ #&lt;Babel::Member:0x53ca50
1473
+ @desc="Teleporter",
1474
+ @name="Aoi Nogami",
1475
+ @team=#&lt;Babel::Team:0x53e0f8 ...&gt;&gt;,
1476
+ #&lt;Babel::Member:0x53c488 ...&gt;],
1477
+ @name="The Children"&gt;&gt;]}
1478
+ </pre>
1479
+ <br>
1480
+
1481
+
1482
+ <br>
1483
+
1484
+
1485
+ <a name="actions"></a>
1486
+ <h2 class="section1">Actions</h2>
1487
+ <p>Kwalify has the command-line '-a <em>action</em>' which perform a certain action to schema definition.
1488
+ Currently only the following actions are provided.
1489
+ </p>
1490
+ <dl class="dl2">
1491
+ <dt class="dt2">
1492
+ genclass-ruby</dt>
1493
+ <dd class="dd2">
1494
+ <p> Generate class definitions in Ruby.
1495
+ </p>
1496
+ </dd>
1497
+ <dt class="dt2">
1498
+ genclass-java</dt>
1499
+ <dd class="dd2">
1500
+ <p> Generate class definitions in Java.
1501
+ </p>
1502
+ </dd>
1503
+ <dt class="dt2">
1504
+ genclass-php</dt>
1505
+ <dd class="dd2">
1506
+ <p> Generate class definitions in Ruby.
1507
+ </p>
1508
+ </dd>
1509
+ </dl>
1510
+ <p>In fact action name represents template filename.
1511
+ For example, action 'genclass-ruby' invokes template file 'kwalify/templates/genclass-ruby.eruby'.
1512
+ </p>
1513
+ <p>Each action can accept some command-line properties.
1514
+ For example, action 'genclass-ruby' can accept the command-line properties '--module=<em>name</em>', '--parent=<em>name</em>', and so on.
1515
+ Type 'kwalify -h -a <em>action</em>' to show the list of command-line properties the action can accept.
1516
+ </p>
1517
+ <p>It is able to add your on action template file.
1518
+ The command-line option '-I' (template path) will help you.
1519
+ </p>
1520
+ <a name="action-genclass"></a>
1521
+ <h3 class="section2">Class Definition Generation</h3>
1522
+ <p>Command-line option '-a genclass-ruby' or '-a genclass-java' generates class definition
1523
+ automatically from schema definition in Ruby or Java.
1524
+ </p>
1525
+ <p>Assume the following data file and schema definition.
1526
+ </p>
1527
+ <a name="address_book.yaml"></a>
1528
+ <div class="program_caption">
1529
+ <code>address_book.yaml</code> : data file</div>
1530
+ <pre class="program">groups:
1531
+
1532
+ - name: family
1533
+ desc: my family
1534
+
1535
+ - name: friend
1536
+ desc: my friends
1537
+
1538
+ - name: business
1539
+ desc: those who works together
1540
+
1541
+ people:
1542
+
1543
+ - name: Sumire
1544
+ group: family
1545
+ birth: 2000-01-01
1546
+ blood: A
1547
+
1548
+ - name: Shiina
1549
+ group: friend
1550
+ birth: 1995-01-01
1551
+ email: shiina@mail.org
1552
+
1553
+ - name: Sakura
1554
+ group: business
1555
+ email: cherry@mail.net
1556
+ phone: 012-345-6789
1557
+ </pre>
1558
+ <a name="address_book.schema.yaml"></a>
1559
+ <div class="program_caption">
1560
+ <code>address_book.schema.yaml</code> : schema definition file</div>
1561
+ <pre class="program">type: map
1562
+ <strong>class: AddressBook</strong>
1563
+ desc: address-book class
1564
+ mapping:
1565
+ "groups":
1566
+ type: seq
1567
+ sequence:
1568
+ - type: map
1569
+ <strong>class: Group</strong>
1570
+ desc: group class
1571
+ mapping:
1572
+ "name": { type: str, required: yes }
1573
+ "desc": { type: str }
1574
+ "people":
1575
+ type: seq
1576
+ sequence:
1577
+ - type: map
1578
+ <strong>class: Person</strong>
1579
+ desc: person class
1580
+ mapping:
1581
+ "name": { type: str, required: yes }
1582
+ "desc": { type: str }
1583
+ "group": { type: str }
1584
+ "email": { type: str, pattern: '/@/' }
1585
+ "phone": { type: str }
1586
+ "birth": { type: date }
1587
+ "blood": { type: str, enum: [A, B, O, AB] }
1588
+ "deleted": { type: bool, <strong>default: false</strong> }
1589
+ </pre>
1590
+ <a name="action-genclass-ruby"></a>
1591
+ <h4 class="section3">Ruby Class Definition</h4>
1592
+ <div class="terminal_caption">
1593
+ generate class definition</div>
1594
+ <pre class="terminal">$ kwalify <strong>-a genclass-ruby</strong> -tf address_book.schema.yaml &gt; address_book.rb
1595
+ </pre>
1596
+ <a name="address_book.rb"></a>
1597
+ <div class="program_caption">
1598
+ <code>address_book.rb</code> : generated class definition</div>
1599
+ <pre class="program">## address-book class
1600
+ class AddressBook
1601
+ def initialize(hash=nil)
1602
+ if hash.nil?
1603
+ return
1604
+ end
1605
+ @groups = (v=hash['groups']) ? v.map!{|e| e.is_a?(Group) ? e : Group.new(e)} : v
1606
+ @people = (v=hash['people']) ? v.map!{|e| e.is_a?(Person) ? e : Person.new(e)} : v
1607
+ end
1608
+ attr_accessor :groups # seq
1609
+ attr_accessor :people # seq
1610
+ end
1611
+
1612
+ ## group class
1613
+ class Group
1614
+ def initialize(hash=nil)
1615
+ if hash.nil?
1616
+ return
1617
+ end
1618
+ @name = hash['name']
1619
+ @desc = hash['desc']
1620
+ end
1621
+ attr_accessor :name # str
1622
+ attr_accessor :desc # str
1623
+ end
1624
+
1625
+ ## person class
1626
+ class Person
1627
+ def initialize(hash=nil)
1628
+ if hash.nil?
1629
+ @deleted = false
1630
+ return
1631
+ end
1632
+ @name = hash['name']
1633
+ @desc = hash['desc']
1634
+ @group = hash['group']
1635
+ @email = hash['email']
1636
+ @phone = hash['phone']
1637
+ @birth = hash['birth']
1638
+ @blood = hash['blood']
1639
+ @deleted = (v=hash['deleted']).nil? ? false : v
1640
+ end
1641
+ attr_accessor :name # str
1642
+ attr_accessor :desc # str
1643
+ attr_accessor :group # str
1644
+ attr_accessor :email # str
1645
+ attr_accessor :phone # str
1646
+ attr_accessor :birth # date
1647
+ attr_accessor :blood # str
1648
+ attr_accessor :deleted # bool
1649
+ def deleted? ; @deleted ; end
1650
+ end
1651
+ </pre>
1652
+ <a name="example_address_book.rb"></a>
1653
+ <div class="program_caption">
1654
+ <code>example_address_book.rb</code> : example code of using address-book.rb</div>
1655
+ <pre class="program">require 'address_book'
1656
+ require 'yaml'
1657
+ require 'pp'
1658
+
1659
+ str = File.read('address_book.yaml')
1660
+ ydoc = YAML.load(str)
1661
+ <strong>addrbook = AddressBook.new(ydoc)</strong>
1662
+
1663
+ pp <strong>addrbook.groups</strong>
1664
+ pp <strong>addrbook.people</strong>
1665
+ </pre>
1666
+ <a name="example_address_book_ruby.result"></a>
1667
+ <div class="terminal_caption">
1668
+ result</div>
1669
+ <pre class="terminal">$ ruby example_address_book.rb
1670
+ [#&lt;Group:0xddf24 @desc="my family", @name="family"&gt;,
1671
+ #&lt;Group:0xddf10 @desc="my friends", @name="friend"&gt;,
1672
+ #&lt;Group:0xdde84 @desc="those who works together", @name="business"&gt;]
1673
+ [#&lt;Person:0xdefdc
1674
+ @birth=#&lt;Date: 4903089/2,0,2299161&gt;,
1675
+ @blood="A",
1676
+ @deleted=false,
1677
+ @desc=nil,
1678
+ @email=nil,
1679
+ @group="family",
1680
+ @name="Sumire",
1681
+ @phone=nil&gt;,
1682
+ #&lt;Person:0xdee9c
1683
+ @birth=#&lt;Date: 4899437/2,0,2299161&gt;,
1684
+ @blood=nil,
1685
+ @deleted=false,
1686
+ @desc=nil,
1687
+ @email="shiina@mail.org",
1688
+ @group="friend",
1689
+ @name="Shiina",
1690
+ @phone=nil&gt;,
1691
+ #&lt;Person:0xde8e8
1692
+ @birth=nil,
1693
+ @blood=nil,
1694
+ @deleted=false,
1695
+ @desc=nil,
1696
+ @email="cherry@mail.net",
1697
+ @group="business",
1698
+ @name="Sakura",
1699
+ @phone="012-345-6789"&gt;]
1700
+ </pre>
1701
+ <p>Command-line option '<code>-h -a genclass-ruby</code>' shows the command-line properties that template can accept.
1702
+ </p>
1703
+ <a name="option_ha.result"></a>
1704
+ <div class="terminal_caption">
1705
+ show command-line properties</div>
1706
+ <pre class="terminal">$ kwalify -ha genclass-ruby
1707
+ --module=name : module name in which class defined
1708
+ --parent=name : parent class name
1709
+ --include=name : module name which all classes include
1710
+ --initialize=false : not print initialize() method
1711
+ --hashlike : include Kwalify::Util::HashLike module
1712
+ </pre>
1713
+ <div class="terminal_caption">
1714
+ example of command-line properties</div>
1715
+ <pre class="terminal">$ kwalify -ha genclass-ruby --module=My --hashlike
1716
+ </pre>
1717
+ <p>If command-line property '--hashlike' (== '--hashlike=true') is specified,
1718
+ module Kwalify::Util::HashLike is included for each classes generated.
1719
+ That module is defined in 'kwalify/util/hashlike.rb'
1720
+ </p>
1721
+ <br>
1722
+
1723
+ <a name="action-genclass-java"></a>
1724
+ <h4 class="section3">Java Class Definition</h4>
1725
+ <a name="genclass_java.result"></a>
1726
+ <div class="terminal_caption">
1727
+ generate java class definition</div>
1728
+ <pre class="terminal">$ kwalify <strong>-a genclass-java</strong> -tf address_book.schema.yaml
1729
+ generating ./AddressBook.java...done.
1730
+ generating ./Group.java...done.
1731
+ generating ./Person.java...done.
1732
+ </pre>
1733
+ <a name="AddressBook.java.expected"></a>
1734
+ <div class="program_caption">
1735
+ <code>AddressBook.java</code> : generated class definition</div>
1736
+ <pre class="program">// generated by kwalify from address_book.schema.yaml
1737
+
1738
+ import java.util.*;
1739
+
1740
+ /**
1741
+ * address-book class
1742
+ */
1743
+ public class AddressBook {
1744
+
1745
+ private List _groups;
1746
+ private List _people;
1747
+
1748
+ public AddressBook() {}
1749
+
1750
+ public AddressBook(Map map) {
1751
+ List seq;
1752
+ Object obj;
1753
+ if ((seq = (List)map.get("groups")) != null) {
1754
+ for (int i = 0; i &lt; seq.size(); i++) {
1755
+ if ((obj = seq.get(i)) instanceof Map) {
1756
+ seq.set(i, new Group((Map)obj));
1757
+ }
1758
+ }
1759
+ }
1760
+ _groups = seq;
1761
+ if ((seq = (List)map.get("people")) != null) {
1762
+ for (int i = 0; i &lt; seq.size(); i++) {
1763
+ if ((obj = seq.get(i)) instanceof Map) {
1764
+ seq.set(i, new Person((Map)obj));
1765
+ }
1766
+ }
1767
+ }
1768
+ _people = seq;
1769
+ }
1770
+
1771
+ public List getGroups() { return _groups; }
1772
+ public void setGroups(List groups_) { _groups = groups_; }
1773
+ public List getPeople() { return _people; }
1774
+ public void setPeople(List people_) { _people = people_; }
1775
+ }
1776
+ </pre>
1777
+ <a name="Group.java.expected"></a>
1778
+ <div class="program_caption">
1779
+ <code>Group.java</code> : generated class definition</div>
1780
+ <pre class="program">// generated by kwalify from address_book.schema.yaml
1781
+
1782
+ import java.util.*;
1783
+
1784
+ /**
1785
+ * group class
1786
+ */
1787
+ public class Group {
1788
+
1789
+ private String _name;
1790
+ private String _desc;
1791
+
1792
+ public Group() {}
1793
+
1794
+ public Group(Map map) {
1795
+ _name = (String)map.get("name");
1796
+ _desc = (String)map.get("desc");
1797
+ }
1798
+
1799
+ public String getName() { return _name; }
1800
+ public void setName(String name_) { _name = name_; }
1801
+ public String getDesc() { return _desc; }
1802
+ public void setDesc(String desc_) { _desc = desc_; }
1803
+ }
1804
+ </pre>
1805
+ <a name="Person.java.expected"></a>
1806
+ <div class="program_caption">
1807
+ <code>Person.java</code> : generated class definition</div>
1808
+ <pre class="program">// generated by kwalify from address_book.schema.yaml
1809
+
1810
+ import java.util.*;
1811
+
1812
+ /**
1813
+ * person class
1814
+ */
1815
+ public class Person {
1816
+
1817
+ private String _name;
1818
+ private String _desc;
1819
+ private String _group;
1820
+ private String _email;
1821
+ private String _phone;
1822
+ private Date _birth;
1823
+ private String _blood;
1824
+
1825
+ public Person() {}
1826
+
1827
+ public Person(Map map) {
1828
+ _name = (String)map.get("name");
1829
+ _desc = (String)map.get("desc");
1830
+ _group = (String)map.get("group");
1831
+ _email = (String)map.get("email");
1832
+ _phone = (String)map.get("phone");
1833
+ _birth = (Date)map.get("birth");
1834
+ _blood = (String)map.get("blood");
1835
+ }
1836
+
1837
+ public String getName() { return _name; }
1838
+ public void setName(String name_) { _name = name_; }
1839
+ public String getDesc() { return _desc; }
1840
+ public void setDesc(String desc_) { _desc = desc_; }
1841
+ public String getGroup() { return _group; }
1842
+ public void setGroup(String group_) { _group = group_; }
1843
+ public String getEmail() { return _email; }
1844
+ public void setEmail(String email_) { _email = email_; }
1845
+ public String getPhone() { return _phone; }
1846
+ public void setPhone(String phone_) { _phone = phone_; }
1847
+ public Date getBirth() { return _birth; }
1848
+ public void setBirth(Date birth_) { _birth = birth_; }
1849
+ public String getBlood() { return _blood; }
1850
+ public void setBlood(String blood_) { _blood = blood_; }
1851
+ }
1852
+ </pre>
1853
+ <a name="ExampleAddressBook.java"></a>
1854
+ <div class="program_caption">
1855
+ <code>ExampleAddressBook.java</code> : example code of using *.java</div>
1856
+ <pre class="program">import java.util.*;
1857
+ import kwalify.*;
1858
+
1859
+ public class ExampleAddressBook {
1860
+ public static void main(String args[]) throws Exception {
1861
+ // read schema
1862
+ String schema_str = Util.readFile("address_book.schema.yaml");
1863
+ schema_str = Util.untabify(schema_str);
1864
+ Object schema = new YamlParser(schema_str).parse();
1865
+
1866
+ // read document file
1867
+ String document_str = Util.readFile("address_book.yaml");
1868
+ document_str = Util.untabify(document_str);
1869
+ YamlParser parser = new YamlParser(document_str);
1870
+ Object document = parser.parse();
1871
+
1872
+ // create address book object
1873
+ AddressBook addrbook = new AddressBook((Map)document);
1874
+
1875
+ // show groups
1876
+ List groups = addrbook.getGroups();
1877
+ if (groups != null) {
1878
+ for (Iterator it = groups.iterator(); it.hasNext(); ) {
1879
+ Group group = (Group)it.next();
1880
+ System.out.println("group name: " + group.getName());
1881
+ System.out.println("group desc: " + group.getDesc());
1882
+ System.out.println();
1883
+ }
1884
+ }
1885
+
1886
+ // show people
1887
+ List people = addrbook.getPeople();
1888
+ if (people != null) {
1889
+ for (Iterator it = people.iterator(); it.hasNext(); ) {
1890
+ Person person = (Person)it.next();
1891
+ System.out.println("person name: " + person.getName());
1892
+ System.out.println("person group: " + person.getGroup());
1893
+ System.out.println("person email: " + person.getEmail());
1894
+ System.out.println("person phone: " + person.getPhone());
1895
+ System.out.println("person blood: " + person.getBlood());
1896
+ System.out.println("person birth: " + person.getBirth());
1897
+ System.out.println();
1898
+ }
1899
+ }
1900
+ }
1901
+
1902
+ }
1903
+ </pre>
1904
+ <a name="example_address_book_java.result"></a>
1905
+ <div class="terminal_caption">
1906
+ result</div>
1907
+ <pre class="terminal">$ javac -classpath '.:kwalify.jar' *.java
1908
+ $ java -classpath '.:kwalify.jar' ExampleAddressBook
1909
+ group name: family
1910
+ group desc: my family
1911
+
1912
+ group name: friend
1913
+ group desc: my friends
1914
+
1915
+ group name: business
1916
+ group desc: those who works together
1917
+
1918
+ person name: Sumire
1919
+ person group: family
1920
+ person email: null
1921
+ person phone: null
1922
+ person blood: A
1923
+ person birth: Tue Feb 01 00:00:00 JST 2000
1924
+
1925
+ person name: Shiina
1926
+ person group: friend
1927
+ person email: shiina@mail.org
1928
+ person phone: null
1929
+ person blood: null
1930
+ person birth: Wed Feb 01 00:00:00 JST 1995
1931
+
1932
+ person name: Sakura
1933
+ person group: business
1934
+ person email: cherry@mail.net
1935
+ person phone: 012-345-6789
1936
+ person blood: null
1937
+ person birth: null
1938
+
1939
+ </pre>
1940
+ <p>Command-line option '<code>-h -a genclass-java</code>' shows the command-line properties that template can accept.
1941
+ </p>
1942
+ <a name="option_ha_genclass_java.result"></a>
1943
+ <div class="terminal_caption">
1944
+ show command-line properties</div>
1945
+ <pre class="terminal">$ kwalify -ha genclass-java
1946
+ --package=name : package name
1947
+ --extends=name : class name to extend
1948
+ --implements=name,... : interface names to implement
1949
+ --dir=path : directory to locate output file
1950
+ --basedir=path : base directory to locate output file
1951
+ --constructor=false : not print initialize() method
1952
+ </pre>
1953
+ <div class="terminal_caption">
1954
+ example of command-line properties</div>
1955
+ <pre class="terminal">$ kwalify -a genclass-java --package=com.example.my --implements=Serializable --basedir=src
1956
+ </pre>
1957
+ <br>
1958
+
1959
+ <br>
1960
+
1961
+
1962
+ <br>
1963
+
1964
+
1965
+ <a name="ref"></a>
1966
+ <h2 class="section1">References</h2>
1967
+ <a name="ref-usage"></a>
1968
+ <h3 class="section2">Usage in Command-Line</h3>
1969
+ <div class="terminal_caption">
1970
+ </div>
1971
+ <pre class="terminal">### usage1: validate YAML document in command-line
1972
+ $ kwalify -f schema.yaml document.yaml [document2.yaml ...]
1973
+ ### usage2: validate schema definition in command-line
1974
+ $ kwalify -m schema.yaml [schema2.yaml ...]
1975
+ </pre>
1976
+ <p>Command-line options:
1977
+ </p>
1978
+ <dl class="dl3">
1979
+ <dt class="dt3"><strong>
1980
+ <code>-h</code>, <code>--help</code> </strong></dt>
1981
+ <dd class="dd3">
1982
+ Print help message.
1983
+ </dd>
1984
+ <dt class="dt3"><strong>
1985
+ <code>-v</code> </strong></dt>
1986
+ <dd class="dd3">
1987
+ Print version.
1988
+ </dd>
1989
+ <dt class="dt3"><strong>
1990
+ <code>-q</code> </strong></dt>
1991
+ <dd class="dd3">
1992
+ Quiet mode.
1993
+ </dd>
1994
+ <dt class="dt3"><strong>
1995
+ <code>-s</code> </strong></dt>
1996
+ <dd class="dd3">
1997
+ (Obsolete. Use '-q' instead.) Silent mode.
1998
+ </dd>
1999
+ <dt class="dt3"><strong>
2000
+ <code>-f <em>schema.yaml</em></code> </strong></dt>
2001
+ <dd class="dd3">
2002
+ Specify schema definition file.
2003
+ </dd>
2004
+ <dt class="dt3"><strong>
2005
+ <code>-m</code> </strong></dt>
2006
+ <dd class="dd3">
2007
+ Meta-validation of schema definition.
2008
+ </dd>
2009
+ <dt class="dt3"><strong>
2010
+ <code>-t</code> </strong></dt>
2011
+ <dd class="dd3">
2012
+ Expand tab characters to spaces automatically.
2013
+ </dd>
2014
+ <dt class="dt3"><strong>
2015
+ <code>-l</code> </strong></dt>
2016
+ <dd class="dd3">
2017
+ Show linenumber on which error found.
2018
+ </dd>
2019
+ <dt class="dt3"><strong>
2020
+ <code>-E</code> </strong></dt>
2021
+ <dd class="dd3">
2022
+ Show errors in Emacs-compatible style (implies '-l' option).
2023
+ </dd>
2024
+ <dt class="dt3"><strong>
2025
+ <code>-a action</code> </strong></dt>
2026
+ <dd class="dd3">
2027
+ Do action. Currently supported action is 'genclass-ruby' and 'genclass-java'.
2028
+ Try '-ha action' to get help about the action.
2029
+ </dd>
2030
+ <dt class="dt3"><strong>
2031
+ <code>-I path1,path2,...</code> </strong></dt>
2032
+ <dd class="dd3">
2033
+ Template path (for '-a').
2034
+ </dd>
2035
+ <dt class="dt3"><strong>
2036
+ <code>-P</code> </strong></dt>
2037
+ <dd class="dd3">
2038
+ Enable preceding alias.
2039
+ </dd>
2040
+ </dl>
2041
+ <br>
2042
+
2043
+
2044
+ <br>
2045
+
2046
+
2047
+
2048
+ </div>
2049
+
2050
+ </body>
2051
+ </html>