kwalify 0.4.1 → 0.5.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/ChangeLog +14 -3
- data/README.txt +3 -3
- data/bin/kwalify +4 -15
- data/doc/users-guide.html +237 -61
- data/examples/address-book/address-book.schema.yaml +1 -1
- data/examples/invoice/invoice.schema.yaml +2 -2
- data/examples/tapkit/tapkit.schema.yaml +39 -39
- data/lib/kwalify.rb +4 -4
- data/lib/kwalify/errors.rb +21 -14
- data/lib/kwalify/main.rb +357 -0
- data/lib/kwalify/messages.rb +38 -9
- data/lib/kwalify/meta-validator.rb +96 -64
- data/lib/kwalify/rule.rb +356 -269
- data/lib/kwalify/types.rb +53 -35
- data/lib/kwalify/util/assert-diff.rb +2 -2
- data/lib/kwalify/util/option-parser.rb +2 -2
- data/lib/kwalify/util/yaml-helper.rb +2 -2
- data/lib/kwalify/validator.rb +8 -17
- data/lib/kwalify/{parser.rb → yaml-parser.rb} +70 -41
- data/test/test-main.rb +179 -0
- data/test/test-main.yaml +756 -0
- data/test/test-metavalidator.rb +38 -721
- data/test/test-metavalidator.yaml +1104 -0
- data/test/test-rule.rb +60 -0
- data/test/test-rule.yaml +314 -0
- data/test/test-validator.rb +5 -5
- data/test/test-validator.yaml +816 -0
- data/test/{test-parser.rb → test-yamlparser.rb} +17 -17
- data/test/test-yamlparser.yaml +1080 -0
- data/test/test.rb +5 -3
- data/todo.txt +1 -0
- metadata +16 -11
- data/lib/kwalify/main-program.rb +0 -258
data/lib/kwalify/messages.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
###
|
2
|
-
### $Rev:
|
3
|
-
### $Release: 0.
|
2
|
+
### $Rev: 42 $
|
3
|
+
### $Release: 0.5.0 $
|
4
4
|
### copyright(c) 2005 kuwata-lab all rights reserved.
|
5
5
|
###
|
6
6
|
|
@@ -14,26 +14,32 @@ module Kwalify
|
|
14
14
|
|
15
15
|
|
16
16
|
##----- begin
|
17
|
-
# filename: lib/kwalify/main
|
18
|
-
@@messages[:
|
19
|
-
@@messages[:
|
20
|
-
@@messages[:
|
21
|
-
@@messages[:
|
17
|
+
# filename: lib/kwalify/main.rb
|
18
|
+
@@messages[:command_option_noaction] = "command-line option '-f' or '-m' required."
|
19
|
+
@@messages[:meta_empty] = "%s: empty.\n"
|
20
|
+
@@messages[:meta_valid] = "%s: ok.\n"
|
21
|
+
@@messages[:meta_invalid] = "%s: NG!\n"
|
22
22
|
@@messages[:schema_empty] = "%s#%d: empty.\n"
|
23
23
|
@@messages[:validation_valid] = "%s#%d: valid.\n"
|
24
24
|
@@messages[:validation_invalid] = "%s#%d: INVALID\n"
|
25
|
+
@@messages[:command_property_invalid] = "%s: invalid property."
|
26
|
+
@@messages[:command_option_noarg] = "-%s: argument required."
|
27
|
+
@@messages[:command_option_noschema] = "-%s: schema filename required."
|
28
|
+
@@messages[:command_option_invalid] = "-%s: invalid command option."
|
25
29
|
# --
|
26
30
|
# filename: lib/kwalify/rule.rb
|
27
31
|
@@messages[:schema_notmap] = "schema definition is not a mapping."
|
32
|
+
@@messages[:key_unknown] = "unknown key."
|
28
33
|
@@messages[:type_notstr] = "not a string."
|
29
34
|
@@messages[:type_unknown] = "unknown type."
|
30
35
|
@@messages[:required_notbool] = "not a boolean."
|
36
|
+
@@messages[:pattern_notstr] = "not a string (or regexp)"
|
31
37
|
@@messages[:pattern_notmatch] = "should be '/..../'."
|
32
38
|
@@messages[:pattern_syntaxerr] = "has regexp error."
|
33
39
|
@@messages[:enum_notseq] = "not a sequence."
|
34
40
|
@@messages[:enum_notscalar] = "not available with seq or map."
|
35
|
-
@@messages[:enum_duplicate] = "duplicated enum value."
|
36
41
|
@@messages[:enum_type_unmatch] = "%s type expected."
|
42
|
+
@@messages[:enum_duplicate] = "duplicated enum value."
|
37
43
|
@@messages[:assert_notstr] = "not a string."
|
38
44
|
@@messages[:assert_noval] = "'val' is not used."
|
39
45
|
@@messages[:assert_syntaxerr] = "expression syntax error."
|
@@ -43,12 +49,20 @@ module Kwalify
|
|
43
49
|
@@messages[:range_undefined] = "undefined key."
|
44
50
|
@@messages[:range_twomax] = "both 'max' and 'max-ex' are not available at once."
|
45
51
|
@@messages[:range_twomin] = "both 'min' and 'min-ex' are not available at once."
|
52
|
+
@@messages[:range_maxltmin] = "max '%s' is less than min '%s'."
|
53
|
+
@@messages[:range_maxleminex] = "max '%s' is less than or equal to min-ex '%s'."
|
54
|
+
@@messages[:range_maxexlemin] = "max-ex '%s' is less than or equal to min '%s'."
|
55
|
+
@@messages[:range_maxexleminex] = "max-ex '%s' is less than or equal to min-ex '%s'."
|
46
56
|
@@messages[:length_notmap] = "not a mapping."
|
47
57
|
@@messages[:length_nottext] = "is available only with string or text."
|
48
58
|
@@messages[:length_notint] = "not an integer."
|
49
59
|
@@messages[:length_undefined] = "undefined key."
|
50
60
|
@@messages[:length_twomax] = "both 'max' and 'max-ex' are not available at once."
|
51
61
|
@@messages[:length_twomin] = "both 'min' and 'min-ex' are not available at once."
|
62
|
+
@@messages[:length_maxltmin] = "max '%s' is less than min '%s'."
|
63
|
+
@@messages[:length_maxleminex] = "max '%s' is less than or equal to min-ex '%s'."
|
64
|
+
@@messages[:length_maxexlemin] = "max-ex '%s' is less than or equal to min '%s'."
|
65
|
+
@@messages[:length_maxexleminex] = "max-ex '%s' is less than or equal to min-ex '%s'."
|
52
66
|
@@messages[:ident_notbool] = "not a boolean."
|
53
67
|
@@messages[:ident_notscalar] = "is available only with a scalar type."
|
54
68
|
@@messages[:ident_onroot] = "is not available on root element."
|
@@ -61,7 +75,6 @@ module Kwalify
|
|
61
75
|
@@messages[:sequence_toomany] = "required just one element."
|
62
76
|
@@messages[:mapping_notmap] = "not a mapping."
|
63
77
|
@@messages[:mapping_noelem] = "required at least one element."
|
64
|
-
@@messages[:key_unknown] = "unknown key."
|
65
78
|
@@messages[:seq_nosequence] = "type 'seq' requires 'sequence:'."
|
66
79
|
@@messages[:seq_conflict] = "not available with sequence."
|
67
80
|
@@messages[:map_nomapping] = "type 'map' requires 'mapping:'."
|
@@ -87,6 +100,22 @@ module Kwalify
|
|
87
100
|
@@messages[:required_nokey] = "key '%s:' is required."
|
88
101
|
@@messages[:key_undefined] = "key '%s' is undefined."
|
89
102
|
# --
|
103
|
+
# filename: lib/kwalify/yaml-parser.rb
|
104
|
+
@@messages[:flow_hastail] = "flow style sequence is closed but got '%s'."
|
105
|
+
@@messages[:flow_eof] = "found EOF when parsing flow style."
|
106
|
+
@@messages[:flow_noseqitem] = "sequence item required (or last comma is extra)."
|
107
|
+
@@messages[:flow_seqnotclosed] = "flow style sequence requires ']'."
|
108
|
+
@@messages[:flow_mapnoitem] = "mapping item required (or last comma is extra)."
|
109
|
+
@@messages[:flow_mapnotclosed] = "flow style mapping requires '}'."
|
110
|
+
@@messages[:flow_nocolon] = "':' expected but got '%s'."
|
111
|
+
@@messages[:anchor_duplicated] = "anchor '%s' is already used."
|
112
|
+
@@messages[:alias_extradata] = "alias cannot take any data."
|
113
|
+
@@messages[:anchor_notfound] = "anchor '%s' not found"
|
114
|
+
@@messages[:sequence_noitem] = "sequence item is expected."
|
115
|
+
@@messages[:sequence_badindent] = "illegal indent of sequence."
|
116
|
+
@@messages[:mapping_noitem] = "mapping item is expected."
|
117
|
+
@@messages[:mapping_badindent] = "illegal indent of mapping."
|
118
|
+
# --
|
90
119
|
##----- end
|
91
120
|
|
92
121
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
###
|
2
|
-
### $Rev:
|
3
|
-
### $Release: 0.
|
2
|
+
### $Rev: 42 $
|
3
|
+
### $Release: 0.5.0 $
|
4
4
|
### copyright(c) 2005 kuwata-lab all rights reserved.
|
5
5
|
###
|
6
6
|
|
@@ -11,7 +11,21 @@ require 'yaml'
|
|
11
11
|
|
12
12
|
module Kwalify
|
13
13
|
|
14
|
-
|
14
|
+
|
15
|
+
##
|
16
|
+
## ex.
|
17
|
+
## meta_validator = Kwalify::MetaValidator.instance()
|
18
|
+
## schema = File.load_file('schema.yaml')
|
19
|
+
## errors = meta_validator.validate(schema)
|
20
|
+
## if !errors.empty?
|
21
|
+
## errors.each do |error|
|
22
|
+
## puts "[#{error.path}] #{error.message}"
|
23
|
+
## end
|
24
|
+
## end
|
25
|
+
##
|
26
|
+
class MetaValidator < Validator
|
27
|
+
|
28
|
+
META_SCHEMA = <<'END'
|
15
29
|
name: MAIN
|
16
30
|
type: map
|
17
31
|
required: yes
|
@@ -53,6 +67,7 @@ mapping: &main-rule
|
|
53
67
|
type: seq
|
54
68
|
sequence:
|
55
69
|
- type: scalar
|
70
|
+
unique: yes
|
56
71
|
"pattern":
|
57
72
|
type: str
|
58
73
|
"assert":
|
@@ -69,8 +84,6 @@ mapping: &main-rule
|
|
69
84
|
type: scalar
|
70
85
|
"min-ex":
|
71
86
|
type: scalar
|
72
|
-
#complement":
|
73
|
-
# type: boolean
|
74
87
|
"length":
|
75
88
|
type: map
|
76
89
|
mapping:
|
@@ -106,18 +119,6 @@ mapping: &main-rule
|
|
106
119
|
END
|
107
120
|
|
108
121
|
|
109
|
-
##
|
110
|
-
## ex.
|
111
|
-
## meta_validator = Kwalify.meta_validator()
|
112
|
-
## schema = File.load_file('schema.yaml')
|
113
|
-
## errors = meta_validator.validate(schema)
|
114
|
-
## if !errors.empty?
|
115
|
-
## errors.each do |error|
|
116
|
-
## puts "[#{error.path}] #{error.message}"
|
117
|
-
## end
|
118
|
-
## end
|
119
|
-
##
|
120
|
-
class MetaValidator < Validator
|
121
122
|
def initialize(schema, &block)
|
122
123
|
super
|
123
124
|
end
|
@@ -128,14 +129,11 @@ END
|
|
128
129
|
#
|
129
130
|
hash = value
|
130
131
|
type = hash['type']
|
131
|
-
type =
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
unless klass
|
137
|
-
errors << validate_error(:type_unknown, rule, "#{path}/type", type.to_s)
|
138
|
-
end
|
132
|
+
type = Types::DEFAULT_TYPE if type == nil
|
133
|
+
klass = Types.type_class(type)
|
134
|
+
#unless klass
|
135
|
+
# errors << validate_error(:type_unknown, rule, "#{path}/type", type)
|
136
|
+
#end
|
139
137
|
#
|
140
138
|
if hash.key?('pattern')
|
141
139
|
val = hash['pattern']
|
@@ -148,15 +146,15 @@ END
|
|
148
146
|
end
|
149
147
|
#
|
150
148
|
if hash.key?('enum')
|
151
|
-
if
|
149
|
+
if Types.collection_type?(type)
|
152
150
|
errors << validate_error(:enum_notscalar, rule, path, 'enum:')
|
153
151
|
else
|
154
|
-
elem_table = {}
|
152
|
+
#elem_table = {}
|
155
153
|
hash['enum'].each do |elem|
|
156
|
-
if elem_table[elem]
|
157
|
-
|
158
|
-
end
|
159
|
-
elem_table[elem] = true
|
154
|
+
#if elem_table[elem]
|
155
|
+
# errors << validate_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s)
|
156
|
+
#end
|
157
|
+
#elem_table[elem] = true
|
160
158
|
unless elem.is_a?(klass)
|
161
159
|
errors << validate_error(:enum_type_unmatch, rule, "#{path}/enum", elem, [Kwalify.word(type)])
|
162
160
|
end
|
@@ -166,7 +164,7 @@ END
|
|
166
164
|
#
|
167
165
|
if hash.key?('assert')
|
168
166
|
val = hash['assert']
|
169
|
-
val =~ /\bval\b/ or errors << validate_error(:assert_noval, rule, "#{path}/assert", val)
|
167
|
+
#val =~ /\bval\b/ or errors << validate_error(:assert_noval, rule, "#{path}/assert", val)
|
170
168
|
begin
|
171
169
|
eval "proc { |val| #{val} }"
|
172
170
|
rescue SyntaxError => ex
|
@@ -177,9 +175,10 @@ END
|
|
177
175
|
if hash.key?('range')
|
178
176
|
val = hash['range']
|
179
177
|
curr_path = path + "/range"
|
180
|
-
if ! val.is_a?(Hash)
|
181
|
-
|
182
|
-
elsif
|
178
|
+
#if ! val.is_a?(Hash)
|
179
|
+
# errors << validate_error(:range_notmap, rule, curr_path, val)
|
180
|
+
#elsif ...
|
181
|
+
if Types.collection_type?(type) || type == 'bool' || type == 'any'
|
183
182
|
errors << validate_error(:range_notscalar, rule, path, 'range:')
|
184
183
|
else
|
185
184
|
val.each do |rkey, rval|
|
@@ -200,35 +199,63 @@ END
|
|
200
199
|
if val.key?('min') && val.key?('min-ex')
|
201
200
|
errors << validate_error(:range_twomin, rule, curr_path, nil)
|
202
201
|
end
|
202
|
+
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
203
|
+
if max
|
204
|
+
if min && max < min
|
205
|
+
errors << validate_error(:range_maxltmin, rule, curr_path, nil, [max, min])
|
206
|
+
elsif min_ex && max <= min_ex
|
207
|
+
errors << validate_error(:range_maxleminex, rule, curr_path, nil, [max, min_ex])
|
208
|
+
end
|
209
|
+
elsif max_ex
|
210
|
+
if min && max_ex <= min
|
211
|
+
errors << validate_error(:range_maxexlemin, rule, curr_path, nil, [max_ex, min])
|
212
|
+
elsif min_ex && max_ex <= min_ex
|
213
|
+
errors << validate_error(:range_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
|
214
|
+
end
|
215
|
+
end
|
203
216
|
end
|
204
217
|
#
|
205
218
|
if hash.key?('length')
|
206
219
|
val = hash['length']
|
207
220
|
curr_path = path + "/length"
|
208
|
-
val.is_a?(Hash) or errors << validate_error(:length_notmap, rule, curr_path, val)
|
221
|
+
#val.is_a?(Hash) or errors << validate_error(:length_notmap, rule, curr_path, val)
|
209
222
|
unless type == 'str' || type == 'text'
|
210
223
|
errors << validate_error(:length_nottext, rule, path, 'length:')
|
211
224
|
end
|
212
|
-
val.each do |lkey, lval|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
end
|
225
|
+
#val.each do |lkey, lval|
|
226
|
+
# #case lkey
|
227
|
+
# #when 'max', 'min', 'max-ex', 'min-ex'
|
228
|
+
# unless lval.is_a?(Integer)
|
229
|
+
# errors << validate_error(:length_notint, rule, "#{curr_path}/#{lkey}", lval)
|
230
|
+
# end
|
231
|
+
# #else
|
232
|
+
# # errors << validate_error(:length_undefined, rule, curr_path, "#{lkey}:")
|
233
|
+
# #end
|
234
|
+
#end
|
222
235
|
if val.key?('max') && val.key?('max-ex')
|
223
236
|
errors << validate_error(:length_twomax, rule, curr_path, nil)
|
224
237
|
end
|
225
238
|
if val.key?('min') && val.key?('min-ex')
|
226
239
|
errors << validate_error(:length_twomin, rule, curr_path, nil)
|
227
240
|
end
|
241
|
+
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
242
|
+
if max
|
243
|
+
if min && max < min
|
244
|
+
errors << validate_error(:length_maxltmin, rule, curr_path, nil, [max, min])
|
245
|
+
elsif min_ex && max <= min_ex
|
246
|
+
errors << validate_error(:length_maxleminex, rule, curr_path, nil, [max, min_ex])
|
247
|
+
end
|
248
|
+
elsif max_ex
|
249
|
+
if min && max_ex <= min
|
250
|
+
errors << validate_error(:length_maxexlemin, rule, curr_path, nil, [max_ex, min])
|
251
|
+
elsif min_ex && max_ex <= min_ex
|
252
|
+
errors << validate_error(:length_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
|
253
|
+
end
|
254
|
+
end
|
228
255
|
end
|
229
256
|
#
|
230
257
|
if hash.key?('unique')
|
231
|
-
if hash['unique'] && (type
|
258
|
+
if hash['unique'] && Types.collection_type?(type)
|
232
259
|
errors << validate_error(:unique_notscalar, rule, path, "unique:")
|
233
260
|
end
|
234
261
|
if path.empty?
|
@@ -237,7 +264,7 @@ END
|
|
237
264
|
end
|
238
265
|
#
|
239
266
|
if hash.key?('ident')
|
240
|
-
if hash['ident'] && (type
|
267
|
+
if hash['ident'] && Types.collection_type?(type)
|
241
268
|
errors << validate_error(:ident_notscalar, rule, path, "ident:")
|
242
269
|
end
|
243
270
|
if path.empty?
|
@@ -247,21 +274,18 @@ END
|
|
247
274
|
#
|
248
275
|
if hash.key?('sequence')
|
249
276
|
val = hash['sequence']
|
250
|
-
if val != nil && !val.is_a?(Array)
|
251
|
-
|
252
|
-
elsif
|
277
|
+
#if val != nil && !val.is_a?(Array)
|
278
|
+
# errors << validate_error(:sequence_notseq, rule, "#{path}/sequence", val)
|
279
|
+
#elsif ...
|
280
|
+
if val == nil || val.empty?
|
253
281
|
errors << validate_error(:sequence_noelem, rule, "#{path}/sequence", val)
|
254
282
|
elsif val.length > 1
|
255
283
|
errors << validate_error(:sequence_toomany, rule, "#{path}/sequence", val)
|
256
284
|
else
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
end
|
262
|
-
#if child['unique'] && child['type'] != 'map'
|
263
|
-
# errors << validate_error(:unique_notmap, nil, "#{path}/sequence/0", 'unique:')
|
264
|
-
#end
|
285
|
+
elem = val[0]
|
286
|
+
assert_error("elem.class=#{elem.class}") unless elem.is_a?(Hash)
|
287
|
+
if elem['ident'] && elem['type'] != 'map'
|
288
|
+
errors << validate_error(:ident_notmap, nil, "#{path}/sequence/0", 'ident:')
|
265
289
|
end
|
266
290
|
end
|
267
291
|
end
|
@@ -281,14 +305,14 @@ END
|
|
281
305
|
errors << validate_error(:seq_conflict, rule, path, 'pattern:') if hash.key?('pattern')
|
282
306
|
errors << validate_error(:seq_conflict, rule, path, 'mapping:') if hash.key?('mapping')
|
283
307
|
#errors << validate_error(:seq_conflict, rule, path, 'range:') if hash.key?('range')
|
284
|
-
errors << validate_error(:seq_conflict, rule, path, 'length:') if hash.key?('length')
|
308
|
+
#errors << validate_error(:seq_conflict, rule, path, 'length:') if hash.key?('length')
|
285
309
|
elsif type == 'map'
|
286
310
|
errors << validate_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping')
|
287
311
|
#errors << validate_error(:map_conflict, rule, path, 'enum:') if hash.key?('enum')
|
288
312
|
errors << validate_error(:map_conflict, rule, path, 'pattern:') if hash.key?('pattern')
|
289
313
|
errors << validate_error(:map_conflict, rule, path, 'sequence:') if hash.key?('sequence')
|
290
314
|
#errors << validate_error(:map_conflict, rule, path, 'range:') if hash.key?('range')
|
291
|
-
errors << validate_error(:map_conflict, rule, path, 'length:') if hash.key?('length')
|
315
|
+
#errors << validate_error(:map_conflict, rule, path, 'length:') if hash.key?('length')
|
292
316
|
else
|
293
317
|
errors << validate_error(:scalar_conflict, rule, path, 'sequence:') if hash.key?('sequence')
|
294
318
|
errors << validate_error(:scalar_conflict, rule, path, 'mapping:') if hash.key?('mapping')
|
@@ -301,13 +325,21 @@ END
|
|
301
325
|
|
302
326
|
end # end of def validate_hook()
|
303
327
|
|
328
|
+
|
329
|
+
schema = YAML.load(META_SCHEMA)
|
330
|
+
@instance = MetaValidator.new(schema)
|
331
|
+
|
332
|
+
def self.instance()
|
333
|
+
return @instance
|
334
|
+
end
|
335
|
+
|
336
|
+
|
304
337
|
end # end of class MetaValidator
|
305
338
|
|
306
339
|
|
307
|
-
|
308
|
-
META_VALIDATOR = MetaValidator.new(schema)
|
340
|
+
META_VALIDATOR = MetaValidator.instance()
|
309
341
|
|
310
|
-
def self.meta_validator
|
342
|
+
def self.meta_validator # obsolete
|
311
343
|
return META_VALIDATOR
|
312
344
|
end
|
313
345
|
|
data/lib/kwalify/rule.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
###
|
2
|
-
### $Rev:
|
3
|
-
### $Release: 0.
|
2
|
+
### $Rev: 42 $
|
3
|
+
### $Release: 0.5.0 $
|
4
4
|
### copyright(c) 2005 kuwata-lab all rights reserved.
|
5
5
|
###
|
6
6
|
|
@@ -14,273 +14,375 @@ module Kwalify
|
|
14
14
|
include Kwalify::ErrorHelper
|
15
15
|
|
16
16
|
def initialize(hash=nil, parent=nil)
|
17
|
-
|
17
|
+
init(hash, "", {}) if hash
|
18
18
|
@parent = parent
|
19
19
|
end
|
20
|
+
|
20
21
|
attr_accessor :parent
|
22
|
+
#attr_reader :id
|
23
|
+
attr_reader :name
|
24
|
+
attr_reader :desc
|
25
|
+
attr_reader :enum
|
26
|
+
attr_reader :required
|
27
|
+
attr_reader :type
|
28
|
+
attr_reader :type_class
|
29
|
+
attr_reader :pattern
|
30
|
+
attr_reader :regexp
|
31
|
+
attr_reader :sequence
|
32
|
+
attr_reader :mapping
|
33
|
+
attr_reader :assert
|
34
|
+
attr_reader :assert_proc
|
35
|
+
attr_reader :range
|
36
|
+
attr_reader :length
|
37
|
+
attr_reader :ident
|
38
|
+
attr_reader :unique
|
39
|
+
|
21
40
|
|
22
|
-
def
|
41
|
+
def init(hash, path="", rule_table={})
|
23
42
|
unless hash.is_a?(Hash)
|
24
43
|
#* key=:schema_notmap msg="schema definition is not a mapping."
|
25
44
|
raise Kwalify.schema_error(:schema_notmap, nil, (!path || path.empty? ? "/" : path), nil)
|
26
45
|
end
|
27
|
-
|
28
46
|
rule = self
|
29
47
|
rule_table[hash.__id__] = rule
|
48
|
+
## 'type:' entry
|
49
|
+
_init_type_value(hash['type'], rule, path)
|
50
|
+
## other entries
|
51
|
+
hash.each do |key, val|
|
52
|
+
code = key.intern
|
53
|
+
curr_path = "#{path}/#{key}"
|
54
|
+
case code
|
55
|
+
#when "id"
|
56
|
+
# @id = val
|
57
|
+
when :type ; # done
|
58
|
+
when :name ; _init_name_value( val, rule, path)
|
59
|
+
when :desc ; _init_desc_value( val, rule, path)
|
60
|
+
when :required ; _init_required_value(val, rule, path)
|
61
|
+
when :pattern ; _init_pattern_value( val, rule, path)
|
62
|
+
when :enum ; _init_enum_value( val, rule, path)
|
63
|
+
when :assert ; _init_assert_value( val, rule, path)
|
64
|
+
when :range ; _init_range_value( val, rule, path)
|
65
|
+
when :length ; _init_length_value( val, rule, path)
|
66
|
+
when :ident ; _init_ident_value( val, rule, path)
|
67
|
+
when :unique ; _init_unique_value( val, rule, path)
|
68
|
+
when :sequence ; _init_sequence_value(val, rule, path, rule_table)
|
69
|
+
when :mapping ; _init_mapping_value( val, rule, path, rule_table)
|
70
|
+
else
|
71
|
+
#* key=:key_unknown msg="unknown key."
|
72
|
+
raise schema_error(:key_unknown, rule, curr_path, "#{key}:")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
check_confliction(hash, rule, path)
|
76
|
+
return self
|
77
|
+
end # end of def init
|
78
|
+
|
79
|
+
|
80
|
+
private
|
30
81
|
|
31
|
-
|
32
|
-
|
33
|
-
@type =
|
82
|
+
|
83
|
+
def _init_type_value(val, rule, path)
|
84
|
+
@type = val
|
85
|
+
@type = Types::DEFAULT_TYPE if @type == nil
|
34
86
|
unless @type.is_a?(String)
|
35
87
|
#* key=:type_notstr msg="not a string."
|
36
88
|
raise schema_error(:type_notstr, rule, "#{path}/type", @type.to_s)
|
37
89
|
end
|
38
|
-
@
|
39
|
-
#if @
|
90
|
+
@type_class = Types.type_class(@type)
|
91
|
+
#if @type_class == nil
|
40
92
|
# begin
|
41
|
-
# @
|
93
|
+
# @type_class = Kernel.const_get(@type)
|
42
94
|
# rescue NameError
|
43
95
|
# end
|
44
96
|
#end
|
45
|
-
unless @
|
97
|
+
unless @type_class
|
46
98
|
#* key=:type_unknown msg="unknown type."
|
47
99
|
raise schema_error(:type_unknown, rule, "#{path}/type", @type.to_s)
|
48
100
|
end
|
101
|
+
end
|
49
102
|
|
50
|
-
## other key
|
51
|
-
hash.each do |key, val|
|
52
|
-
curr_path = "#{path}/#{key}"
|
53
|
-
case key
|
54
|
-
#when "id"
|
55
|
-
# @id = val
|
56
|
-
when "name"
|
57
|
-
@name = val
|
58
103
|
|
59
|
-
|
60
|
-
|
104
|
+
def _init_name_value(val, rule, path)
|
105
|
+
@name = val
|
106
|
+
end
|
61
107
|
|
62
|
-
when "type"
|
63
|
-
# done
|
64
108
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
#* key=:required_notbool msg="not a boolean."
|
69
|
-
raise schema_error(:required_notbool, rule, curr_path, val)
|
70
|
-
end
|
109
|
+
def _init_desc_value(val, rule, path)
|
110
|
+
@desc = val
|
111
|
+
end
|
71
112
|
|
72
|
-
when "pattern"
|
73
|
-
unless val =~ /\A\/(.*)\/([mi]?[mi]?)\z/
|
74
|
-
#* key=:pattern_notmatch msg="should be '/..../'."
|
75
|
-
raise schema_error(:pattern_notmatch, rule, curr_path, val)
|
76
|
-
end
|
77
|
-
pat = $1; opt = $2
|
78
|
-
flag = 0
|
79
|
-
flag += Regexp::IGNORECASE if opt.include?("i")
|
80
|
-
flag += Regexp::MULTILINE if opt.include?("m")
|
81
|
-
begin
|
82
|
-
@pattern = Regexp.compile(pat, flag)
|
83
|
-
rescue RegexpError => ex
|
84
|
-
#* key=:pattern_syntaxerr msg="has regexp error."
|
85
|
-
raise schema_error(:pattern_syntaxerr, rule, curr_path, val)
|
86
|
-
end
|
87
113
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
#* key=:enum_notscalar msg="not available with seq or map."
|
96
|
-
raise schema_error(:enum_notscalar, rule, path, 'enum:')
|
97
|
-
end
|
98
|
-
elem_table = {}
|
99
|
-
@enum.each do |elem|
|
100
|
-
unless !elem_table[elem]
|
101
|
-
#* key=:enum_duplicate msg="duplicated enum value."
|
102
|
-
raise schema_error(:enum_duplicate, rule, curr_path, elem.to_s)
|
103
|
-
end
|
104
|
-
elem_table[elem] = true
|
105
|
-
unless elem.is_a?(@klass)
|
106
|
-
#* key=:enum_type_unmatch msg="%s type expected."
|
107
|
-
raise schema_error(:enum_type_unmatch, rule, curr_path, elem, [Kwalify.word(@type)])
|
108
|
-
end
|
109
|
-
end
|
114
|
+
def _init_required_value(val, rule, path)
|
115
|
+
@required = val
|
116
|
+
unless val.is_a?(Boolean) #|| val == nil
|
117
|
+
#* key=:required_notbool msg="not a boolean."
|
118
|
+
raise schema_error(:required_notbool, rule, "#{path}/required", val)
|
119
|
+
end
|
120
|
+
end
|
110
121
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
122
|
+
def _init_pattern_value(val, rule, path)
|
123
|
+
@pattern = val
|
124
|
+
unless val.is_a?(String) || val.is_a?(Regexp)
|
125
|
+
#* key=:pattern_notstr msg="not a string (or regexp)"
|
126
|
+
raise schema_error(:pattern_notstr, rule, "#{path}/pattern", val)
|
127
|
+
end
|
128
|
+
unless val =~ /\A\/(.*)\/([mi]?[mi]?)\z/
|
129
|
+
#* key=:pattern_notmatch msg="should be '/..../'."
|
130
|
+
raise schema_error(:pattern_notmatch, rule, "#{path}/pattern", val)
|
131
|
+
end
|
132
|
+
pat = $1; opt = $2
|
133
|
+
flag = 0
|
134
|
+
flag += Regexp::IGNORECASE if opt.include?("i")
|
135
|
+
flag += Regexp::MULTILINE if opt.include?("m")
|
136
|
+
begin
|
137
|
+
@regexp = Regexp.compile(pat, flag)
|
138
|
+
rescue RegexpError => ex
|
139
|
+
#* key=:pattern_syntaxerr msg="has regexp error."
|
140
|
+
raise schema_error(:pattern_syntaxerr, rule, "#{path}/pattern", val)
|
141
|
+
end
|
142
|
+
end
|
127
143
|
|
128
|
-
when "range"
|
129
|
-
@range = val
|
130
|
-
unless val.is_a?(Hash)
|
131
|
-
#* key=:range_notmap msg="not a mapping."
|
132
|
-
raise schema_error(:range_notmap, rule, curr_path, val)
|
133
|
-
end
|
134
|
-
if @type == 'map' || @type == 'seq' || @type == 'bool'
|
135
|
-
#* key=:range_notscalar msg="is available only with scalar type."
|
136
|
-
raise schema_error(:range_notscalar, rule, path, 'range:')
|
137
|
-
end
|
138
|
-
val.each do |rkey, rval|
|
139
|
-
case rkey
|
140
|
-
when 'max', 'min', 'max-ex', 'min-ex'
|
141
|
-
unless rval.is_a?(@klass)
|
142
|
-
typename = Kwalify.word(@type) || @type
|
143
|
-
#* key=:range_type_unmatch msg="not a %s."
|
144
|
-
raise schema_error(:range_type_unmatch, rule, "#{curr_path}/#{rkey}", rval, [typename])
|
145
|
-
end
|
146
|
-
else
|
147
|
-
#* key=:range_undefined msg="undefined key."
|
148
|
-
raise schema_error(:range_undefined, rule, "#{curr_path}/#{rkey}", "#{rkey}:")
|
149
|
-
end
|
150
|
-
end
|
151
|
-
if val.key?('max') && val.key?('max-ex')
|
152
|
-
#* key=:range_twomax msg="both 'max' and 'max-ex' are not available at once."
|
153
|
-
raise schema_error(:range_twomax, rule, curr_path, nil)
|
154
|
-
end
|
155
|
-
if val.key?('min') && val.key?('min-ex')
|
156
|
-
#* key=:range_twomin msg="both 'min' and 'min-ex' are not available at once."
|
157
|
-
raise schema_error(:range_twomin, rule, curr_path, nil)
|
158
|
-
end
|
159
144
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
#* key=:length_twomax msg="both 'max' and 'max-ex' are not available at once."
|
184
|
-
raise schema_error(:length_twomax, rule, curr_path, nil)
|
185
|
-
end
|
186
|
-
if val.key?('min') && val.key?('min-ex')
|
187
|
-
#* key=:length_twomin msg="both 'min' and 'min-ex' are not available at once."
|
188
|
-
raise schema_error(:length_twomin, rule, curr_path, nil)
|
189
|
-
end
|
145
|
+
def _init_enum_value(val, rule, path)
|
146
|
+
@enum = val
|
147
|
+
unless val.is_a?(Array)
|
148
|
+
#* key=:enum_notseq msg="not a sequence."
|
149
|
+
raise schema_error(:enum_notseq, rule, "#{path}/enum", val)
|
150
|
+
end
|
151
|
+
if Types.collection_type?(@type) # unless Kwalify.scalar_class?(@type_class)
|
152
|
+
#* key=:enum_notscalar msg="not available with seq or map."
|
153
|
+
raise schema_error(:enum_notscalar, rule, path, 'enum:')
|
154
|
+
end
|
155
|
+
elem_table = {}
|
156
|
+
@enum.each do |elem|
|
157
|
+
unless elem.is_a?(@type_class)
|
158
|
+
#* key=:enum_type_unmatch msg="%s type expected."
|
159
|
+
raise schema_error(:enum_type_unmatch, rule, "#{path}/enum", elem, [Kwalify.word(@type)])
|
160
|
+
end
|
161
|
+
if elem_table[elem]
|
162
|
+
#* key=:enum_duplicate msg="duplicated enum value."
|
163
|
+
raise schema_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s)
|
164
|
+
end
|
165
|
+
elem_table[elem] = true
|
166
|
+
end
|
167
|
+
end
|
190
168
|
|
191
|
-
when "ident"
|
192
|
-
@ident = val
|
193
|
-
@required = true
|
194
|
-
unless val.is_a?(Boolean)
|
195
|
-
#* key=:ident_notbool msg="not a boolean."
|
196
|
-
raise schema_error(:ident_notbool, rule, curr_path, val)
|
197
|
-
end
|
198
|
-
if @type == 'map' || @type == 'seq'
|
199
|
-
#* key=:ident_notscalar msg="is available only with a scalar type."
|
200
|
-
raise schema_error(:ident_notscalar, rule, path, "ident:")
|
201
|
-
end
|
202
|
-
if path.empty?
|
203
|
-
#* key=:ident_onroot msg="is not available on root element."
|
204
|
-
raise schema_error(:ident_onroot, rule, "/", "ident:")
|
205
|
-
end
|
206
|
-
unless @parent && @parent.type == 'map'
|
207
|
-
#* key=:ident_notmap msg="is available only with an element of mapping."
|
208
|
-
raise schema_error(:ident_notmap, rule, path, "ident:")
|
209
|
-
end
|
210
169
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
#end
|
229
|
-
|
230
|
-
when "sequence"
|
231
|
-
if val != nil && !val.is_a?(Array)
|
232
|
-
#* key=:sequence_notseq msg="not a sequence."
|
233
|
-
raise schema_error(:sequence_notseq, rule, curr_path, val)
|
234
|
-
elsif val == nil || val.empty?
|
235
|
-
#* key=:sequence_noelem msg="required one element."
|
236
|
-
raise schema_error(:sequence_noelem, rule, curr_path, val)
|
237
|
-
elsif val.length > 1
|
238
|
-
#* key=:sequence_toomany msg="required just one element."
|
239
|
-
raise schema_error(:sequence_toomany, rule, curr_path, val)
|
240
|
-
else
|
241
|
-
elem = val[0]
|
242
|
-
elem ||= {}
|
243
|
-
i = 0 # or 1? *index*
|
244
|
-
rule = rule_table[elem.__id__]
|
245
|
-
rule ||= Rule.new(nil, self).configure(elem, "#{curr_path}/#{i}", rule_table)
|
246
|
-
@sequence = [ rule ]
|
247
|
-
end
|
170
|
+
def _init_assert_value(val, rule, path)
|
171
|
+
@assert = val
|
172
|
+
unless val.is_a?(String)
|
173
|
+
#* key=:assert_notstr msg="not a string."
|
174
|
+
raise schema_error(:assert_notstr, rule, "#{path}/assert", val)
|
175
|
+
end
|
176
|
+
unless val =~ /\bval\b/
|
177
|
+
#* key=:assert_noval msg="'val' is not used."
|
178
|
+
raise schema_error(:assert_noval, rule, "#{path}/assert", val)
|
179
|
+
end
|
180
|
+
begin
|
181
|
+
@assert_proc = eval "proc { |val| #{val} }"
|
182
|
+
rescue SyntaxError => ex
|
183
|
+
#* key=:assert_syntaxerr msg="expression syntax error."
|
184
|
+
raise schema_error(:assert_syntaxerr, rule, "#{path}/assert", val)
|
185
|
+
end
|
186
|
+
end
|
248
187
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
rule = rule_table[elem.__id__]
|
269
|
-
rule ||= Rule.new(nil, self).configure(elem, "#{curr_path}/#{key}", rule_table)
|
270
|
-
if key == '='
|
271
|
-
@mapping.default = rule
|
272
|
-
else
|
273
|
-
@mapping[key] = rule
|
274
|
-
end
|
275
|
-
end if val
|
188
|
+
|
189
|
+
def _init_range_value(val, rule, path)
|
190
|
+
@range = val
|
191
|
+
curr_path = "#{path}/range"
|
192
|
+
unless val.is_a?(Hash)
|
193
|
+
#* key=:range_notmap msg="not a mapping."
|
194
|
+
raise schema_error(:range_notmap, rule, curr_path, val)
|
195
|
+
end
|
196
|
+
if Types.collection_type?(@type) || @type == 'bool'
|
197
|
+
#* key=:range_notscalar msg="is available only with scalar type."
|
198
|
+
raise schema_error(:range_notscalar, rule, path, 'range:')
|
199
|
+
end
|
200
|
+
val.each do |k, v|
|
201
|
+
case k
|
202
|
+
when 'max', 'min', 'max-ex', 'min-ex'
|
203
|
+
unless v.is_a?(@type_class)
|
204
|
+
typename = Kwalify.word(@type) || @type
|
205
|
+
#* key=:range_type_unmatch msg="not a %s."
|
206
|
+
raise schema_error(:range_type_unmatch, rule, "#{curr_path}/#{k}", v, [typename])
|
276
207
|
end
|
208
|
+
else
|
209
|
+
#* key=:range_undefined msg="undefined key."
|
210
|
+
raise schema_error(:range_undefined, rule, "#{curr_path}/#{k}", "#{k}:")
|
211
|
+
end
|
212
|
+
end
|
213
|
+
if val.key?('max') && val.key?('max-ex')
|
214
|
+
#* key=:range_twomax msg="both 'max' and 'max-ex' are not available at once."
|
215
|
+
raise schema_error(:range_twomax, rule, curr_path, nil)
|
216
|
+
end
|
217
|
+
if val.key?('min') && val.key?('min-ex')
|
218
|
+
#* key=:range_twomin msg="both 'min' and 'min-ex' are not available at once."
|
219
|
+
raise schema_error(:range_twomin, rule, curr_path, nil)
|
220
|
+
end
|
221
|
+
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
222
|
+
if max
|
223
|
+
if min && max < min
|
224
|
+
#* key=:range_maxltmin msg="max '%s' is less than min '%s'."
|
225
|
+
raise validate_error(:range_maxltmin, rule, curr_path, nil, [max, min])
|
226
|
+
elsif min_ex && max <= min_ex
|
227
|
+
#* key=:range_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
|
228
|
+
raise validate_error(:range_maxleminex, rule, curr_path, nil, [max, min_ex])
|
229
|
+
end
|
230
|
+
elsif max_ex
|
231
|
+
if min && max_ex <= min
|
232
|
+
#* key=:range_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
|
233
|
+
raise validate_error(:range_maxexlemin, rule, curr_path, nil, [max_ex, min])
|
234
|
+
elsif min_ex && max_ex <= min_ex
|
235
|
+
#* key=:range_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
|
236
|
+
raise validate_error(:range_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
277
240
|
|
241
|
+
|
242
|
+
def _init_length_value(val, rule, path)
|
243
|
+
@length = val
|
244
|
+
curr_path = "#{path}/length"
|
245
|
+
unless val.is_a?(Hash)
|
246
|
+
#* key=:length_notmap msg="not a mapping."
|
247
|
+
raise schema_error(:length_notmap, rule, curr_path, val)
|
248
|
+
end
|
249
|
+
unless @type == 'str' || @type == 'text'
|
250
|
+
#* key=:length_nottext msg="is available only with string or text."
|
251
|
+
raise schema_error(:length_nottext, rule, path, 'length:')
|
252
|
+
end
|
253
|
+
val.each do |k, v|
|
254
|
+
case k
|
255
|
+
when 'max', 'min', 'max-ex', 'min-ex'
|
256
|
+
unless v.is_a?(Integer)
|
257
|
+
#* key=:length_notint msg="not an integer."
|
258
|
+
raise schema_error(:length_notint, rule, "#{curr_path}/#{k}", v)
|
259
|
+
end
|
278
260
|
else
|
279
|
-
#* key=:
|
280
|
-
raise schema_error(:
|
261
|
+
#* key=:length_undefined msg="undefined key."
|
262
|
+
raise schema_error(:length_undefined, rule, "#{curr_path}/#{k}", "#{k}:")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
if val.key?('max') && val.key?('max-ex')
|
266
|
+
#* key=:length_twomax msg="both 'max' and 'max-ex' are not available at once."
|
267
|
+
raise schema_error(:length_twomax, rule, curr_path, nil)
|
268
|
+
end
|
269
|
+
if val.key?('min') && val.key?('min-ex')
|
270
|
+
#* key=:length_twomin msg="both 'min' and 'min-ex' are not available at once."
|
271
|
+
raise schema_error(:length_twomin, rule, curr_path, nil)
|
272
|
+
end
|
273
|
+
max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
|
274
|
+
if max
|
275
|
+
if min && max < min
|
276
|
+
#* key=:length_maxltmin msg="max '%s' is less than min '%s'."
|
277
|
+
raise validate_error(:length_maxltmin, rule, curr_path, nil, [max, min])
|
278
|
+
elsif min_ex && max <= min_ex
|
279
|
+
#* key=:length_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
|
280
|
+
raise validate_error(:length_maxleminex, rule, curr_path, nil, [max, min_ex])
|
281
|
+
end
|
282
|
+
elsif max_ex
|
283
|
+
if min && max_ex <= min
|
284
|
+
#* key=:length_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
|
285
|
+
raise validate_error(:length_maxexlemin, rule, curr_path, nil, [max_ex, min])
|
286
|
+
elsif min_ex && max_ex <= min_ex
|
287
|
+
#* key=:length_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
|
288
|
+
raise validate_error(:length_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
def _init_ident_value(val, rule, path)
|
295
|
+
@ident = val
|
296
|
+
@required = true
|
297
|
+
unless val.is_a?(Boolean)
|
298
|
+
#* key=:ident_notbool msg="not a boolean."
|
299
|
+
raise schema_error(:ident_notbool, rule, "#{path}/ident", val)
|
300
|
+
end
|
301
|
+
if @type == 'map' || @type == 'seq'
|
302
|
+
#* key=:ident_notscalar msg="is available only with a scalar type."
|
303
|
+
raise schema_error(:ident_notscalar, rule, path, "ident:")
|
304
|
+
end
|
305
|
+
if path.empty?
|
306
|
+
#* key=:ident_onroot msg="is not available on root element."
|
307
|
+
raise schema_error(:ident_onroot, rule, "/", "ident:")
|
308
|
+
end
|
309
|
+
unless @parent && @parent.type == 'map'
|
310
|
+
#* key=:ident_notmap msg="is available only with an element of mapping."
|
311
|
+
raise schema_error(:ident_notmap, rule, path, "ident:")
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
|
316
|
+
def _init_unique_value(val, rule, path)
|
317
|
+
@unique = val
|
318
|
+
unless val.is_a?(Boolean)
|
319
|
+
#* key=:unique_notbool msg="not a boolean."
|
320
|
+
raise schema_error(:unique_notbool, rule, "#{path}/unique", val)
|
321
|
+
end
|
322
|
+
if @type == 'map' || @type == 'seq'
|
323
|
+
#* key=:unique_notscalar msg="is available only with a scalar type."
|
324
|
+
raise schema_error(:unique_notscalar, rule, path, "unique:")
|
325
|
+
end
|
326
|
+
if path.empty?
|
327
|
+
#* key=:unique_onroot msg="is not available on root element."
|
328
|
+
raise schema_error(:unique_onroot, rule, "/", "unique:")
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
def _init_sequence_value(val, rule, path, rule_table)
|
334
|
+
if val != nil && !val.is_a?(Array)
|
335
|
+
#* key=:sequence_notseq msg="not a sequence."
|
336
|
+
raise schema_error(:sequence_notseq, rule, "#{path}/sequence", val)
|
337
|
+
elsif val == nil || val.empty?
|
338
|
+
#* key=:sequence_noelem msg="required one element."
|
339
|
+
raise schema_error(:sequence_noelem, rule, "#{path}/sequence", val)
|
340
|
+
elsif val.length > 1
|
341
|
+
#* key=:sequence_toomany msg="required just one element."
|
342
|
+
raise schema_error(:sequence_toomany, rule, "#{path}/sequence", val)
|
343
|
+
else
|
344
|
+
elem = val[0]
|
345
|
+
elem ||= {}
|
346
|
+
i = 0 # or 1? *index*
|
347
|
+
rule = rule_table[elem.__id__]
|
348
|
+
rule ||= Rule.new(nil, self).init(elem, "#{path}/sequence/#{i}", rule_table)
|
349
|
+
@sequence = [ rule ]
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
def _init_mapping_value(val, rule, path, rule_table)
|
355
|
+
if val != nil && !val.is_a?(Hash)
|
356
|
+
#* key=:mapping_notmap msg="not a mapping."
|
357
|
+
raise schema_error(:mapping_notmap, rule, "#{path}/mapping", val)
|
358
|
+
elsif val == nil || (val.empty? && !val.default)
|
359
|
+
#* key=:mapping_noelem msg="required at least one element."
|
360
|
+
raise schema_error(:mapping_noelem, rule, "#{path}/mapping", val)
|
361
|
+
else
|
362
|
+
@mapping = {}
|
363
|
+
if val.default
|
364
|
+
elem = val.default # hash
|
365
|
+
rule = rule_table[elem.__id__]
|
366
|
+
rule ||= Rule.new(nil, self).init(elem, "#{path}/mapping/=", rule_table)
|
367
|
+
@mapping.default = rule
|
281
368
|
end
|
369
|
+
val.each do |k, v|
|
370
|
+
##* key=:key_duplicate msg="key duplicated."
|
371
|
+
#raise schema_error(:key_duplicate, rule, "#{path}/mapping", key) if @mapping.key?(key)
|
372
|
+
v ||= {}
|
373
|
+
rule = rule_table[v.__id__]
|
374
|
+
rule ||= Rule.new(nil, self).init(v, "#{path}/mapping/#{k}", rule_table)
|
375
|
+
if k == '='
|
376
|
+
@mapping.default = rule
|
377
|
+
else
|
378
|
+
@mapping[k] = rule
|
379
|
+
end
|
380
|
+
end if val
|
282
381
|
end
|
382
|
+
end
|
283
383
|
|
384
|
+
|
385
|
+
def check_confliction(hash, rule, path)
|
284
386
|
if @type == 'seq'
|
285
387
|
#* key=:seq_nosequence msg="type 'seq' requires 'sequence:'."
|
286
388
|
raise schema_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
|
@@ -310,28 +412,7 @@ module Kwalify
|
|
310
412
|
raise schema_error(:enum_conflict, rule, path, 'pattern:') if @pattern
|
311
413
|
end
|
312
414
|
end
|
313
|
-
|
314
|
-
return self
|
315
|
-
|
316
|
-
end # end of def configure
|
317
|
-
|
318
|
-
#attr_reader :id
|
319
|
-
attr_reader :name
|
320
|
-
attr_reader :desc
|
321
|
-
attr_reader :enum
|
322
|
-
attr_reader :required
|
323
|
-
attr_reader :type
|
324
|
-
attr_reader :klass
|
325
|
-
attr_reader :pattern
|
326
|
-
attr_reader :sequence
|
327
|
-
attr_reader :mapping
|
328
|
-
attr_reader :assert
|
329
|
-
attr_reader :assert_proc
|
330
|
-
attr_reader :range
|
331
|
-
attr_reader :length
|
332
|
-
attr_reader :ident
|
333
|
-
attr_reader :unique
|
334
|
-
|
415
|
+
end
|
335
416
|
|
336
417
|
#def inspect()
|
337
418
|
# str = ""; level = 0; done = {}
|
@@ -340,7 +421,7 @@ module Kwalify
|
|
340
421
|
#end
|
341
422
|
|
342
423
|
|
343
|
-
|
424
|
+
protected
|
344
425
|
|
345
426
|
|
346
427
|
def _inspect(str="", level=0, done={})
|
@@ -348,9 +429,9 @@ module Kwalify
|
|
348
429
|
str << " " * level << "name: #{@name}\n" if @name != nil
|
349
430
|
str << " " * level << "desc: #{@desc}\n" if @desc != nil
|
350
431
|
str << " " * level << "type: #{@type}\n" if @type != nil
|
351
|
-
str << " " * level << "klass: #{@
|
432
|
+
str << " " * level << "klass: #{@type_class.name}\n" if @type_class != nil
|
352
433
|
str << " " * level << "required: #{@required}\n" if @required != nil
|
353
|
-
str << " " * level << "pattern: #{@
|
434
|
+
str << " " * level << "pattern: #{@regexp.inspect}\n" if @pattern != nil
|
354
435
|
str << " " * level << "assert: #{@assert}\n" if @assert != nil
|
355
436
|
str << " " * level << "ident: #{@ident}\n" if @ident != nil
|
356
437
|
str << " " * level << "unique: #{@unique}\n" if @unique != nil
|
@@ -360,25 +441,31 @@ module Kwalify
|
|
360
441
|
str << " " * (level+1) << "- #{item}\n"
|
361
442
|
end
|
362
443
|
end
|
363
|
-
if @range
|
444
|
+
if @range != nil
|
364
445
|
str << " " * level
|
365
446
|
str << "range: { "
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
447
|
+
colon = ""
|
448
|
+
%w[max max-ex min min-ex].each do |key|
|
449
|
+
val = @range[key]
|
450
|
+
if val != nil
|
451
|
+
str << colon << "#{key}: #{val.inspect}"
|
452
|
+
colon = ", "
|
453
|
+
end
|
454
|
+
end
|
455
|
+
str << " }\n"
|
456
|
+
end
|
457
|
+
if @length != nil
|
374
458
|
str << " " * level
|
375
459
|
str << "length: { "
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
460
|
+
colon = ""
|
461
|
+
%w[max max-ex min min-ex].each do |key|
|
462
|
+
val = @length[key]
|
463
|
+
if val != nil
|
464
|
+
str << colon << "#{key}: #{val.inspect}"
|
465
|
+
colon = ", "
|
466
|
+
end
|
467
|
+
end
|
468
|
+
str << " }\n"
|
382
469
|
end
|
383
470
|
@sequence.each do |rule|
|
384
471
|
if done[rule.__id__]
|