kwalify 0.6.1 → 0.7.0
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 +232 -0
- data/MIT-LICENSE +20 -0
- data/README.txt +16 -19
- data/bin/kwalify +3 -3
- data/contrib/inline-require +6 -4
- data/contrib/kwalify +3719 -2427
- data/doc-api/classes/CommandOptionError.html +17 -17
- data/doc-api/classes/CommandOptionParser.html +63 -63
- data/doc-api/classes/Kwalify.html +29 -7
- data/doc-api/classes/Kwalify/AssertionError.html +9 -9
- data/doc-api/classes/Kwalify/BaseError.html +72 -71
- data/doc-api/classes/Kwalify/BaseParser.html +461 -0
- data/doc-api/classes/Kwalify/CommandOptionError.html +11 -11
- data/doc-api/classes/Kwalify/ErrorHelper.html +51 -46
- data/doc-api/classes/Kwalify/HashInterface.html +13 -135
- data/doc-api/classes/Kwalify/Json.html +105 -0
- data/doc-api/classes/Kwalify/Main.html +129 -126
- data/doc-api/classes/Kwalify/MetaValidator.html +248 -232
- data/doc-api/classes/Kwalify/Parser.html +12 -12
- data/doc-api/classes/Kwalify/PlainYamlParser.html +166 -163
- data/doc-api/classes/Kwalify/PlainYamlParser/Alias.html +11 -11
- data/doc-api/classes/Kwalify/Rule.html +152 -130
- data/doc-api/classes/Kwalify/SchemaError.html +10 -10
- data/doc-api/classes/Kwalify/SyntaxError.html +185 -0
- data/doc-api/classes/Kwalify/Types.html +26 -25
- data/doc-api/classes/Kwalify/Util.html +389 -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/ValidationError.html +10 -10
- data/doc-api/classes/Kwalify/Validator.html +153 -86
- data/doc-api/classes/Kwalify/Yaml.html +181 -0
- data/doc-api/classes/Kwalify/Yaml/Parser.html +1538 -0
- data/doc-api/classes/Kwalify/YamlParser.html +190 -183
- data/doc-api/classes/Kwalify/YamlSyntaxError.html +8 -57
- data/doc-api/created.rid +1 -1
- data/doc-api/files/__/README_txt.html +17 -22
- data/doc-api/files/kwalify/errors_rb.html +2 -2
- data/doc-api/files/kwalify/main_rb.html +4 -3
- data/doc-api/files/kwalify/messages_rb.html +2 -2
- data/doc-api/files/kwalify/meta-validator_rb.html +3 -3
- data/doc-api/files/kwalify/{util/yaml-helper_rb.html → parser/base_rb.html} +8 -6
- data/doc-api/files/kwalify/parser/yaml_rb.html +117 -0
- data/doc-api/files/kwalify/rule_rb.html +2 -2
- data/doc-api/files/kwalify/types_rb.html +2 -2
- data/doc-api/files/kwalify/util/assert-text-equal_rb.html +2 -2
- data/doc-api/files/kwalify/util/hash-interface_rb.html +9 -2
- data/doc-api/files/kwalify/util/hashlike_rb.html +107 -0
- data/doc-api/files/kwalify/util/option-parser_rb.html +2 -2
- data/doc-api/files/kwalify/util/ordered-hash_rb.html +107 -0
- data/doc-api/files/kwalify/util/testcase-helper_rb.html +2 -2
- data/doc-api/files/kwalify/util_rb.html +107 -0
- data/doc-api/files/kwalify/validator_rb.html +2 -2
- data/doc-api/files/kwalify/yaml-parser_rb.html +2 -2
- data/doc-api/files/kwalify_rb.html +3 -2
- data/doc-api/fr_class_index.html +8 -1
- data/doc-api/fr_file_index.html +5 -1
- data/doc-api/fr_method_index.html +128 -69
- data/doc/img/fig01.png +0 -0
- data/doc/users-guide.html +882 -717
- data/examples/address-book/address-book.schema.yaml +2 -2
- 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/invoice.schema.yaml +3 -3
- data/examples/tapkit/tapkit.schema.yaml +2 -2
- data/lib/kwalify.rb +41 -4
- data/lib/kwalify/errors.rb +118 -96
- data/lib/kwalify/kwalify.schema.yaml +58 -0
- data/lib/kwalify/main.rb +384 -377
- data/lib/kwalify/messages.rb +41 -27
- data/lib/kwalify/meta-validator.rb +251 -331
- data/lib/kwalify/parser/base.rb +127 -0
- data/lib/kwalify/parser/yaml.rb +837 -0
- data/lib/kwalify/rule.rb +545 -487
- data/lib/kwalify/templates/genclass-java.eruby +189 -162
- data/lib/kwalify/templates/genclass-php.eruby +104 -0
- data/lib/kwalify/templates/genclass-ruby.eruby +95 -66
- data/lib/kwalify/types.rb +107 -106
- data/lib/kwalify/util.rb +157 -0
- data/lib/kwalify/util/assert-text-equal.rb +33 -31
- data/lib/kwalify/util/hash-interface.rb +11 -30
- data/lib/kwalify/util/hashlike.rb +51 -0
- data/lib/kwalify/util/option-parser.rb +144 -144
- data/lib/kwalify/util/ordered-hash.rb +57 -0
- data/lib/kwalify/util/testcase-helper.rb +3 -3
- data/lib/kwalify/validator.rb +267 -212
- data/lib/kwalify/yaml-parser.rb +822 -768
- data/setup.rb +861 -607
- data/test/Rookbook.yaml +10 -0
- data/test/{tmp.dir/Context.java → data/users-guide/AddressBook.java.expected} +11 -11
- 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/{tmp.dir/Group.java → data/users-guide/Group.java.expected} +2 -11
- 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/{tmp.dir/silent1.document → data/users-guide/document01a.yaml} +0 -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 +15 -0
- data/test/data/users-guide/loadconfig.result +2 -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/{tmp.dir/meta1.schema → data/users-guide/schema01.yaml} +0 -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 +80 -0
- data/test/test-databinding.yaml +301 -0
- data/test/test-main.rb +129 -150
- data/test/test-main.yaml +126 -321
- data/test/test-metavalidator.rb +47 -47
- data/test/test-metavalidator.yaml +77 -21
- data/test/test-parser-yaml.rb +57 -0
- data/test/test-parser-yaml.yaml +1749 -0
- data/test/test-rule.rb +14 -15
- data/test/test-rule.yaml +6 -3
- data/test/test-users-guide.rb +75 -0
- data/test/test-validator.rb +77 -52
- data/test/test-validator.yaml +168 -6
- data/test/test-yaml-parser.rb +47 -0
- data/test/{test-yamlparser.yaml → test-yaml-parser.yaml} +159 -52
- data/test/test.rb +37 -21
- metadata +136 -37
- data/COPYING +0 -340
- data/ChangeLog +0 -70
- data/doc-api/classes/YamlHelper.html +0 -259
- data/lib/kwalify/util/yaml-helper.rb +0 -82
- data/test/test-yamlparser.rb +0 -58
- data/test/tmp.dir/User.java +0 -43
- data/test/tmp.dir/action1.document +0 -18
- data/test/tmp.dir/action1.schema +0 -32
- data/test/tmp.dir/action2.document +0 -18
- data/test/tmp.dir/action2.schema +0 -32
- data/test/tmp.dir/emacs.document +0 -6
- data/test/tmp.dir/emacs.schema +0 -6
- data/test/tmp.dir/meta1.document +0 -0
- data/test/tmp.dir/meta2.document +0 -0
- data/test/tmp.dir/meta2.schema +0 -3
- data/test/tmp.dir/silent1.schema +0 -3
- data/test/tmp.dir/silent2.document +0 -7
- data/test/tmp.dir/silent2.schema +0 -3
- data/test/tmp.dir/stream.invalid +0 -8
- data/test/tmp.dir/stream.schema +0 -3
- data/test/tmp.dir/stream.valid +0 -8
- data/test/tmp.dir/untabify.document +0 -5
- data/test/tmp.dir/untabify.schema +0 -10
- data/todo.txt +0 -34
data/lib/kwalify/rule.rb
CHANGED
@@ -1,501 +1,559 @@
|
|
1
1
|
###
|
2
|
-
### $Rev:
|
3
|
-
### $Release: 0.
|
4
|
-
### copyright(c) 2005 kuwata-lab all rights reserved.
|
2
|
+
### $Rev: 95 $
|
3
|
+
### $Release: 0.7.0 $
|
4
|
+
### copyright(c) 2005-2008 kuwata-lab all rights reserved.
|
5
5
|
###
|
6
6
|
|
7
7
|
require 'kwalify/messages'
|
8
8
|
require 'kwalify/errors'
|
9
9
|
require 'kwalify/types'
|
10
10
|
|
11
|
+
|
11
12
|
module Kwalify
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
unless @type == 'map'
|
108
|
-
#* key=:classname_notmap msg="available only with map type."
|
109
|
-
raise schema_error(:classname_notmap, rule, "#{path}/classname", 'classname:')
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
|
-
def _init_name_value(val, rule, path)
|
115
|
-
@name = val
|
116
|
-
end
|
117
|
-
|
118
|
-
|
119
|
-
def _init_desc_value(val, rule, path)
|
120
|
-
@desc = val
|
121
|
-
end
|
122
|
-
|
123
|
-
|
124
|
-
def _init_required_value(val, rule, path)
|
125
|
-
@required = val
|
126
|
-
unless val.is_a?(Boolean) #|| val == nil
|
127
|
-
#* key=:required_notbool msg="not a boolean."
|
128
|
-
raise schema_error(:required_notbool, rule, "#{path}/required", val)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def _init_pattern_value(val, rule, path)
|
133
|
-
@pattern = val
|
134
|
-
unless val.is_a?(String) || val.is_a?(Regexp)
|
135
|
-
#* key=:pattern_notstr msg="not a string (or regexp)"
|
136
|
-
raise schema_error(:pattern_notstr, rule, "#{path}/pattern", val)
|
137
|
-
end
|
138
|
-
unless val =~ /\A\/(.*)\/([mi]?[mi]?)\z/
|
139
|
-
#* key=:pattern_notmatch msg="should be '/..../'."
|
140
|
-
raise schema_error(:pattern_notmatch, rule, "#{path}/pattern", val)
|
141
|
-
end
|
142
|
-
pat = $1; opt = $2
|
143
|
-
flag = 0
|
144
|
-
flag += Regexp::IGNORECASE if opt.include?("i")
|
145
|
-
flag += Regexp::MULTILINE if opt.include?("m")
|
146
|
-
begin
|
147
|
-
@regexp = Regexp.compile(pat, flag)
|
148
|
-
rescue RegexpError => ex
|
149
|
-
#* key=:pattern_syntaxerr msg="has regexp error."
|
150
|
-
raise schema_error(:pattern_syntaxerr, rule, "#{path}/pattern", val)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
|
155
|
-
def _init_enum_value(val, rule, path)
|
156
|
-
@enum = val
|
157
|
-
unless val.is_a?(Array)
|
158
|
-
#* key=:enum_notseq msg="not a sequence."
|
159
|
-
raise schema_error(:enum_notseq, rule, "#{path}/enum", val)
|
160
|
-
end
|
161
|
-
if Types.collection_type?(@type) # unless Kwalify.scalar_class?(@type_class)
|
162
|
-
#* key=:enum_notscalar msg="not available with seq or map."
|
163
|
-
raise schema_error(:enum_notscalar, rule, path, 'enum:')
|
164
|
-
end
|
165
|
-
elem_table = {}
|
166
|
-
@enum.each do |elem|
|
167
|
-
unless elem.is_a?(@type_class)
|
168
|
-
#* key=:enum_type_unmatch msg="%s type expected."
|
169
|
-
raise schema_error(:enum_type_unmatch, rule, "#{path}/enum", elem, [Kwalify.word(@type)])
|
170
|
-
end
|
171
|
-
if elem_table[elem]
|
172
|
-
#* key=:enum_duplicate msg="duplicated enum value."
|
173
|
-
raise schema_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s)
|
174
|
-
end
|
175
|
-
elem_table[elem] = true
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
|
180
|
-
def _init_assert_value(val, rule, path)
|
181
|
-
@assert = val
|
182
|
-
unless val.is_a?(String)
|
183
|
-
#* key=:assert_notstr msg="not a string."
|
184
|
-
raise schema_error(:assert_notstr, rule, "#{path}/assert", val)
|
185
|
-
end
|
186
|
-
unless val =~ /\bval\b/
|
187
|
-
#* key=:assert_noval msg="'val' is not used."
|
188
|
-
raise schema_error(:assert_noval, rule, "#{path}/assert", val)
|
189
|
-
end
|
190
|
-
begin
|
191
|
-
@assert_proc = eval "proc { |val| #{val} }"
|
192
|
-
rescue SyntaxError => ex
|
193
|
-
#* key=:assert_syntaxerr msg="expression syntax error."
|
194
|
-
raise schema_error(:assert_syntaxerr, rule, "#{path}/assert", val)
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
|
199
|
-
def _init_range_value(val, rule, path)
|
200
|
-
@range = val
|
201
|
-
curr_path = "#{path}/range"
|
202
|
-
unless val.is_a?(Hash)
|
203
|
-
#* key=:range_notmap msg="not a mapping."
|
204
|
-
raise schema_error(:range_notmap, rule, curr_path, val)
|
205
|
-
end
|
206
|
-
if Types.collection_type?(@type) || @type == 'bool'
|
207
|
-
#* key=:range_notscalar msg="is available only with scalar type."
|
208
|
-
raise schema_error(:range_notscalar, rule, path, 'range:')
|
209
|
-
end
|
210
|
-
val.each do |k, v|
|
211
|
-
case k
|
212
|
-
when 'max', 'min', 'max-ex', 'min-ex'
|
213
|
-
unless v.is_a?(@type_class)
|
214
|
-
typename = Kwalify.word(@type) || @type
|
215
|
-
#* key=:range_type_unmatch msg="not a %s."
|
216
|
-
raise schema_error(:range_type_unmatch, rule, "#{curr_path}/#{k}", v, [typename])
|
217
|
-
end
|
218
|
-
else
|
219
|
-
#* key=:range_undefined msg="undefined key."
|
220
|
-
raise schema_error(:range_undefined, rule, "#{curr_path}/#{k}", "#{k}:")
|
221
|
-
end
|
222
|
-
end
|
223
|
-
if val.key?('max') && val.key?('max-ex')
|
224
|
-
#* key=:range_twomax msg="both 'max' and 'max-ex' are not available at once."
|
225
|
-
raise schema_error(:range_twomax, rule, curr_path, nil)
|
226
|
-
end
|
227
|
-
if val.key?('min') && val.key?('min-ex')
|
228
|
-
#* key=:range_twomin msg="both 'min' and 'min-ex' are not available at once."
|
229
|
-
raise schema_error(:range_twomin, rule, curr_path, nil)
|
230
|
-
end
|
231
|
-
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
232
|
-
if max
|
233
|
-
if min && max < min
|
234
|
-
#* key=:range_maxltmin msg="max '%s' is less than min '%s'."
|
235
|
-
raise validate_error(:range_maxltmin, rule, curr_path, nil, [max, min])
|
236
|
-
elsif min_ex && max <= min_ex
|
237
|
-
#* key=:range_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
|
238
|
-
raise validate_error(:range_maxleminex, rule, curr_path, nil, [max, min_ex])
|
239
|
-
end
|
240
|
-
elsif max_ex
|
241
|
-
if min && max_ex <= min
|
242
|
-
#* key=:range_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
|
243
|
-
raise validate_error(:range_maxexlemin, rule, curr_path, nil, [max_ex, min])
|
244
|
-
elsif min_ex && max_ex <= min_ex
|
245
|
-
#* key=:range_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
|
246
|
-
raise validate_error(:range_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
|
252
|
-
def _init_length_value(val, rule, path)
|
253
|
-
@length = val
|
254
|
-
curr_path = "#{path}/length"
|
255
|
-
unless val.is_a?(Hash)
|
256
|
-
#* key=:length_notmap msg="not a mapping."
|
257
|
-
raise schema_error(:length_notmap, rule, curr_path, val)
|
258
|
-
end
|
259
|
-
unless @type == 'str' || @type == 'text'
|
260
|
-
#* key=:length_nottext msg="is available only with string or text."
|
261
|
-
raise schema_error(:length_nottext, rule, path, 'length:')
|
262
|
-
end
|
263
|
-
val.each do |k, v|
|
264
|
-
case k
|
265
|
-
when 'max', 'min', 'max-ex', 'min-ex'
|
266
|
-
unless v.is_a?(Integer)
|
267
|
-
#* key=:length_notint msg="not an integer."
|
268
|
-
raise schema_error(:length_notint, rule, "#{curr_path}/#{k}", v)
|
269
|
-
end
|
270
|
-
else
|
271
|
-
#* key=:length_undefined msg="undefined key."
|
272
|
-
raise schema_error(:length_undefined, rule, "#{curr_path}/#{k}", "#{k}:")
|
273
|
-
end
|
274
|
-
end
|
275
|
-
if val.key?('max') && val.key?('max-ex')
|
276
|
-
#* key=:length_twomax msg="both 'max' and 'max-ex' are not available at once."
|
277
|
-
raise schema_error(:length_twomax, rule, curr_path, nil)
|
278
|
-
end
|
279
|
-
if val.key?('min') && val.key?('min-ex')
|
280
|
-
#* key=:length_twomin msg="both 'min' and 'min-ex' are not available at once."
|
281
|
-
raise schema_error(:length_twomin, rule, curr_path, nil)
|
282
|
-
end
|
283
|
-
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
284
|
-
if max
|
285
|
-
if min && max < min
|
286
|
-
#* key=:length_maxltmin msg="max '%s' is less than min '%s'."
|
287
|
-
raise validate_error(:length_maxltmin, rule, curr_path, nil, [max, min])
|
288
|
-
elsif min_ex && max <= min_ex
|
289
|
-
#* key=:length_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
|
290
|
-
raise validate_error(:length_maxleminex, rule, curr_path, nil, [max, min_ex])
|
291
|
-
end
|
292
|
-
elsif max_ex
|
293
|
-
if min && max_ex <= min
|
294
|
-
#* key=:length_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
|
295
|
-
raise validate_error(:length_maxexlemin, rule, curr_path, nil, [max_ex, min])
|
296
|
-
elsif min_ex && max_ex <= min_ex
|
297
|
-
#* key=:length_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
|
298
|
-
raise validate_error(:length_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
|
304
|
-
def _init_ident_value(val, rule, path)
|
305
|
-
@ident = val
|
306
|
-
@required = true
|
307
|
-
unless val.is_a?(Boolean)
|
308
|
-
#* key=:ident_notbool msg="not a boolean."
|
309
|
-
raise schema_error(:ident_notbool, rule, "#{path}/ident", val)
|
310
|
-
end
|
311
|
-
if @type == 'map' || @type == 'seq'
|
312
|
-
#* key=:ident_notscalar msg="is available only with a scalar type."
|
313
|
-
raise schema_error(:ident_notscalar, rule, path, "ident:")
|
314
|
-
end
|
315
|
-
if path.empty?
|
316
|
-
#* key=:ident_onroot msg="is not available on root element."
|
317
|
-
raise schema_error(:ident_onroot, rule, "/", "ident:")
|
318
|
-
end
|
319
|
-
unless @parent && @parent.type == 'map'
|
320
|
-
#* key=:ident_notmap msg="is available only with an element of mapping."
|
321
|
-
raise schema_error(:ident_notmap, rule, path, "ident:")
|
322
|
-
end
|
323
|
-
end
|
324
|
-
|
325
|
-
|
326
|
-
def _init_unique_value(val, rule, path)
|
327
|
-
@unique = val
|
328
|
-
unless val.is_a?(Boolean)
|
329
|
-
#* key=:unique_notbool msg="not a boolean."
|
330
|
-
raise schema_error(:unique_notbool, rule, "#{path}/unique", val)
|
331
|
-
end
|
332
|
-
if @type == 'map' || @type == 'seq'
|
333
|
-
#* key=:unique_notscalar msg="is available only with a scalar type."
|
334
|
-
raise schema_error(:unique_notscalar, rule, path, "unique:")
|
335
|
-
end
|
336
|
-
if path.empty?
|
337
|
-
#* key=:unique_onroot msg="is not available on root element."
|
338
|
-
raise schema_error(:unique_onroot, rule, "/", "unique:")
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
|
343
|
-
def _init_sequence_value(val, rule, path, rule_table)
|
344
|
-
if val != nil && !val.is_a?(Array)
|
345
|
-
#* key=:sequence_notseq msg="not a sequence."
|
346
|
-
raise schema_error(:sequence_notseq, rule, "#{path}/sequence", val)
|
347
|
-
elsif val == nil || val.empty?
|
348
|
-
#* key=:sequence_noelem msg="required one element."
|
349
|
-
raise schema_error(:sequence_noelem, rule, "#{path}/sequence", val)
|
350
|
-
elsif val.length > 1
|
351
|
-
#* key=:sequence_toomany msg="required just one element."
|
352
|
-
raise schema_error(:sequence_toomany, rule, "#{path}/sequence", val)
|
353
|
-
else
|
354
|
-
elem = val[0]
|
355
|
-
elem ||= {}
|
356
|
-
i = 0 # or 1? *index*
|
357
|
-
rule = rule_table[elem.__id__]
|
358
|
-
rule ||= Rule.new(nil, self).init(elem, "#{path}/sequence/#{i}", rule_table)
|
359
|
-
@sequence = [ rule ]
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
|
364
|
-
def _init_mapping_value(val, rule, path, rule_table)
|
365
|
-
if val != nil && !val.is_a?(Hash)
|
366
|
-
#* key=:mapping_notmap msg="not a mapping."
|
367
|
-
raise schema_error(:mapping_notmap, rule, "#{path}/mapping", val)
|
368
|
-
elsif val == nil || (val.empty? && !val.default)
|
369
|
-
#* key=:mapping_noelem msg="required at least one element."
|
370
|
-
raise schema_error(:mapping_noelem, rule, "#{path}/mapping", val)
|
371
|
-
else
|
372
|
-
@mapping = {}
|
373
|
-
if val.default
|
374
|
-
elem = val.default # hash
|
375
|
-
rule = rule_table[elem.__id__]
|
376
|
-
rule ||= Rule.new(nil, self).init(elem, "#{path}/mapping/=", rule_table)
|
377
|
-
@mapping.default = rule
|
378
|
-
end
|
379
|
-
val.each do |k, v|
|
380
|
-
##* key=:key_duplicate msg="key duplicated."
|
381
|
-
#raise schema_error(:key_duplicate, rule, "#{path}/mapping", key) if @mapping.key?(key)
|
382
|
-
v ||= {}
|
383
|
-
rule = rule_table[v.__id__]
|
384
|
-
rule ||= Rule.new(nil, self).init(v, "#{path}/mapping/#{k}", rule_table)
|
385
|
-
if k == '='
|
386
|
-
@mapping.default = rule
|
387
|
-
else
|
388
|
-
@mapping[k] = rule
|
389
|
-
end
|
390
|
-
end if val
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
|
395
|
-
def check_confliction(hash, rule, path)
|
396
|
-
if @type == 'seq'
|
397
|
-
#* key=:seq_nosequence msg="type 'seq' requires 'sequence:'."
|
398
|
-
raise schema_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
|
399
|
-
#* key=:seq_conflict msg="not available with sequence."
|
400
|
-
raise schema_error(:seq_conflict, rule, path, 'enum:') if @enum
|
401
|
-
raise schema_error(:seq_conflict, rule, path, 'pattern:') if @pattern
|
402
|
-
raise schema_error(:seq_conflict, rule, path, 'mapping:') if @mapping
|
403
|
-
raise schema_error(:seq_conflict, rule, path, 'range:') if @range
|
404
|
-
raise schema_error(:seq_conflict, rule, path, 'length:') if @length
|
405
|
-
elsif @type == 'map'
|
406
|
-
#* key=:map_nomapping msg="type 'map' requires 'mapping:'."
|
407
|
-
raise schema_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping')
|
408
|
-
#* key=:map_conflict msg="not available with mapping."
|
409
|
-
raise schema_error(:map_conflict, rule, path, 'enum:') if @enum
|
410
|
-
raise schema_error(:map_conflict, rule, path, 'pattern:') if @pattern
|
411
|
-
raise schema_error(:map_conflict, rule, path, 'sequence:') if @sequence
|
412
|
-
raise schema_error(:map_conflict, rule, path, 'range:') if @range
|
413
|
-
raise schema_error(:map_conflict, rule, path, 'length:') if @length
|
414
|
-
else
|
415
|
-
#* key=:scalar_conflict msg="not available with scalar type."
|
416
|
-
raise schema_error(:scalar_conflict, rule, path, 'sequence:') if @sequence
|
417
|
-
raise schema_error(:scalar_conflict, rule, path, 'mapping:') if @mapping
|
418
|
-
if @enum
|
419
|
-
#* key=:enum_conflict msg="not available with 'enum:'."
|
420
|
-
raise schema_error(:enum_conflict, rule, path, 'range:') if @range
|
421
|
-
raise schema_error(:enum_conflict, rule, path, 'length:') if @length
|
422
|
-
raise schema_error(:enum_conflict, rule, path, 'pattern:') if @pattern
|
423
|
-
end
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
#def inspect()
|
428
|
-
# str = ""; level = 0; done = {}
|
429
|
-
# _inspect(str, level, done)
|
430
|
-
# return str
|
14
|
+
|
15
|
+
class Rule
|
16
|
+
include Kwalify::ErrorHelper
|
17
|
+
|
18
|
+
attr_accessor :parent
|
19
|
+
attr_reader :name
|
20
|
+
attr_reader :desc
|
21
|
+
attr_reader :enum
|
22
|
+
attr_reader :required
|
23
|
+
attr_reader :type
|
24
|
+
attr_reader :type_class
|
25
|
+
attr_reader :pattern
|
26
|
+
attr_reader :regexp
|
27
|
+
attr_reader :sequence
|
28
|
+
attr_reader :mapping
|
29
|
+
attr_reader :assert
|
30
|
+
attr_reader :assert_proc
|
31
|
+
attr_reader :range
|
32
|
+
attr_reader :length
|
33
|
+
attr_reader :ident
|
34
|
+
attr_reader :unique
|
35
|
+
attr_reader :default
|
36
|
+
attr_reader :classname
|
37
|
+
attr_reader :classobj
|
38
|
+
|
39
|
+
|
40
|
+
def initialize(hash=nil, parent=nil)
|
41
|
+
_init(hash, "", {}) if hash
|
42
|
+
@parent = parent
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def _init(hash, path="", rule_table={})
|
47
|
+
unless hash.is_a?(Hash)
|
48
|
+
#* key=:schema_notmap msg="schema definition is not a mapping."
|
49
|
+
raise Kwalify.schema_error(:schema_notmap, nil, (!path || path.empty? ? "/" : path), nil)
|
50
|
+
end
|
51
|
+
rule = self
|
52
|
+
rule_table[hash.__id__] = rule
|
53
|
+
## 'type:' entry
|
54
|
+
curr_path = "#{path}/type"
|
55
|
+
_init_type_value(hash['type'], rule, curr_path)
|
56
|
+
## other entries
|
57
|
+
hash.each do |key, val|
|
58
|
+
curr_path = "#{path}/#{key}"
|
59
|
+
sym = key.intern
|
60
|
+
method = get_init_method(sym)
|
61
|
+
unless method
|
62
|
+
#* key=:key_unknown msg="unknown key."
|
63
|
+
raise schema_error(:key_unknown, rule, curr_path, "#{key}:")
|
64
|
+
end
|
65
|
+
if sym == :sequence || sym == :mapping
|
66
|
+
__send__(method, val, rule, curr_path, rule_table)
|
67
|
+
else
|
68
|
+
__send__(method, val, rule, curr_path)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
_check_confliction(hash, rule, path)
|
72
|
+
return self
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
keys = %w[type name desc required pattern enum assert range length
|
77
|
+
ident unique default sequence mapping class]
|
78
|
+
#table = keys.inject({}) {|h, k| h[k.intern] = "_init_#{k}_value".intern; h }
|
79
|
+
table = {}; keys.each {|k| table[k.intern] = "_init_#{k}_value".intern }
|
80
|
+
@@dispatch_table = table
|
81
|
+
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
|
86
|
+
def get_init_method(sym)
|
87
|
+
@_dispatch_table ||= @@dispatch_table
|
88
|
+
return @_dispatch_table[sym]
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
|
95
|
+
def _init_type_value(val, rule, path)
|
96
|
+
@type = val
|
97
|
+
@type = Types::DEFAULT_TYPE if @type.nil?
|
98
|
+
unless @type.is_a?(String)
|
99
|
+
#* key=:type_notstr msg="not a string."
|
100
|
+
raise schema_error(:type_notstr, rule, path, @type.to_s)
|
101
|
+
end
|
102
|
+
@type_class = Types.type_class(@type)
|
103
|
+
#if @type_class.nil?
|
104
|
+
# begin
|
105
|
+
# @type_class = Kernel.const_get(@type)
|
106
|
+
# rescue NameError
|
107
|
+
# end
|
431
108
|
#end
|
109
|
+
unless @type_class
|
110
|
+
#* key=:type_unknown msg="unknown type."
|
111
|
+
raise schema_error(:type_unknown, rule, path, @type.to_s)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def _init_class_value(val, rule, path)
|
117
|
+
@classname = val
|
118
|
+
unless @type == 'map'
|
119
|
+
#* key=:class_notmap msg="available only with map type."
|
120
|
+
raise schema_error(:class_notmap, rule, path, 'class:')
|
121
|
+
end
|
122
|
+
begin
|
123
|
+
@classobj = Util.get_class(val)
|
124
|
+
rescue NameError
|
125
|
+
@classobj = nil
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def _init_name_value(val, rule, path)
|
131
|
+
@name = val
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def _init_desc_value(val, rule, path)
|
136
|
+
@desc = val
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
def _init_required_value(val, rule, path)
|
141
|
+
@required = val
|
142
|
+
unless val.is_a?(Boolean) #|| val.nil?
|
143
|
+
#* key=:required_notbool msg="not a boolean."
|
144
|
+
raise schema_error(:required_notbool, rule, path, val)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def _init_pattern_value(val, rule, path)
|
150
|
+
@pattern = val
|
151
|
+
unless val.is_a?(String) || val.is_a?(Regexp)
|
152
|
+
#* key=:pattern_notstr msg="not a string (or regexp)"
|
153
|
+
raise schema_error(:pattern_notstr, rule, path, val)
|
154
|
+
end
|
155
|
+
unless val =~ /\A\/(.*)\/([mi]?[mi]?)\z/
|
156
|
+
#* key=:pattern_notmatch msg="should be '/..../'."
|
157
|
+
raise schema_error(:pattern_notmatch, rule, path, val)
|
158
|
+
end
|
159
|
+
pat = $1; opt = $2
|
160
|
+
flag = 0
|
161
|
+
flag += Regexp::IGNORECASE if opt.include?("i")
|
162
|
+
flag += Regexp::MULTILINE if opt.include?("m")
|
163
|
+
begin
|
164
|
+
@regexp = Regexp.compile(pat, flag)
|
165
|
+
rescue RegexpError => ex
|
166
|
+
#* key=:pattern_syntaxerr msg="has regexp error."
|
167
|
+
raise schema_error(:pattern_syntaxerr, rule, path, val)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
def _init_enum_value(val, rule, path)
|
173
|
+
@enum = val
|
174
|
+
unless val.is_a?(Array)
|
175
|
+
#* key=:enum_notseq msg="not a sequence."
|
176
|
+
raise schema_error(:enum_notseq, rule, path, val)
|
177
|
+
end
|
178
|
+
if Types.collection_type?(@type) # unless Kwalify.scalar_class?(@type_class)
|
179
|
+
#* key=:enum_notscalar msg="not available with seq or map."
|
180
|
+
raise schema_error(:enum_notscalar, rule, File.dirname(path), 'enum:')
|
181
|
+
end
|
182
|
+
elem_table = {}
|
183
|
+
@enum.each do |elem|
|
184
|
+
unless elem.is_a?(@type_class)
|
185
|
+
#* key=:enum_type_unmatch msg="%s type expected."
|
186
|
+
raise schema_error(:enum_type_unmatch, rule, path, elem, [Kwalify.word(@type)])
|
187
|
+
end
|
188
|
+
if elem_table[elem]
|
189
|
+
#* key=:enum_duplicate msg="duplicated enum value."
|
190
|
+
raise schema_error(:enum_duplicate, rule, path, elem.to_s)
|
191
|
+
end
|
192
|
+
elem_table[elem] = true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
def _init_assert_value(val, rule, path)
|
198
|
+
@assert = val
|
199
|
+
unless val.is_a?(String)
|
200
|
+
#* key=:assert_notstr msg="not a string."
|
201
|
+
raise schema_error(:assert_notstr, rule, path, val)
|
202
|
+
end
|
203
|
+
unless val =~ /\bval\b/
|
204
|
+
#* key=:assert_noval msg="'val' is not used."
|
205
|
+
raise schema_error(:assert_noval, rule, path, val)
|
206
|
+
end
|
207
|
+
begin
|
208
|
+
@assert_proc = eval "proc { |val| #{val} }"
|
209
|
+
rescue ::SyntaxError => ex
|
210
|
+
#* key=:assert_syntaxerr msg="expression syntax error."
|
211
|
+
raise schema_error(:assert_syntaxerr, rule, path, val)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
def _init_range_value(val, rule, path)
|
217
|
+
@range = val
|
218
|
+
unless val.is_a?(Hash)
|
219
|
+
#* key=:range_notmap msg="not a mapping."
|
220
|
+
raise schema_error(:range_notmap, rule, path, val)
|
221
|
+
end
|
222
|
+
if Types.collection_type?(@type) || @type == 'bool'
|
223
|
+
#* key=:range_notscalar msg="is available only with scalar type."
|
224
|
+
raise schema_error(:range_notscalar, rule, File.dirname(path), 'range:')
|
225
|
+
end
|
226
|
+
val.each do |k, v|
|
227
|
+
case k
|
228
|
+
when 'max', 'min', 'max-ex', 'min-ex'
|
229
|
+
unless v.is_a?(@type_class)
|
230
|
+
typename = Kwalify.word(@type) || @type
|
231
|
+
#* key=:range_type_unmatch msg="not a %s."
|
232
|
+
raise schema_error(:range_type_unmatch, rule, "#{path}/#{k}", v, [typename])
|
233
|
+
end
|
234
|
+
else
|
235
|
+
#* key=:range_undefined msg="undefined key."
|
236
|
+
raise schema_error(:range_undefined, rule, "#{path}/#{k}", "#{k}:")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
if val.key?('max') && val.key?('max-ex')
|
240
|
+
#* key=:range_twomax msg="both 'max' and 'max-ex' are not available at once."
|
241
|
+
raise schema_error(:range_twomax, rule, path, nil)
|
242
|
+
end
|
243
|
+
if val.key?('min') && val.key?('min-ex')
|
244
|
+
#* key=:range_twomin msg="both 'min' and 'min-ex' are not available at once."
|
245
|
+
raise schema_error(:range_twomin, rule, path, nil)
|
246
|
+
end
|
247
|
+
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
248
|
+
if max
|
249
|
+
if min && max < min
|
250
|
+
#* key=:range_maxltmin msg="max '%s' is less than min '%s'."
|
251
|
+
raise validate_error(:range_maxltmin, rule, path, nil, [max, min])
|
252
|
+
elsif min_ex && max <= min_ex
|
253
|
+
#* key=:range_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
|
254
|
+
raise validate_error(:range_maxleminex, rule, path, nil, [max, min_ex])
|
255
|
+
end
|
256
|
+
elsif max_ex
|
257
|
+
if min && max_ex <= min
|
258
|
+
#* key=:range_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
|
259
|
+
raise validate_error(:range_maxexlemin, rule, path, nil, [max_ex, min])
|
260
|
+
elsif min_ex && max_ex <= min_ex
|
261
|
+
#* key=:range_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
|
262
|
+
raise validate_error(:range_maxexleminex, rule, path, nil, [max_ex, min_ex])
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
def _init_length_value(val, rule, path)
|
269
|
+
@length = val
|
270
|
+
unless val.is_a?(Hash)
|
271
|
+
#* key=:length_notmap msg="not a mapping."
|
272
|
+
raise schema_error(:length_notmap, rule, path, val)
|
273
|
+
end
|
274
|
+
unless @type == 'str' || @type == 'text'
|
275
|
+
#* key=:length_nottext msg="is available only with string or text."
|
276
|
+
raise schema_error(:length_nottext, rule, File.dirname(path), 'length:')
|
277
|
+
end
|
278
|
+
val.each do |k, v|
|
279
|
+
case k
|
280
|
+
when 'max', 'min', 'max-ex', 'min-ex'
|
281
|
+
unless v.is_a?(Integer)
|
282
|
+
#* key=:length_notint msg="not an integer."
|
283
|
+
raise schema_error(:length_notint, rule, "#{path}/#{k}", v)
|
284
|
+
end
|
285
|
+
else
|
286
|
+
#* key=:length_undefined msg="undefined key."
|
287
|
+
raise schema_error(:length_undefined, rule, "#{path}/#{k}", "#{k}:")
|
288
|
+
end
|
289
|
+
end
|
290
|
+
if val.key?('max') && val.key?('max-ex')
|
291
|
+
#* key=:length_twomax msg="both 'max' and 'max-ex' are not available at once."
|
292
|
+
raise schema_error(:length_twomax, rule, path, nil)
|
293
|
+
end
|
294
|
+
if val.key?('min') && val.key?('min-ex')
|
295
|
+
#* key=:length_twomin msg="both 'min' and 'min-ex' are not available at once."
|
296
|
+
raise schema_error(:length_twomin, rule, path, nil)
|
297
|
+
end
|
298
|
+
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
299
|
+
if max
|
300
|
+
if min && max < min
|
301
|
+
#* key=:length_maxltmin msg="max '%s' is less than min '%s'."
|
302
|
+
raise validate_error(:length_maxltmin, rule, path, nil, [max, min])
|
303
|
+
elsif min_ex && max <= min_ex
|
304
|
+
#* key=:length_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
|
305
|
+
raise validate_error(:length_maxleminex, rule, path, nil, [max, min_ex])
|
306
|
+
end
|
307
|
+
elsif max_ex
|
308
|
+
if min && max_ex <= min
|
309
|
+
#* key=:length_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
|
310
|
+
raise validate_error(:length_maxexlemin, rule, path, nil, [max_ex, min])
|
311
|
+
elsif min_ex && max_ex <= min_ex
|
312
|
+
#* key=:length_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
|
313
|
+
raise validate_error(:length_maxexleminex, rule, path, nil, [max_ex, min_ex])
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
|
319
|
+
def _init_ident_value(val, rule, path)
|
320
|
+
@ident = val
|
321
|
+
@required = true
|
322
|
+
unless val.is_a?(Boolean)
|
323
|
+
#* key=:ident_notbool msg="not a boolean."
|
324
|
+
raise schema_error(:ident_notbool, rule, path, val)
|
325
|
+
end
|
326
|
+
if @type == 'map' || @type == 'seq'
|
327
|
+
#* key=:ident_notscalar msg="is available only with a scalar type."
|
328
|
+
raise schema_error(:ident_notscalar, rule, File.dirname(path), "ident:")
|
329
|
+
end
|
330
|
+
if File.dirname(path) == "/"
|
331
|
+
#* key=:ident_onroot msg="is not available on root element."
|
332
|
+
raise schema_error(:ident_onroot, rule, "/", "ident:")
|
333
|
+
end
|
334
|
+
unless @parent && @parent.type == 'map'
|
335
|
+
#* key=:ident_notmap msg="is available only with an element of mapping."
|
336
|
+
raise schema_error(:ident_notmap, rule, File.dirname(path), "ident:")
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
|
341
|
+
def _init_unique_value(val, rule, path)
|
342
|
+
@unique = val
|
343
|
+
unless val.is_a?(Boolean)
|
344
|
+
#* key=:unique_notbool msg="not a boolean."
|
345
|
+
raise schema_error(:unique_notbool, rule, path, val)
|
346
|
+
end
|
347
|
+
if @type == 'map' || @type == 'seq'
|
348
|
+
#* key=:unique_notscalar msg="is available only with a scalar type."
|
349
|
+
raise schema_error(:unique_notscalar, rule, File.dirname(path), "unique:")
|
350
|
+
end
|
351
|
+
if File.dirname(path) == "/"
|
352
|
+
#* key=:unique_onroot msg="is not available on root element."
|
353
|
+
raise schema_error(:unique_onroot, rule, "/", "unique:")
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
|
358
|
+
def _init_default_value(val, rule, path)
|
359
|
+
@default = val
|
360
|
+
unless Types.scalar?(val)
|
361
|
+
#* key=:default_nonscalarval msg="not a scalar."
|
362
|
+
raise schema_error(:default_nonscalarval, rule, path, val)
|
363
|
+
end
|
364
|
+
if @type == 'map' || @type == 'seq'
|
365
|
+
#* key=:default_notscalar msg="is available only with a scalar type."
|
366
|
+
raise schema_error(:default_notscalar, rule, File.dirname(path), "default:")
|
367
|
+
end
|
368
|
+
unless val.nil? || val.is_a?(@type_class)
|
369
|
+
#* key=:default_unmatch msg="not a %s."
|
370
|
+
raise schema_error(:default_unmatch, rule, path, val, [Kwalify.word(@type)])
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
|
375
|
+
def _init_sequence_value(val, rule, path, rule_table)
|
376
|
+
if !val.nil? && !val.is_a?(Array)
|
377
|
+
#* key=:sequence_notseq msg="not a sequence."
|
378
|
+
raise schema_error(:sequence_notseq, rule, path, val)
|
379
|
+
elsif val.nil? || val.empty?
|
380
|
+
#* key=:sequence_noelem msg="required one element."
|
381
|
+
raise schema_error(:sequence_noelem, rule, path, val)
|
382
|
+
elsif val.length > 1
|
383
|
+
#* key=:sequence_toomany msg="required just one element."
|
384
|
+
raise schema_error(:sequence_toomany, rule, path, val)
|
385
|
+
else
|
386
|
+
elem = val[0]
|
387
|
+
elem ||= {}
|
388
|
+
i = 0 # or 1? *index*
|
389
|
+
rule = rule_table[elem.__id__]
|
390
|
+
rule ||= Rule.new(nil, self)._init(elem, "#{path}/#{i}", rule_table)
|
391
|
+
@sequence = [ rule ]
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
def _init_mapping_value(val, rule, path, rule_table)
|
397
|
+
if !val.nil? && !val.is_a?(Hash)
|
398
|
+
#* key=:mapping_notmap msg="not a mapping."
|
399
|
+
raise schema_error(:mapping_notmap, rule, path, val)
|
400
|
+
elsif val.nil? || (val.empty? && !val.default)
|
401
|
+
#* key=:mapping_noelem msg="required at least one element."
|
402
|
+
raise schema_error(:mapping_noelem, rule, path, val)
|
403
|
+
else
|
404
|
+
@mapping = {}
|
405
|
+
if val.default
|
406
|
+
elem = val.default # hash
|
407
|
+
rule = rule_table[elem.__id__]
|
408
|
+
rule ||= Rule.new(nil, self)._init(elem, "#{path}/=", rule_table)
|
409
|
+
@mapping.default = rule
|
410
|
+
end
|
411
|
+
val.each do |k, v|
|
412
|
+
##* key=:key_duplicate msg="key duplicated."
|
413
|
+
#raise schema_error(:key_duplicate, rule, path, key) if @mapping.key?(key)
|
414
|
+
v ||= {}
|
415
|
+
rule = rule_table[v.__id__]
|
416
|
+
rule ||= Rule.new(nil, self)._init(v, "#{path}/#{k}", rule_table)
|
417
|
+
if k == '='
|
418
|
+
@mapping.default = rule
|
419
|
+
else
|
420
|
+
@mapping[k] = rule
|
421
|
+
end
|
422
|
+
end if val
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
|
427
|
+
def _check_confliction(hash, rule, path)
|
428
|
+
if @type == 'seq'
|
429
|
+
#* key=:seq_nosequence msg="type 'seq' requires 'sequence:'."
|
430
|
+
raise schema_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
|
431
|
+
#* key=:seq_conflict msg="not available with sequence."
|
432
|
+
raise schema_error(:seq_conflict, rule, path, 'enum:') if @enum
|
433
|
+
raise schema_error(:seq_conflict, rule, path, 'pattern:') if @pattern
|
434
|
+
raise schema_error(:seq_conflict, rule, path, 'mapping:') if @mapping
|
435
|
+
raise schema_error(:seq_conflict, rule, path, 'range:') if @range
|
436
|
+
raise schema_error(:seq_conflict, rule, path, 'length:') if @length
|
437
|
+
elsif @type == 'map'
|
438
|
+
#* key=:map_nomapping msg="type 'map' requires 'mapping:'."
|
439
|
+
raise schema_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping')
|
440
|
+
#* key=:map_conflict msg="not available with mapping."
|
441
|
+
raise schema_error(:map_conflict, rule, path, 'enum:') if @enum
|
442
|
+
raise schema_error(:map_conflict, rule, path, 'pattern:') if @pattern
|
443
|
+
raise schema_error(:map_conflict, rule, path, 'sequence:') if @sequence
|
444
|
+
raise schema_error(:map_conflict, rule, path, 'range:') if @range
|
445
|
+
raise schema_error(:map_conflict, rule, path, 'length:') if @length
|
446
|
+
else
|
447
|
+
#* key=:scalar_conflict msg="not available with scalar type."
|
448
|
+
raise schema_error(:scalar_conflict, rule, path, 'sequence:') if @sequence
|
449
|
+
raise schema_error(:scalar_conflict, rule, path, 'mapping:') if @mapping
|
450
|
+
if @enum
|
451
|
+
#* key=:enum_conflict msg="not available with 'enum:'."
|
452
|
+
raise schema_error(:enum_conflict, rule, path, 'range:') if @range
|
453
|
+
raise schema_error(:enum_conflict, rule, path, 'length:') if @length
|
454
|
+
raise schema_error(:enum_conflict, rule, path, 'pattern:') if @pattern
|
455
|
+
end
|
456
|
+
unless @default.nil?
|
457
|
+
#* key=:default_conflict msg="not available when 'required:' is true."
|
458
|
+
raise schema_error(:default_conflict, rule, path, 'default:') if @required
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
#def inspect()
|
464
|
+
# str = ""; level = 0; done = {}
|
465
|
+
# _inspect(str, level, done)
|
466
|
+
# return str
|
467
|
+
#end
|
468
|
+
|
469
|
+
|
470
|
+
protected
|
471
|
+
|
472
|
+
|
473
|
+
def _inspect(str="", level=0, done={})
|
474
|
+
done[self.__id__] = true
|
475
|
+
str << " " * level << "name: #{@name}\n" unless @name.nil?
|
476
|
+
str << " " * level << "desc: #{@desc}\n" unless @desc.nil?
|
477
|
+
str << " " * level << "type: #{@type}\n" unless @type.nil?
|
478
|
+
str << " " * level << "klass: #{@type_class.name}\n" unless @type_class.nil?
|
479
|
+
str << " " * level << "required: #{@required}\n" unless @required.nil?
|
480
|
+
str << " " * level << "pattern: #{@regexp.inspect}\n" unless @pattern.nil?
|
481
|
+
str << " " * level << "assert: #{@assert}\n" unless @assert.nil?
|
482
|
+
str << " " * level << "ident: #{@ident}\n" unless @ident.nil?
|
483
|
+
str << " " * level << "unique: #{@unique}\n" unless @unique.nil?
|
484
|
+
if !@enum.nil?
|
485
|
+
str << " " * level << "enum:\n"
|
486
|
+
@enum.each do |item|
|
487
|
+
str << " " * (level+1) << "- #{item}\n"
|
488
|
+
end
|
489
|
+
end
|
490
|
+
if !@range.nil?
|
491
|
+
str << " " * level
|
492
|
+
str << "range: { "
|
493
|
+
colon = ""
|
494
|
+
%w[max max-ex min min-ex].each do |key|
|
495
|
+
val = @range[key]
|
496
|
+
unless val.nil?
|
497
|
+
str << colon << "#{key}: #{val.inspect}"
|
498
|
+
colon = ", "
|
499
|
+
end
|
500
|
+
end
|
501
|
+
str << " }\n"
|
502
|
+
end
|
503
|
+
if !@length.nil?
|
504
|
+
str << " " * level
|
505
|
+
str << "length: { "
|
506
|
+
colon = ""
|
507
|
+
%w[max max-ex min min-ex].each do |key|
|
508
|
+
val = @length[key]
|
509
|
+
if !val.nil?
|
510
|
+
str << colon << "#{key}: #{val.inspect}"
|
511
|
+
colon = ", "
|
512
|
+
end
|
513
|
+
end
|
514
|
+
str << " }\n"
|
515
|
+
end
|
516
|
+
@sequence.each do |rule|
|
517
|
+
if done[rule.__id__]
|
518
|
+
str << " " * (level+1) << "- ...\n"
|
519
|
+
else
|
520
|
+
str << " " * (level+1) << "- \n"
|
521
|
+
rule._inspect(str, level+2, done)
|
522
|
+
end
|
523
|
+
end if @sequence
|
524
|
+
@mapping.each do |key, rule|
|
525
|
+
if done[rule.__id__]
|
526
|
+
str << ' ' * (level+1) << '"' << key << "\": ...\n"
|
527
|
+
else
|
528
|
+
str << ' ' * (level+1) << '"' << key << "\":\n"
|
529
|
+
rule._inspect(str, level+2, done)
|
530
|
+
end
|
531
|
+
end if @mapping
|
532
|
+
return str
|
533
|
+
end
|
534
|
+
|
535
|
+
|
536
|
+
public
|
537
|
+
|
538
|
+
|
539
|
+
def _uniqueness_check_table() # :nodoc:
|
540
|
+
uniq_table = nil
|
541
|
+
if @type == 'map'
|
542
|
+
@mapping.keys.each do |key|
|
543
|
+
rule = @mapping[key]
|
544
|
+
if rule.unique || rule.ident
|
545
|
+
uniq_table ||= {}
|
546
|
+
uniq_table[key] = {}
|
547
|
+
end
|
548
|
+
end
|
549
|
+
elsif @unique || @ident
|
550
|
+
uniq_table = {}
|
551
|
+
end
|
552
|
+
return uniq_table
|
553
|
+
end
|
554
|
+
|
432
555
|
|
556
|
+
end
|
433
557
|
|
434
|
-
protected
|
435
|
-
|
436
|
-
|
437
|
-
def _inspect(str="", level=0, done={})
|
438
|
-
done[self.__id__] = true
|
439
|
-
str << " " * level << "name: #{@name}\n" if @name != nil
|
440
|
-
str << " " * level << "desc: #{@desc}\n" if @desc != nil
|
441
|
-
str << " " * level << "type: #{@type}\n" if @type != nil
|
442
|
-
str << " " * level << "klass: #{@type_class.name}\n" if @type_class != nil
|
443
|
-
str << " " * level << "required: #{@required}\n" if @required != nil
|
444
|
-
str << " " * level << "pattern: #{@regexp.inspect}\n" if @pattern != nil
|
445
|
-
str << " " * level << "assert: #{@assert}\n" if @assert != nil
|
446
|
-
str << " " * level << "ident: #{@ident}\n" if @ident != nil
|
447
|
-
str << " " * level << "unique: #{@unique}\n" if @unique != nil
|
448
|
-
if @enum != nil
|
449
|
-
str << " " * level << "enum:\n"
|
450
|
-
@enum.each do |item|
|
451
|
-
str << " " * (level+1) << "- #{item}\n"
|
452
|
-
end
|
453
|
-
end
|
454
|
-
if @range != nil
|
455
|
-
str << " " * level
|
456
|
-
str << "range: { "
|
457
|
-
colon = ""
|
458
|
-
%w[max max-ex min min-ex].each do |key|
|
459
|
-
val = @range[key]
|
460
|
-
if val != nil
|
461
|
-
str << colon << "#{key}: #{val.inspect}"
|
462
|
-
colon = ", "
|
463
|
-
end
|
464
|
-
end
|
465
|
-
str << " }\n"
|
466
|
-
end
|
467
|
-
if @length != nil
|
468
|
-
str << " " * level
|
469
|
-
str << "length: { "
|
470
|
-
colon = ""
|
471
|
-
%w[max max-ex min min-ex].each do |key|
|
472
|
-
val = @length[key]
|
473
|
-
if val != nil
|
474
|
-
str << colon << "#{key}: #{val.inspect}"
|
475
|
-
colon = ", "
|
476
|
-
end
|
477
|
-
end
|
478
|
-
str << " }\n"
|
479
|
-
end
|
480
|
-
@sequence.each do |rule|
|
481
|
-
if done[rule.__id__]
|
482
|
-
str << " " * (level+1) << "- ...\n"
|
483
|
-
else
|
484
|
-
str << " " * (level+1) << "- \n"
|
485
|
-
rule._inspect(str, level+2, done)
|
486
|
-
end
|
487
|
-
end if @sequence
|
488
|
-
@mapping.each do |key, rule|
|
489
|
-
if done[rule.__id__]
|
490
|
-
str << ' ' * (level+1) << '"' << key << "\": ...\n"
|
491
|
-
else
|
492
|
-
str << ' ' * (level+1) << '"' << key << "\":\n"
|
493
|
-
rule._inspect(str, level+2, done)
|
494
|
-
end
|
495
|
-
end if @mapping
|
496
|
-
return str
|
497
|
-
end
|
498
|
-
|
499
|
-
end
|
500
558
|
|
501
559
|
end
|