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.
- data/CHANGES.txt +252 -0
- data/MIT-LICENSE +20 -0
- data/README.txt +61 -0
- data/bin/kwalify +13 -0
- data/contrib/inline-require +179 -0
- data/contrib/kwalify +4160 -0
- data/doc/docstyle.css +188 -0
- data/doc/img/fig01.png +0 -0
- data/doc/users-guide.html +2050 -0
- data/doc-api/classes/CommandOptionError.html +184 -0
- data/doc-api/classes/CommandOptionParser.html +325 -0
- data/doc-api/classes/Kwalify/AssertionError.html +148 -0
- data/doc-api/classes/Kwalify/BaseError.html +297 -0
- data/doc-api/classes/Kwalify/BaseParser.html +461 -0
- data/doc-api/classes/Kwalify/CommandOptionError.html +168 -0
- data/doc-api/classes/Kwalify/ErrorHelper.html +223 -0
- data/doc-api/classes/Kwalify/HashInterface.html +118 -0
- data/doc-api/classes/Kwalify/Json.html +105 -0
- data/doc-api/classes/Kwalify/KwalifyError.html +111 -0
- data/doc-api/classes/Kwalify/Main.html +339 -0
- data/doc-api/classes/Kwalify/MetaValidator.html +448 -0
- data/doc-api/classes/Kwalify/Parser.html +155 -0
- data/doc-api/classes/Kwalify/PlainYamlParser/Alias.html +165 -0
- data/doc-api/classes/Kwalify/PlainYamlParser.html +523 -0
- data/doc-api/classes/Kwalify/Rule.html +433 -0
- data/doc-api/classes/Kwalify/SchemaError.html +148 -0
- data/doc-api/classes/Kwalify/SyntaxError.html +185 -0
- data/doc-api/classes/Kwalify/Types.html +302 -0
- data/doc-api/classes/Kwalify/Util/HashLike.html +246 -0
- data/doc-api/classes/Kwalify/Util/OrderedHash.html +330 -0
- data/doc-api/classes/Kwalify/Util.html +390 -0
- data/doc-api/classes/Kwalify/ValidationError.html +148 -0
- data/doc-api/classes/Kwalify/Validator.html +381 -0
- data/doc-api/classes/Kwalify/Yaml/Parser.html +1538 -0
- data/doc-api/classes/Kwalify/Yaml.html +194 -0
- data/doc-api/classes/Kwalify/YamlParser.html +542 -0
- data/doc-api/classes/Kwalify/YamlSyntaxError.html +119 -0
- data/doc-api/classes/Kwalify.html +292 -0
- data/doc-api/classes/Test/Unit.html +101 -0
- data/doc-api/classes/Test.html +107 -0
- data/doc-api/created.rid +1 -0
- data/doc-api/files/__/README_txt.html +172 -0
- data/doc-api/files/kwalify/errors_rb.html +114 -0
- data/doc-api/files/kwalify/main_rb.html +118 -0
- data/doc-api/files/kwalify/messages_rb.html +107 -0
- data/doc-api/files/kwalify/meta-validator_rb.html +117 -0
- data/doc-api/files/kwalify/parser/base_rb.html +116 -0
- data/doc-api/files/kwalify/parser/yaml_rb.html +117 -0
- data/doc-api/files/kwalify/rule_rb.html +116 -0
- data/doc-api/files/kwalify/types_rb.html +114 -0
- data/doc-api/files/kwalify/util/assert-text-equal_rb.html +115 -0
- data/doc-api/files/kwalify/util/hash-interface_rb.html +114 -0
- data/doc-api/files/kwalify/util/hashlike_rb.html +107 -0
- data/doc-api/files/kwalify/util/option-parser_rb.html +107 -0
- data/doc-api/files/kwalify/util/ordered-hash_rb.html +107 -0
- data/doc-api/files/kwalify/util/testcase-helper_rb.html +115 -0
- data/doc-api/files/kwalify/util_rb.html +107 -0
- data/doc-api/files/kwalify/validator_rb.html +117 -0
- data/doc-api/files/kwalify/yaml-parser_rb.html +117 -0
- data/doc-api/files/kwalify_rb.html +121 -0
- data/doc-api/fr_class_index.html +57 -0
- data/doc-api/fr_file_index.html +45 -0
- data/doc-api/fr_method_index.html +168 -0
- data/doc-api/index.html +24 -0
- data/doc-api/rdoc-style.css +208 -0
- data/examples/address-book/Makefile +10 -0
- data/examples/address-book/address-book.schema.yaml +45 -0
- data/examples/address-book/address-book.yaml +36 -0
- data/examples/data-binding/BABEL.data.yaml +63 -0
- data/examples/data-binding/BABEL.schema.yaml +31 -0
- data/examples/data-binding/Makefile +8 -0
- data/examples/data-binding/Rakefile +13 -0
- data/examples/data-binding/main.rb +27 -0
- data/examples/invoice/Makefile +9 -0
- data/examples/invoice/invoice.schema.yaml +43 -0
- data/examples/invoice/invoice.yaml +32 -0
- data/examples/tapkit/Makefile +10 -0
- data/examples/tapkit/main.rb +7 -0
- data/examples/tapkit/tapkit.schema.yaml +146 -0
- data/examples/tapkit/tapkit.yaml +85 -0
- data/lib/kwalify/errors.rb +127 -0
- data/lib/kwalify/kwalify.schema.yaml +58 -0
- data/lib/kwalify/main.rb +442 -0
- data/lib/kwalify/messages.rb +173 -0
- data/lib/kwalify/meta-validator.rb +275 -0
- data/lib/kwalify/parser/base.rb +127 -0
- data/lib/kwalify/parser/yaml.rb +841 -0
- data/lib/kwalify/rule.rb +559 -0
- data/lib/kwalify/templates/genclass-java.eruby +222 -0
- data/lib/kwalify/templates/genclass-php.eruby +104 -0
- data/lib/kwalify/templates/genclass-ruby.eruby +113 -0
- data/lib/kwalify/types.rb +156 -0
- data/lib/kwalify/util/assert-text-equal.rb +46 -0
- data/lib/kwalify/util/hash-interface.rb +18 -0
- data/lib/kwalify/util/hashlike.rb +51 -0
- data/lib/kwalify/util/option-parser.rb +220 -0
- data/lib/kwalify/util/ordered-hash.rb +57 -0
- data/lib/kwalify/util/testcase-helper.rb +112 -0
- data/lib/kwalify/util.rb +158 -0
- data/lib/kwalify/validator.rb +282 -0
- data/lib/kwalify/yaml-parser.rb +870 -0
- data/lib/kwalify.rb +67 -0
- data/setup.rb +1585 -0
- data/test/Rookbook.yaml +10 -0
- data/test/data/users-guide/AddressBook.java.expected +40 -0
- data/test/data/users-guide/BABEL.data.yaml +24 -0
- data/test/data/users-guide/BABEL.schema.yaml +30 -0
- data/test/data/users-guide/ExampleAddressBook.java +47 -0
- data/test/data/users-guide/Group.java.expected +24 -0
- data/test/data/users-guide/Person.java.expected +44 -0
- data/test/data/users-guide/address_book.rb +52 -0
- data/test/data/users-guide/address_book.schema.yaml +28 -0
- data/test/data/users-guide/address_book.yaml +27 -0
- data/test/data/users-guide/answers-schema.yaml +12 -0
- data/test/data/users-guide/answers-validator.rb +52 -0
- data/test/data/users-guide/babel_genclass.result +26 -0
- data/test/data/users-guide/config.schema.yaml +7 -0
- data/test/data/users-guide/config.yaml +4 -0
- data/test/data/users-guide/document01a.yaml +3 -0
- data/test/data/users-guide/document01b.yaml +3 -0
- data/test/data/users-guide/document02a.yaml +4 -0
- data/test/data/users-guide/document02b.yaml +4 -0
- data/test/data/users-guide/document03a.yaml +6 -0
- data/test/data/users-guide/document03b.yaml +6 -0
- data/test/data/users-guide/document04a.yaml +9 -0
- data/test/data/users-guide/document04b.yaml +9 -0
- data/test/data/users-guide/document05a.yaml +11 -0
- data/test/data/users-guide/document05b.yaml +12 -0
- data/test/data/users-guide/document06a.yaml +15 -0
- data/test/data/users-guide/document06b.yaml +16 -0
- data/test/data/users-guide/document07a.yaml +9 -0
- data/test/data/users-guide/document07b.yaml +7 -0
- data/test/data/users-guide/document12a.json +10 -0
- data/test/data/users-guide/document12b.json +6 -0
- data/test/data/users-guide/document13a.yaml +17 -0
- data/test/data/users-guide/document14a.yaml +3 -0
- data/test/data/users-guide/document14b.yaml +3 -0
- data/test/data/users-guide/document15a.yaml +6 -0
- data/test/data/users-guide/document15b.yaml +5 -0
- data/test/data/users-guide/example_address_book.rb +10 -0
- data/test/data/users-guide/example_address_book_java.result +32 -0
- data/test/data/users-guide/example_address_book_ruby.result +31 -0
- data/test/data/users-guide/genclass_java.result +4 -0
- data/test/data/users-guide/howto-validation-with-parsing.rb +28 -0
- data/test/data/users-guide/howto-validation.rb +25 -0
- data/test/data/users-guide/howto3.rb +6 -0
- data/test/data/users-guide/howto3.result +5 -0
- data/test/data/users-guide/howto3.yaml +8 -0
- data/test/data/users-guide/howto5_databinding.result +111 -0
- data/test/data/users-guide/invalid01.result +3 -0
- data/test/data/users-guide/invalid02.result +5 -0
- data/test/data/users-guide/invalid03.result +5 -0
- data/test/data/users-guide/invalid04.result +4 -0
- data/test/data/users-guide/invalid05.result +11 -0
- data/test/data/users-guide/invalid06.result +4 -0
- data/test/data/users-guide/invalid07.result +3 -0
- data/test/data/users-guide/invalid08.result +3 -0
- data/test/data/users-guide/invalid12.json +8 -0
- data/test/data/users-guide/invalid14.result +4 -0
- data/test/data/users-guide/invalid15.result +4 -0
- data/test/data/users-guide/loadbabel.rb +27 -0
- data/test/data/users-guide/loadconfig.rb +16 -0
- data/test/data/users-guide/loadconfig.result +6 -0
- data/test/data/users-guide/models.rb +22 -0
- data/test/data/users-guide/option_ha.result +6 -0
- data/test/data/users-guide/option_ha_genclass_java.result +7 -0
- data/test/data/users-guide/schema01.yaml +3 -0
- data/test/data/users-guide/schema02.yaml +12 -0
- data/test/data/users-guide/schema03.yaml +9 -0
- data/test/data/users-guide/schema04.yaml +20 -0
- data/test/data/users-guide/schema05.yaml +29 -0
- data/test/data/users-guide/schema06.yaml +11 -0
- data/test/data/users-guide/schema12.json +12 -0
- data/test/data/users-guide/schema13.yaml +13 -0
- data/test/data/users-guide/schema14.yaml +5 -0
- data/test/data/users-guide/schema15.yaml +21 -0
- data/test/data/users-guide/valid01.result +2 -0
- data/test/data/users-guide/valid02.result +2 -0
- data/test/data/users-guide/valid03.result +2 -0
- data/test/data/users-guide/valid04.result +2 -0
- data/test/data/users-guide/valid05.result +2 -0
- data/test/data/users-guide/valid06.result +2 -0
- data/test/data/users-guide/valid07.result +2 -0
- data/test/data/users-guide/valid08.result +2 -0
- data/test/data/users-guide/valid12.result +2 -0
- data/test/data/users-guide/valid13.result +2 -0
- data/test/data/users-guide/valid14.result +2 -0
- data/test/data/users-guide/valid15.result +2 -0
- data/test/data/users-guide/validate08.rb +37 -0
- data/test/test-action.rb +78 -0
- data/test/test-action.yaml +738 -0
- data/test/test-databinding.rb +83 -0
- data/test/test-databinding.yaml +339 -0
- data/test/test-main.rb +157 -0
- data/test/test-main.yaml +415 -0
- data/test/test-metavalidator.rb +80 -0
- data/test/test-metavalidator.yaml +1179 -0
- data/test/test-parser-yaml.rb +57 -0
- data/test/test-parser-yaml.yaml +1749 -0
- data/test/test-rule.rb +26 -0
- data/test/test-rule.yaml +317 -0
- data/test/test-users-guide.rb +75 -0
- data/test/test-util.rb +125 -0
- data/test/test-validator.rb +95 -0
- data/test/test-validator.yaml +986 -0
- data/test/test-yaml-parser.rb +47 -0
- data/test/test-yaml-parser.yaml +1226 -0
- data/test/test.rb +61 -0
- 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 <kwa(at)kuwata-lab.com>">
|
|
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 <kwa(at)kuwata-lab.com><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 <= val && val <= 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 < 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 (< 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>&employee</strong>
|
|
719
|
+
type: map
|
|
720
|
+
mapping:
|
|
721
|
+
"given-name": <strong>&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>&foo</strong>
|
|
736
|
+
given-name: foo
|
|
737
|
+
family-name: Foo
|
|
738
|
+
post: exective
|
|
739
|
+
- <strong>&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"=>10, "B"=>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 (> max 1).
|
|
816
|
+
- (line 3) [/value3] '-2.0': too small (< 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>&a1</strong>
|
|
826
|
+
A: 10
|
|
827
|
+
B: 20
|
|
828
|
+
- <strong><<: *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"=>10, "B"=>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>&name</strong>
|
|
851
|
+
type: str
|
|
852
|
+
required: yes
|
|
853
|
+
"email": <strong>&email</strong>
|
|
854
|
+
type: str
|
|
855
|
+
pattern: /@/
|
|
856
|
+
required: no
|
|
857
|
+
"user":
|
|
858
|
+
type: map
|
|
859
|
+
mapping:
|
|
860
|
+
"name":
|
|
861
|
+
<strong><<: *name</strong> # merge
|
|
862
|
+
<strong>length: { max: 16 }</strong> # add
|
|
863
|
+
"email":
|
|
864
|
+
<strong><<: *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 > 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 && !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 && !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 && !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 < 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 << 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
|
+
- &bar
|
|
1136
|
+
name: Bar
|
|
1137
|
+
parent: *baz # preceding alias
|
|
1138
|
+
- &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"=>"Foo",
|
|
1159
|
+
"parent"=>{"name"=>"Bar", "parent"=>{"name"=>"Baz", "parent"=>nil}}},
|
|
1160
|
+
{"name"=>"Bar", "parent"=>{"name"=>"Baz", "parent"=>nil}},
|
|
1161
|
+
{"name"=>"Baz", "parent"=>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
|
+
#<Config:
|
|
1223
|
+
@host="localhost",
|
|
1224
|
+
@pass="password1",
|
|
1225
|
+
@port=8080,
|
|
1226
|
+
@user="user1">
|
|
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
|
+
- &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
|
+
- &minamoto
|
|
1245
|
+
name: Kohichi Minamoto
|
|
1246
|
+
desc: Scientist
|
|
1247
|
+
team: *thechildren
|
|
1248
|
+
- &kaoru
|
|
1249
|
+
name: Kaoru Akashi
|
|
1250
|
+
desc: Psychokino
|
|
1251
|
+
team: *thechildren
|
|
1252
|
+
- &aoi
|
|
1253
|
+
name: Aoi Nogami
|
|
1254
|
+
desc: Teleporter
|
|
1255
|
+
team: *thechildren
|
|
1256
|
+
- &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
|
+
- &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
|
+
- &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 > 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=>true,
|
|
1341
|
+
:preceding_alias=>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=>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"=>
|
|
1368
|
+
[#<Babel::Team:0x53e0f8
|
|
1369
|
+
@chief=
|
|
1370
|
+
#<Babel::Member:0x53d5e0
|
|
1371
|
+
@desc="Scientist",
|
|
1372
|
+
@name="Kohichi Minamoto",
|
|
1373
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1374
|
+
@desc="Level 7 ESPers",
|
|
1375
|
+
@members=
|
|
1376
|
+
[#<Babel::Member:0x53d018
|
|
1377
|
+
@desc="Psychokino",
|
|
1378
|
+
@name="Kaoru Akashi",
|
|
1379
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1380
|
+
#<Babel::Member:0x53ca50
|
|
1381
|
+
@desc="Teleporter",
|
|
1382
|
+
@name="Aoi Nogami",
|
|
1383
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1384
|
+
#<Babel::Member:0x53c488
|
|
1385
|
+
@desc="Psycometrer",
|
|
1386
|
+
@name="Shiho Sannomiya",
|
|
1387
|
+
@team=#<Babel::Team:0x53e0f8 ...>>],
|
|
1388
|
+
@name="The Children">],
|
|
1389
|
+
"members"=>
|
|
1390
|
+
[#<Babel::Member:0x53d5e0
|
|
1391
|
+
@desc="Scientist",
|
|
1392
|
+
@name="Kohichi Minamoto",
|
|
1393
|
+
@team=
|
|
1394
|
+
#<Babel::Team:0x53e0f8
|
|
1395
|
+
@chief=#<Babel::Member:0x53d5e0 ...>,
|
|
1396
|
+
@desc="Level 7 ESPers",
|
|
1397
|
+
@members=
|
|
1398
|
+
[#<Babel::Member:0x53d018
|
|
1399
|
+
@desc="Psychokino",
|
|
1400
|
+
@name="Kaoru Akashi",
|
|
1401
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1402
|
+
#<Babel::Member:0x53ca50
|
|
1403
|
+
@desc="Teleporter",
|
|
1404
|
+
@name="Aoi Nogami",
|
|
1405
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1406
|
+
#<Babel::Member:0x53c488
|
|
1407
|
+
@desc="Psycometrer",
|
|
1408
|
+
@name="Shiho Sannomiya",
|
|
1409
|
+
@team=#<Babel::Team:0x53e0f8 ...>>],
|
|
1410
|
+
@name="The Children">>,
|
|
1411
|
+
#<Babel::Member:0x53d018
|
|
1412
|
+
@desc="Psychokino",
|
|
1413
|
+
@name="Kaoru Akashi",
|
|
1414
|
+
@team=
|
|
1415
|
+
#<Babel::Team:0x53e0f8
|
|
1416
|
+
@chief=
|
|
1417
|
+
#<Babel::Member:0x53d5e0
|
|
1418
|
+
@desc="Scientist",
|
|
1419
|
+
@name="Kohichi Minamoto",
|
|
1420
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1421
|
+
@desc="Level 7 ESPers",
|
|
1422
|
+
@members=
|
|
1423
|
+
[#<Babel::Member:0x53d018 ...>,
|
|
1424
|
+
#<Babel::Member:0x53ca50
|
|
1425
|
+
@desc="Teleporter",
|
|
1426
|
+
@name="Aoi Nogami",
|
|
1427
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1428
|
+
#<Babel::Member:0x53c488
|
|
1429
|
+
@desc="Psycometrer",
|
|
1430
|
+
@name="Shiho Sannomiya",
|
|
1431
|
+
@team=#<Babel::Team:0x53e0f8 ...>>],
|
|
1432
|
+
@name="The Children">>,
|
|
1433
|
+
#<Babel::Member:0x53ca50
|
|
1434
|
+
@desc="Teleporter",
|
|
1435
|
+
@name="Aoi Nogami",
|
|
1436
|
+
@team=
|
|
1437
|
+
#<Babel::Team:0x53e0f8
|
|
1438
|
+
@chief=
|
|
1439
|
+
#<Babel::Member:0x53d5e0
|
|
1440
|
+
@desc="Scientist",
|
|
1441
|
+
@name="Kohichi Minamoto",
|
|
1442
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1443
|
+
@desc="Level 7 ESPers",
|
|
1444
|
+
@members=
|
|
1445
|
+
[#<Babel::Member:0x53d018
|
|
1446
|
+
@desc="Psychokino",
|
|
1447
|
+
@name="Kaoru Akashi",
|
|
1448
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1449
|
+
#<Babel::Member:0x53ca50 ...>,
|
|
1450
|
+
#<Babel::Member:0x53c488
|
|
1451
|
+
@desc="Psycometrer",
|
|
1452
|
+
@name="Shiho Sannomiya",
|
|
1453
|
+
@team=#<Babel::Team:0x53e0f8 ...>>],
|
|
1454
|
+
@name="The Children">>,
|
|
1455
|
+
#<Babel::Member:0x53c488
|
|
1456
|
+
@desc="Psycometrer",
|
|
1457
|
+
@name="Shiho Sannomiya",
|
|
1458
|
+
@team=
|
|
1459
|
+
#<Babel::Team:0x53e0f8
|
|
1460
|
+
@chief=
|
|
1461
|
+
#<Babel::Member:0x53d5e0
|
|
1462
|
+
@desc="Scientist",
|
|
1463
|
+
@name="Kohichi Minamoto",
|
|
1464
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1465
|
+
@desc="Level 7 ESPers",
|
|
1466
|
+
@members=
|
|
1467
|
+
[#<Babel::Member:0x53d018
|
|
1468
|
+
@desc="Psychokino",
|
|
1469
|
+
@name="Kaoru Akashi",
|
|
1470
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1471
|
+
#<Babel::Member:0x53ca50
|
|
1472
|
+
@desc="Teleporter",
|
|
1473
|
+
@name="Aoi Nogami",
|
|
1474
|
+
@team=#<Babel::Team:0x53e0f8 ...>>,
|
|
1475
|
+
#<Babel::Member:0x53c488 ...>],
|
|
1476
|
+
@name="The Children">>]}
|
|
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 > 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
|
+
[#<Group:0xddf24 @desc="my family", @name="family">,
|
|
1670
|
+
#<Group:0xddf10 @desc="my friends", @name="friend">,
|
|
1671
|
+
#<Group:0xdde84 @desc="those who works together", @name="business">]
|
|
1672
|
+
[#<Person:0xdefdc
|
|
1673
|
+
@birth=#<Date: 4903089/2,0,2299161>,
|
|
1674
|
+
@blood="A",
|
|
1675
|
+
@deleted=false,
|
|
1676
|
+
@desc=nil,
|
|
1677
|
+
@email=nil,
|
|
1678
|
+
@group="family",
|
|
1679
|
+
@name="Sumire",
|
|
1680
|
+
@phone=nil>,
|
|
1681
|
+
#<Person:0xdee9c
|
|
1682
|
+
@birth=#<Date: 4899437/2,0,2299161>,
|
|
1683
|
+
@blood=nil,
|
|
1684
|
+
@deleted=false,
|
|
1685
|
+
@desc=nil,
|
|
1686
|
+
@email="shiina@mail.org",
|
|
1687
|
+
@group="friend",
|
|
1688
|
+
@name="Shiina",
|
|
1689
|
+
@phone=nil>,
|
|
1690
|
+
#<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">]
|
|
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 < 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 < 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>
|