kwalify 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  ###
2
- ### $Rev: 22 $
3
- ### $Release: 0.4.1 $
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-program.rb
18
- @@messages[:action_required] = "command-line option '-f' or '-m' required."
19
- @@messages[:meta_schema_empty] = "%s: empty.\n"
20
- @@messages[:meta_validation_valid] = "%s: ok.\n"
21
- @@messages[:meta_validation_invalid] = "%s: NG!\n"
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: 35 $
3
- ### $Release: 0.4.1 $
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
- META_SCHEMA = <<'END'
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 = Kwalify::DEFAULT_TYPE if type == nil
132
- unless type.is_a?(String)
133
- errors << validate_error(:type_notstr, rule, "#{path}/type", type.to_s)
134
- end
135
- klass = Kwalify.get_type_class(type)
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 type == 'seq' || type == 'map' # unless Kwalify.scalar_class?(klass)
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
- errors << validate_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s)
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
- errors << validate_error(:range_notmap, rule, curr_path, val)
182
- elsif type == 'seq' || type == 'map' || type == 'bool' || type == 'any'
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
- #case lkey
214
- #when 'max', 'min', 'max-ex', 'min-ex'
215
- unless lval.is_a?(Integer)
216
- errors << validate_error(:length_notint, rule, "#{curr_path}/#{lkey}", lval)
217
- end
218
- #else
219
- # errors << validate_error(:length_undefined, rule, curr_path, "#{lkey}:")
220
- #end
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 == 'map' || type == 'seq')
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 == 'map' || type == 'seq')
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
- errors << validate_error(:sequence_notseq, rule, "#{path}/sequence", val)
252
- elsif val == nil || val.empty?
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
- child = hash['sequence'][0]
258
- if child.is_a?(Hash)
259
- if child['ident'] && child['type'] != 'map'
260
- errors << validate_error(:ident_notmap, nil, "#{path}/sequence/0", 'ident:')
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
- schema = YAML.load(META_SCHEMA)
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
 
@@ -1,6 +1,6 @@
1
1
  ###
2
- ### $Rev: 39 $
3
- ### $Release: 0.4.1 $
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
- configure(hash, "", {}) if hash
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 configure(hash, path="", rule_table={})
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
- ## 'type:'
32
- @type = hash['type']
33
- @type = Kwalify::DEFAULT_TYPE if @type == nil
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
- @klass = Kwalify.get_type_class(@type)
39
- #if @klass == nil
90
+ @type_class = Types.type_class(@type)
91
+ #if @type_class == nil
40
92
  # begin
41
- # @klass = Kernel.const_get(@type)
93
+ # @type_class = Kernel.const_get(@type)
42
94
  # rescue NameError
43
95
  # end
44
96
  #end
45
- unless @klass
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
- when "desc"
60
- @desc = val
104
+ def _init_name_value(val, rule, path)
105
+ @name = val
106
+ end
61
107
 
62
- when "type"
63
- # done
64
108
 
