dc-kwalify 0.7.2

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