65
- when "required"
66
- @required = val
67
- unless val.is_a?(Boolean) #|| val == nil
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
- when "enum"
89
- @enum = val
90
- unless val.is_a?(Array)
91
- #* key=:enum_notseq msg="not a sequence."
92
- raise schema_error(:enum_notseq, rule, curr_path, val)
93
- end
94
- if @type == 'seq' || @type == 'map' # unless Kwalify.scalar_class?(@klass)
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
- when "assert" # or "cond-expr" ?
112
- @assert = val
113
- unless val.is_a?(String)
114
- #* key=:assert_notstr msg="not a string."
115
- raise schema_error(:assert_notstr, rule, curr_path, val)
116
- end
117
- unless val =~ /\bval\b/
118
- #* key=:assert_noval msg="'val' is not used."
119
- raise schema_error(:assert_noval, rule, curr_path, val)
120
- end
121
- begin
122
- @assert_proc = eval "proc { |val| #{val} }"
123
- rescue SyntaxError => ex
124
- #* key=:assert_syntaxerr msg="expression syntax error."
125
- raise schema_error(:assert_syntaxerr, rule, curr_path, val)
126
- end
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
- when "length" # or "width"
161
- @length = val
162
- unless val.is_a?(Hash)
163
- #* key=:length_notmap msg="not a mapping."
164
- raise schema_error(:length_notmap, rule, curr_path, val)
165
- end
166
- unless @type == 'str' || @type == 'text'
167
- #* key=:length_nottext msg="is available only with string or text."
168
- raise schema_error(:length_nottext, rule, path, 'length:')
169
- end
170
- val.each do |lkey, lval|
171
- case lkey
172
- when 'max', 'min', 'max-ex', 'min-ex'
173
- unless lval.is_a?(Integer)
174
- #* key=:length_notint msg="not an integer."
175
- raise schema_error(:length_notint, rule, "#{curr_path}/#{lkey}", lval)
176
- end
177
- else
178
- #* key=:length_undefined msg="undefined key."
179
- raise schema_error(:length_undefined, rule, "#{curr_path}/#{lkey}", "#{lkey}:")
180
- end
181
- end
182
- if val.key?('max') && val.key?('max-ex')
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
- when "unique"
212
- @unique = val
213
- unless val.is_a?(Boolean)
214
- #* key=:unique_notbool msg="not a boolean."
215
- raise schema_error(:unique_notbool, rule, curr_path, val)
216
- end
217
- if @type == 'map' || @type == 'seq'
218
- #* key=:unique_notscalar msg="is available only with a scalar type."
219
- raise schema_error(:unique_notscalar, rule, path, "unique:")
220
- end
221
- if path.empty?
222
- #* key=:unique_onroot msg="is not available on root element."
223
- raise schema_error(:unique_onroot, rule, "/", "unique:")
224
- end
225
- #unless @parent && @parent.type == 'map'
226
- # #* key=:unique_notmap msg="is available only with an element of mapping."
227
- # raise schema_error(:unique_notmap, rule, path, "unique:")
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
- when "mapping"
250
- if val != nil && !val.is_a?(Hash)
251
- #* key=:mapping_notmap msg="not a mapping."
252
- raise schema_error(:mapping_notmap, rule, curr_path, val)
253
- elsif val == nil || (val.empty? && !val.default)
254
- #* key=:mapping_noelem msg="required at least one element."
255
- raise schema_error(:mapping_noelem, rule, curr_path, val)
256
- else
257
- @mapping = {}
258
- if val.default
259
- elem = val.default # hash
260
- rule = rule_table[elem.__id__]
261
- rule ||= Rule.new(nil, self).configure(elem, "#{curr_path}/=", rule_table)
262
- @mapping.default = rule
263
- end
264
- val.each do |key, elem|
265
- ##* key=:key_duplicate msg="key duplicated."
266
- #raise schema_error(:key_duplicate, rule, curr_path, key) if @mapping.key?(key)
267
- elem ||= {}
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=:key_unknown msg="unknown key."
280
- raise schema_error(:key_unknown, rule, curr_path, "#{key}:")
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
- #protected
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: #{@klass.name}\n" if @klass != nil
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: #{@pattern.inspect}\n" if @pattern != nil
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 != nil
444
+ if @range != nil
364
445
  str << " " * level
365
446
  str << "range: { "
366
- str << "max: #{@range['max'].inspect}" if @range['max'] != nil
367
- str << "max-ex: #{@range['max-ex'].inspect}" if @range['max-ex'] != nil
368
- str << ", " if (@range['max'] || @range['max-ex']) && (@range['min'] || @range['min-ex'])
369
- str << "min: #{@range['min'].inspect}" if @range['min'] != nil
370
- str << "min-ex: #{@range['min-ex'].inspect}" if @range['min-ex'] != nil
371
- str << "}\n"
372
- end
373
- if @length != nil
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
- str << "max: #{@length['max'].inspect}" if @length['max'] != nil
377
- str << "max-ex: #{@length['max-ex'].inspect}" if @length['max-ex'] != nil
378
- str << ", " if (@length['max'] || @length['max-ex']) && (@length['min'] || @length['min-ex'])
379
- str << "min: #{@length['min'].inspect}" if @length['min'] != nil
380
- str << "min-ex: #{@length['min-ex'].inspect}" if @length['min-ex'] != nil
381
- str << "}\n"
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__]