kwalify 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/kwalify/rule.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  ###
2
- ### $Rev: 22 $
3
- ### $Release: 0.3.0 $
2
+ ### $Rev: 35 $
3
+ ### $Release: 0.4.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
@@ -250,23 +250,29 @@ module Kwalify
250
250
  if val != nil && !val.is_a?(Hash)
251
251
  #* key=:mapping_notmap msg="not a mapping."
252
252
  raise schema_error(:mapping_notmap, rule, curr_path, val)
253
- elsif val == nil || val.empty?
253
+ elsif val == nil || (val.empty? && !val.default)
254
254
  #* key=:mapping_noelem msg="required at least one element."
255
255
  raise schema_error(:mapping_noelem, rule, curr_path, val)
256
256
  else
257
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
258
264
  val.each do |key, elem|
259
265
  ##* key=:key_duplicate msg="key duplicated."
260
266
  #raise schema_error(:key_duplicate, rule, curr_path, key) if @mapping.key?(key)
261
267
  elem ||= {}
262
268
  rule = rule_table[elem.__id__]
263
269
  rule ||= Rule.new(nil, self).configure(elem, "#{curr_path}/#{key}", rule_table)
264
- if key == '*'
270
+ if key == '='
265
271
  @mapping.default = rule
266
272
  else
267
273
  @mapping[key] = rule
268
274
  end
269
- end
275
+ end if val
270
276
  end
271
277
 
272
278
  else
@@ -277,7 +283,7 @@ module Kwalify
277
283
 
278
284
  if @type == 'seq'
279
285
  #* key=:seq_nosequence msg="type 'seq' requires 'sequence:'."
280
- raise Kwalify.validate_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
286
+ raise schema_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
281
287
  #* key=:seq_conflict msg="not available with sequence."
282
288
  raise schema_error(:seq_conflict, rule, path, 'enum:') if @enum
283
289
  raise schema_error(:seq_conflict, rule, path, 'pattern:') if @pattern
@@ -286,7 +292,7 @@ module Kwalify
286
292
  raise schema_error(:seq_conflict, rule, path, 'length:') if @length
287
293
  elsif @type == 'map'
288
294
  #* key=:map_nomapping msg="type 'map' requires 'mapping:'."
289
- raise Kwalify.validate_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping')
295
+ raise schema_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping')
290
296
  #* key=:map_conflict msg="not available with mapping."
291
297
  raise schema_error(:map_conflict, rule, path, 'enum:') if @enum
292
298
  raise schema_error(:map_conflict, rule, path, 'pattern:') if @pattern
data/lib/kwalify/types.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  ###
2
- ### $Rev: 18 $
3
- ### $Release: 0.3.0 $
2
+ ### $Rev: 25 $
3
+ ### $Release: 0.4.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
@@ -114,20 +114,21 @@ module Kwalify
114
114
 
115
115
 
116
116
  module TypeHelper
117
- def collection_class?(klass)
118
- return klass == Array || klass == Hash
119
- end
120
-
121
- def scalar_class?(klass)
122
- return klass != Array && klass != Hash && klass != Object
123
- end
117
+ #--
118
+ #def collection_class?(klass)
119
+ # return klass.is_a?(Array) || klass.is_a?(Hash)
120
+ #end
121
+ #
122
+ #def scalar_class?(klass)
123
+ # return !klass.is_a?(Array) && !klass.is_a?(Hash) && klass != Object
124
+ #end
124
125
 
125
126
  def collection?(val)
126
- return collection_class?(val.class)
127
+ return val.is_a?(Array) || val.is_a?(Hash)
127
128
  end
128
129
 
129
130
  def scalar?(val)
130
- return scalar_class?(val.class)
131
+ return !val.is_a?(Array) && !val.is_a?(Hash) && val.class != Object
131
132
  end
132
133
  end
133
134
 
@@ -1,6 +1,6 @@
1
1
  ###
2
2
  ### $Rev: 5 $
3
- ### $Release: 0.3.0 $
3
+ ### $Release: 0.4.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
@@ -1,6 +1,6 @@
1
1
  ###
2
2
  ### $Rev: 6 $
3
- ### $Release: 0.3.0 $
3
+ ### $Release: 0.4.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
@@ -1,6 +1,6 @@
1
1
  ###
2
2
  ### $Rev: 10 $
3
- ### $Release: 0.3.0 $
3
+ ### $Release: 0.4.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
@@ -1,6 +1,6 @@
1
1
  ###
2
- ### $Rev: 21 $
3
- ### $Release: 0.3.0 $
2
+ ### $Rev: 32 $
3
+ ### $Release: 0.4.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
@@ -39,9 +39,9 @@ module Kwalify
39
39
  end
40
40
 
41
41
 
42
- def validate(val)
42
+ def validate(value)
43
43
  path = ""; errors = []; done = {}
44
- _validate(val, @rule, path, errors, done)
44
+ _validate(value, @rule, path, errors, done)
45
45
  return errors
46
46
  end
47
47
 
@@ -49,107 +49,107 @@ module Kwalify
49
49
  protected
50
50
 
51
51
 
52
- def validate_hook(val, rule, path, errors)
52
+ def validate_hook(value, rule, path, errors)
53
53
  end
54
54
 
55
55
 
56
- def _validate(val, rule, path, errors, done)
57
- if Kwalify.collection_class?(val.class)
58
- return true if done[val.__id__] # avoid infinite loop
59
- done[val.__id__] = true
56
+ def _validate(value, rule, path, errors, done)
57
+ if Kwalify.collection?(value)
58
+ return true if done[value.__id__] # avoid infinite loop
59
+ done[value.__id__] = true
60
60
  end
61
- if rule.required && val == nil
61
+ if rule.required && value == nil
62
62
  #* key=:required_novalue msg="value required but none."
63
- errors << validate_error(:required_novalue, rule, path, val)
63
+ errors << validate_error(:required_novalue, rule, path, value)
64
64
  return
65
65
  end
66
- if rule.klass && val != nil && !val.is_a?(rule.klass)
66
+ if rule.klass && value != nil && !value.is_a?(rule.klass)
67
67
  #* key=:type_unmatch msg="not a %s."
68
- errors << validate_error(:type_unmatch, rule, path, val, [Kwalify.word(rule.type)])
68
+ errors << validate_error(:type_unmatch, rule, path, value, [Kwalify.word(rule.type)])
69
69
  return
70
70
  end
71
71
  #
72
72
  n = errors.length
73
73
  if rule.sequence
74
- _validate_sequence(val, rule, path, errors, done)
74
+ _validate_sequence(value, rule, path, errors, done)
75
75
  elsif rule.mapping
76
- _validate_mapping(val, rule, path, errors, done)
76
+ _validate_mapping(value, rule, path, errors, done)
77
77
  else
78
- _validate_scalar(val, rule, path, errors, done)
78
+ _validate_scalar(value, rule, path, errors, done)
79
79
  end
80
80
  return unless errors.length == n
81
81
  #
82
- validate_hook(val, rule, path, errors)
83
- @block.call(val, rule, path, errors) if @block
82
+ validate_hook(value, rule, path, errors)
83
+ @block.call(value, rule, path, errors) if @block
84
84
  end
85
85
 
86
86
 
87
87
  private
88
88
 
89
89
 
90
- def _validate_scalar(val, rule, path, errors, done)
90
+ def _validate_scalar(value, rule, path, errors, done)
91
91
  assert_error("rule.sequence.class==#{rule.sequence.class.name} (expected NilClass)") if rule.sequence
92
92
  assert_error("rule.mapping.class==#{rule.mapping.class.name} (expected NilClass)") if rule.mapping
93
93
  if rule.assert_proc
94
- unless rule.assert_proc.call(val)
94
+ unless rule.assert_proc.call(value)
95
95
  #* key=:assert_failed msg="assertion expression failed (%s)."
96
- errors << validate_error(:assert_failed, rule, path, val, [rule.assert])
96
+ errors << validate_error(:assert_failed, rule, path, value, [rule.assert])
97
97
  end
98
98
  end
99
99
  if rule.enum
100
- unless rule.enum.include?(val)
100
+ unless rule.enum.include?(value)
101
101
  keyname = File.basename(path)
102
102
  keyname = 'enum' if keyname =~ /\A\d+\z/
103
103
  #* key=:enum_notexist msg="invalid %s value."
104
- errors << validate_error(:enum_notexist, rule, path, val, [keyname])
104
+ errors << validate_error(:enum_notexist, rule, path, value, [keyname])
105
105
  end
106
106
  end
107
107
  #
108
- return if val == nil
108
+ return if value == nil
109
109
  #
110
110
  if rule.pattern
111
- unless val.to_s =~ rule.pattern
111
+ unless value.to_s =~ rule.pattern
112
112
  #* key=:pattern_unmatch msg="not matched to pattern %s."
113
- errors << validate_error(:pattern_unmatch, rule, path, val, [rule.pattern.inspect])
113
+ errors << validate_error(:pattern_unmatch, rule, path, value, [rule.pattern.inspect])
114
114
  end
115
115
  end
116
116
  if rule.range
117
- assert_error("val.class=#{val.class.name}") unless Kwalify.scalar?(val)
118
- if rule.range['max'] && rule.range['max'] < val
117
+ assert_error("value.class=#{value.class.name}") unless Kwalify.scalar?(value)
118
+ if rule.range['max'] && rule.range['max'] < value
119
119
  #* key=:range_toolarge msg="too large (> max %s)."
120
- errors << validate_error(:range_toolarge, rule, path, val, [rule.range['max'].to_s])
120
+ errors << validate_error(:range_toolarge, rule, path, value, [rule.range['max'].to_s])
121
121
  end
122
- if rule.range['min'] && rule.range['min'] > val
122
+ if rule.range['min'] && rule.range['min'] > value
123
123
  #* key=:range_toosmall msg="too small (< min %s)."
124
- errors << validate_error(:range_toosmall, rule, path, val, [rule.range['min'].to_s])
124
+ errors << validate_error(:range_toosmall, rule, path, value, [rule.range['min'].to_s])
125
125
  end
126
- if rule.range['max-ex'] && rule.range['max-ex'] <= val
126
+ if rule.range['max-ex'] && rule.range['max-ex'] <= value
127
127
  #* key=:range_toolargeex msg="too large (>= max %s)."
128
- errors << validate_error(:range_toolargeex, rule, path, val, [rule.range['max-ex'].to_s])
128
+ errors << validate_error(:range_toolargeex, rule, path, value, [rule.range['max-ex'].to_s])
129
129
  end
130
- if rule.range['min-ex'] && rule.range['min-ex'] >= val
130
+ if rule.range['min-ex'] && rule.range['min-ex'] >= value
131
131
  #* key=:range_toosmallex msg="too small (<= min %s)."
132
- errors << validate_error(:range_toosmallex, rule, path, val, [rule.range['min-ex'].to_s])
132
+ errors << validate_error(:range_toosmallex, rule, path, value, [rule.range['min-ex'].to_s])
133
133
  end
134
134
  end
135
135
  if rule.length
136
- assert_error("val.class=#{val.class.name}") unless val.is_a?(String) || val.is_a?(Text)
137
- len = val.to_s.length
136
+ assert_error("value.class=#{value.class.name}") unless value.is_a?(String) || value.is_a?(Text)
137
+ len = value.to_s.length
138
138
  if rule.length['max'] && rule.length['max'] < len
139
139
  #* key=:length_toolong msg="too long (length %d > max %d)."
140
- errors << validate_error(:length_toolong, rule, path, val, [len, rule.length['max']])
140
+ errors << validate_error(:length_toolong, rule, path, value, [len, rule.length['max']])
141
141
  end
142
142
  if rule.length['min'] && rule.length['min'] > len
143
143
  #* key=:length_tooshort msg="too short (length %d < min %d)."
144
- errors << validate_error(:length_tooshort, rule, path, val, [len, rule.length['min']])
144
+ errors << validate_error(:length_tooshort, rule, path, value, [len, rule.length['min']])
145
145
  end
146
146
  if rule.length['max-ex'] && rule.length['max-ex'] <= len
147
147
  #* key=:length_toolongex msg="too long (length %d >= max %d)."
148
- errors << validate_error(:length_toolongex, rule, path, val, [len, rule.length['max-ex']])
148
+ errors << validate_error(:length_toolongex, rule, path, value, [len, rule.length['max-ex']])
149
149
  end
150
150
  if rule.length['min-ex'] && rule.length['min-ex'] >= len
151
151
  #* key=:length_tooshortex msg="too short (length %d <= min %d)."
152
- errors << validate_error(:length_tooshortex, rule, path, val, [len, rule.length['min-ex']])
152
+ errors << validate_error(:length_tooshortex, rule, path, value, [len, rule.length['min-ex']])
153
153
  end
154
154
  end
155
155
  end
@@ -191,7 +191,7 @@ module Kwalify
191
191
  # #* key=:value_notunique msg="is already used at '%s'."
192
192
  errors << validate_error(:value_notunique, rule, "#{path}/#{i}", val, "#{path}/#{table[val]}")
193
193
  else
194
- table[val] = i
194
+ table[val] = i
195
195
  end
196
196
  end
197
197
  end
@@ -207,15 +207,15 @@ module Kwalify
207
207
  errors << validate_error(:required_nokey, rule, path, hash, [key])
208
208
  end
209
209
  end
210
- hash.each do |key, value|
210
+ hash.each do |key, val|
211
211
  rule = map_rule.mapping[key]
212
- if rule
213
- _validate(value, rule, "#{path}/#{key}", errors, done) ## validate recursively
214
- else
212
+ unless rule
215
213
  #* key=:key_undefined msg="key '%s' is undefined."
216
- errors << validate_error(:key_undefined, rule, path, nil, ["#{key}:"])
214
+ errors << validate_error(:key_undefined, rule, path, hash, ["#{key}:"])
217
215
  ##* key=:key_undefined msg="undefined key."
218
216
  #errors << validate_error(:key_undefined, rule, path, "#{key}:")
217
+ else
218
+ _validate(val, rule, "#{path}/#{key}", errors, done) ## validate recursively
219
219
  end
220
220
  end
221
221
  end
@@ -223,3 +223,11 @@ module Kwalify
223
223
  end
224
224
 
225
225
  end
226
+
227
+ if __FILE__ == $0
228
+ require 'kwalify/parser'
229
+ parser = Kwalify::Parser.new(File.read(ARGV.shift))
230
+ schema = parser.parse()
231
+ validator = Kwalify::Validator.new(schema)
232
+ YARGF.read()
233
+ end
@@ -1,20 +1,21 @@
1
1
  ###
2
- ### $Rev: 21 $
3
- ### $Release: 0.3.0 $
2
+ ### $Rev: 31 $
3
+ ### $Release: 0.4.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
7
- if $0 == __FILE__
8
- testdir = File.dirname(__FILE__)
9
- libdir = File.dirname(testdir) + "/lib"
10
- $LOAD_PATH << libdir << testdir
11
- require 'test/unit'
12
- require 'test/unit/ui/console/testrunner'
13
- require 'kwalify'
14
- require 'kwalify/util/assert-diff'
15
- require 'yaml'
7
+ unless defined?(TESTDIR)
8
+ TESTDIR = File.dirname(__FILE__)
9
+ libdir = File.dirname(TESTDIR) + "/lib"
10
+ $LOAD_PATH << libdir << TESTDIR
16
11
  end
17
12
 
13
+ require 'test/unit'
14
+ require 'test/unit/ui/console/testrunner'
15
+ require 'kwalify'
16
+ require 'kwalify/util/assert-diff'
17
+ require 'yaml'
18
+
18
19
 
19
20
  class MetaValidatorTest < Test::Unit::TestCase
20
21
 
@@ -80,6 +81,10 @@ class MetaValidatorTest < Test::Unit::TestCase
80
81
 
81
82
  end
82
83
 
84
+ #if $0 == __FILE__
85
+ # Test::Unit::UI::Console::TestRunner.run(MetaValidatorTest)
86
+ #end
87
+
83
88
  __END__
84
89
  ---
85
90
  name: schema_notmap
@@ -0,0 +1,1276 @@
1
+ ###
2
+ ### $Rev: 35 $
3
+ ### $Release: 0.4.0 $
4
+ ### copyright(c) 2005 kuwata-lab all rights reserved.
5
+ ###
6
+
7
+ unless defined?(TESTDIR)
8
+ TESTDIR = File.dirname(__FILE__)
9
+ libdir = File.dirname(TESTDIR) + "/lib"
10
+ $LOAD_PATH << libdir << TESTDIR
11
+ end
12
+
13
+ require 'test/unit'
14
+ require 'test/unit/ui/console/testrunner'
15
+ require 'kwalify'
16
+ require 'kwalify/util/assert-diff'
17
+ require 'yaml'
18
+ require 'pp'
19
+ require 'stringio'
20
+
21
+
22
+ class ParserTest < Test::Unit::TestCase
23
+ def _test()
24
+ parser = Kwalify::Parser.new(@input)
25
+ if @error_class
26
+ assert_raise(@error_class) do
27
+ doc = parser.parse()
28
+ end
29
+ else
30
+ doc = parser.parse()
31
+ sio = StringIO.new
32
+ PP.pp(doc, sio)
33
+ actual = sio.string
34
+ if $log
35
+ File.open("#{@name}.expected", 'w') { |f| f.write(@expected) }
36
+ File.open("#{@name}.actual", 'w') { |f| f.write(actual) }
37
+ end
38
+ if $print
39
+ print actual
40
+ else
41
+ assert_equal_with_diff(@expected, actual)
42
+ end
43
+ end
44
+ end
45
+
46
+ #str = DATA.read() # doesn't work when required by other script
47
+ str = File.read(__FILE__)
48
+ str.gsub!(/.*^__END__$/m, '')
49
+ doc_table = {}
50
+ YAML.load_documents(str) do |doc|
51
+ name = doc['name']
52
+ raise "name '#{name}' is duplicated." if doc_table[name]
53
+ doc_table[name] = doc
54
+ next if $target && $target != doc['name']
55
+ #if $target && $show
56
+ # puts doc.to_yaml
57
+ # exit
58
+ #end
59
+ s = <<-END
60
+ def test_#{name}
61
+ @name = #{doc['name'].dump}
62
+ @input = #{doc['input'].dump}
63
+ @expected = #{doc['expected'].dump}
64
+ @error_class = #{doc['error'] ? doc['error'] : 'nil'}
65
+ @option = #{doc['option'] ? doc['option'].dump : 'nil'}
66
+ _test()
67
+ end
68
+ END
69
+ if $target && $show
70
+ puts s
71
+ exit
72
+ end
73
+ eval s
74
+ end
75
+ end
76
+
77
+ #if $0 == __FILE__
78
+ # Test::Unit::UI::Console::TestRunner.run(ParserTest)
79
+ #end
80
+
81
+ __END__
82
+ ---
83
+ name: parse01
84
+ desc: basic
85
+ #flag: print
86
+ #
87
+ input: |
88
+ - AAA
89
+ - BBB
90
+ - CCC
91
+ #
92
+ expected: |
93
+ ["AAA", "BBB", "CCC"]
94
+ #
95
+ ---
96
+ name: parse02
97
+ desc: scalar
98
+ #
99
+ input: |
100
+ - abc
101
+ - 123
102
+ - 3.14
103
+ - true
104
+ - false
105
+ - yes
106
+ - no
107
+ - ~
108
+ - null
109
+ - "123"
110
+ - '456'
111
+ - 2005-01-01
112
+ - :sym
113
+ #
114
+ expected: |
115
+ ["abc",
116
+ 123,
117
+ 3.14,
118
+ true,
119
+ false,
120
+ true,
121
+ false,
122
+ nil,
123
+ nil,
124
+ "123",
125
+ "456",
126
+ #<Date: 4906743/2,0,2299161>,
127
+ :sym]
128
+ # ["abc", 123, true, false, true, false, nil, nil, "123", "456", #<Date: 4906743/2,0,2299161>, :sym]
129
+ #
130
+ ---
131
+ name: parse03
132
+ desc: nested sequence
133
+ #
134
+ input: |
135
+ - AAA
136
+ -
137
+ - BBB1
138
+ - BBB2
139
+ - CCC
140
+ #
141
+ expected: |
142
+ ["AAA", ["BBB1", "BBB2"], "CCC"]
143
+ #
144
+ ---
145
+ name: parse04
146
+ desc: nested sequence #2
147
+ #
148
+ input: |
149
+ - A
150
+ -
151
+ - B1
152
+ -
153
+ - B1-1
154
+ - B1-2
155
+ - C
156
+ #
157
+ expected: |
158
+ ["A", ["B1", ["B1-1", "B1-2"]], "C"]
159
+ #
160
+ ---
161
+ name: parse05
162
+ desc: null item of sequence
163
+ #
164
+ input: |
165
+ - A
166
+ -
167
+ - C
168
+ -
169
+ -
170
+ -
171
+ - G
172
+ #
173
+ expected: |
174
+ ["A", nil, "C", nil, nil, nil, "G"]
175
+ #
176
+ ---
177
+ name: parse06
178
+ desc: null item of nested sequence
179
+ #
180
+ input: |
181
+ -
182
+ -
183
+ -
184
+ -
185
+ -
186
+ -
187
+ #
188
+ expected: |
189
+ [[[nil, nil, nil]], nil]
190
+ #
191
+ ---
192
+ name: parse07
193
+ desc: sequence with empty lines
194
+ #
195
+ input: |
196
+
197
+ - A
198
+
199
+ -
200
+
201
+
202
+ - B
203
+
204
+
205
+ -
206
+ #
207
+ expected: |
208
+ ["A", ["B"], nil]
209
+ #
210
+ ---
211
+ name: parse08
212
+ desc: syntax error - invalid indent of sequence.
213
+ error: Kwalify::ParseError
214
+ #
215
+ input: |
216
+ - AAA
217
+ - BBB1
218
+ - BBB2
219
+ - CCC
220
+ #
221
+ expected: |
222
+ #
223
+ ---
224
+ name: parse09
225
+ desc: syntax error - sequence item is exepcted.
226
+ error: Kwalify::ParseError
227
+ #
228
+ input: |
229
+ -
230
+ - a1
231
+ - a2
232
+ a3
233
+ -
234
+ - b1
235
+ - b2
236
+ b3
237
+ #
238
+ expected: |
239
+ #
240
+ ---
241
+ name: parse11
242
+ desc: mapping
243
+ #
244
+ input: |
245
+ A: foo
246
+ B: bar
247
+ C : baz
248
+ #
249
+ expected: |
250
+ {"A"=>"foo", "B"=>"bar", "C"=>"baz"}
251
+ ---
252
+ name: parse12
253
+ desc: mapping of scalar
254
+ #
255
+ input: |
256
+ abc: ABC
257
+ 123: 1.23
258
+ 3.14: 314
259
+ #
260
+ expected: |
261
+ {"abc"=>"ABC", 3.14=>314, 123=>1.23}
262
+ ---
263
+ name: parse12b
264
+ desc: mapping of scalar
265
+ #
266
+ input: |
267
+ true: yes
268
+ false: no
269
+ #
270
+ expected: |
271
+ {false=>false, true=>true}
272
+ #
273
+ ---
274
+ name: parse12c
275
+ desc: mapping of scalar
276
+ #
277
+ input: |
278
+ :sym: :symbol
279
+ --: -10
280
+ #
281
+ expected: |
282
+ {"--"=>-10, :sym=>:symbol}
283
+ #
284
+ ---
285
+ name: parse13
286
+ desc: nested mapping
287
+ #
288
+ input: |
289
+ A: 10
290
+ B:
291
+ B1: 21
292
+ B2: 22
293
+ C: 30
294
+ #
295
+ expected: |
296
+ {"A"=>10, "B"=>{"B1"=>21, "B2"=>22}, "C"=>30}
297
+ #
298
+ ---
299
+ name: parse14
300
+ desc: nested mapping #2
301
+ #
302
+ input: |
303
+ A: 10
304
+ B:
305
+ B1:
306
+ B1-1: 21
307
+ B1-2: 22
308
+ B1-3: 23
309
+ C: 30
310
+ #
311
+ expected: |
312
+ {"A"=>10, "B"=>{"B1"=>{"B1-1"=>21, "B1-2"=>22, "B1-3"=>23}}, "C"=>30}
313
+ #
314
+ ---
315
+ name: parse15
316
+ desc: null item in mapping
317
+ #
318
+ input: |
319
+ A:
320
+ B:
321
+ C:
322
+ D:
323
+ #
324
+ expected: |
325
+ {"A"=>nil, "B"=>nil, "C"=>nil, "D"=>nil}
326
+ #
327
+ ---
328
+ name: parse16
329
+ desc: null mapping
330
+ #
331
+ input: |
332
+ A:
333
+ B:
334
+ B1:
335
+ B1-2:
336
+ C:
337
+ #
338
+ expected: |
339
+ {"A"=>nil, "B"=>{"B1"=>{"B1-2"=>nil}}, "C"=>nil}
340
+ #
341
+ ---
342
+ name: parse17
343
+ desc: mapping with empty lines
344
+ #
345
+ input: |
346
+
347
+ A: 1
348
+
349
+ B:
350
+
351
+
352
+ B1:
353
+
354
+
355
+
356
+ B1a: 2
357
+ C: 3
358
+
359
+ #
360
+ expected: |
361
+ {"A"=>1, "B"=>{"B1"=>{"B1a"=>2}}, "C"=>3}
362
+ #
363
+ ---
364
+ name: parse18
365
+ desc: parse error - invalid indent of mapping.
366
+ error: Kwalify::ParseError
367
+ #
368
+ input: |
369
+ A: 10
370
+ B: 20
371
+ B1: 21
372
+ B2: 22
373
+ C: 30
374
+ #
375
+ expected: |
376
+
377
+ #
378
+ ---
379
+ name: parse19
380
+ desc: parse error - mapping item is expected.
381
+ error: Kwalify::ParseError
382
+ #
383
+ input: |
384
+ A:
385
+ a1: 1
386
+ a2: 2
387
+ a3 3
388
+ B:
389
+ b1: 1
390
+ b2: 2
391
+ b3 3
392
+ expected: |
393
+ #
394
+ ---
395
+ name: parse21
396
+ desc: seq of mapping
397
+ #
398
+ input: |
399
+ -
400
+ x: 10
401
+ y: 20
402
+ -
403
+ x: 15
404
+ y: 25
405
+ #
406
+ expected: |
407
+ [{"x"=>10, "y"=>20}, {"x"=>15, "y"=>25}]
408
+ ---
409
+ name: parse22
410
+ desc: seq of mapping (inline)
411
+ #
412
+ input: |
413
+ - x: 10
414
+ y: 20
415
+ - x: 15
416
+ y: 25
417
+ #
418
+ expected: |
419
+ [{"x"=>10, "y"=>20}, {"x"=>15, "y"=>25}]
420
+ ---
421
+ name: parse23
422
+ desc: seq of seq of seq (inline)
423
+ #
424
+ input: |
425
+ - - - a
426
+ - b
427
+ - - - c
428
+ - d
429
+ #
430
+ expected: |
431
+ [[["a", "b"]], [["c", "d"]]]
432
+ ---
433
+ name: parse24
434
+ desc: map of sequence
435
+ #
436
+ input: |
437
+ foo:
438
+ - 1
439
+ - 2
440
+ - 3
441
+ bar:
442
+ - 4
443
+ - 5
444
+ - 6
445
+ #
446
+ expected: |
447
+ {"foo"=>[1, 2, 3], "bar"=>[4, 5, 6]}
448
+ ---
449
+ name: parse25
450
+ desc: map of sequence (inline)
451
+ #
452
+ input: |
453
+ foo: - 1
454
+ - 2
455
+ - 3
456
+ bar: - 4
457
+ - 5
458
+ - 6
459
+ #
460
+ expected: |
461
+ {"foo"=>[1, 2, 3], "bar"=>[4, 5, 6]}
462
+ ---
463
+ name: parse26
464
+ desc: map of map of map (inline)
465
+ #
466
+ input: |
467
+ A: a: 1: 100
468
+ 2: 200
469
+ B: b: 3: 300
470
+ 4: 400
471
+ #
472
+ expected: |
473
+ {"A"=>{"a"=>{1=>100, 2=>200}}, "B"=>{"b"=>{3=>300, 4=>400}}}
474
+ ---
475
+ name: comment1
476
+ desc: line comment
477
+ #
478
+ input: |
479
+ # comment
480
+ - A
481
+ - B
482
+ # comment
483
+ -
484
+ # comment
485
+ - C
486
+ #
487
+ expected: |
488
+ ["A", "B", ["C"]]
489
+ ---
490
+ name: comment2
491
+ desc: escape line comment
492
+ #
493
+ input: |
494
+ # comment
495
+ - A
496
+ - B:
497
+ "# comment"
498
+ -
499
+ '# comment'
500
+ #
501
+ expected: |
502
+ ["A", {"B"=>"# comment"}, "# comment"]
503
+ ---
504
+ name: comment3
505
+ desc: line comment with seq and map
506
+ #
507
+ input: |
508
+ - A # comment
509
+ - B: # comment
510
+ C: foo # comment
511
+ D: "bar#bar" #comment
512
+ #
513
+ expected: |
514
+ ["A", {"B"=>{"C"=>"foo", "D"=>"bar#bar"}}]
515
+ ---
516
+ name: comment4
517
+ desc: line comment with anchor and alias
518
+ #
519
+ input: |
520
+ - &a1 # comment
521
+ foo
522
+ - *a1 # comment
523
+ #
524
+ expected: |
525
+ ["foo", "foo"]
526
+ ---
527
+ name: flowseq1
528
+ desc: flow style seq
529
+ #
530
+ input: |
531
+ - [ 10, 20 ]
532
+ - [15,25,35]
533
+ #
534
+ expected: |
535
+ [[10, 20], [15, 25, 35]]
536
+ #
537
+ ---
538
+ name: flowseq2
539
+ desc: nested flow style seq
540
+ #
541
+ input: |
542
+ 1: [ A, [B1, B2]]
543
+ 2: [[[X]]]
544
+ 3: [[x1,y1],[x2,"y2"],['x3',y3]]
545
+ #
546
+ expected: |
547
+ {1=>["A", ["B1", "B2"]],
548
+ 2=>[[["X"]]],
549
+ 3=>[["x1", "y1"], ["x2", "y2"], ["x3", "y3"]]}
550
+ #
551
+ ---
552
+ name: flowseq3
553
+ desc: flow style seq with some lines
554
+ #
555
+ input: |
556
+ A: [ [10,20],
557
+ [11,21],
558
+ [12,22]]
559
+ B: [
560
+ [1.1,
561
+ 1.2,
562
+ 1.3
563
+ ]
564
+ ]
565
+ #
566
+ expected: |
567
+ {"A"=>[[10, 20], [11, 21], [12, 22]], "B"=>[[1.1, 1.2, 1.3]]}
568
+ #
569
+ ---
570
+ name: flowseq4
571
+ desc: invalid flow style seq (sequence item required (or last comma is extra).)
572
+ mesg: sequence item required (or last comma is extra).
573
+ error: Kwalify::ParseError
574
+ #
575
+ input: |
576
+ A: [ [10,20], ]
577
+ #
578
+ expected: |
579
+ #
580
+ ---
581
+ name: flowseq5
582
+ desc: invalid flow style seq (flow style sequence requires ']').
583
+ mesg: flow style sequence requires ']'
584
+ error: Kwalify::ParseError
585
+ #
586
+ input: |
587
+ A: [ [10,20]
588
+ B: [ [30, 40]]
589
+ #
590
+ expected: |
591
+ #
592
+ ---
593
+ name: flowseq6
594
+ desc: invalid flow style seq (flow style sequence requires ']').
595
+ mesg: flow style sequence is closed but got ']'.
596
+ error: Kwalify::ParseError
597
+ #
598
+ input: |
599
+ [ 10 ]]
600
+ #
601
+ expected: |
602
+ #
603
+ ---
604
+ name: flowmap1
605
+ desc: flow style map
606
+ #
607
+ input: |
608
+ - { A1: 10, A2: 20 }
609
+ - {B1: 15, 'B2': 25, "B3": 35}
610
+ #
611
+ expected: |
612
+ [{"A1"=>10, "A2"=>20}, {"B1"=>15, "B2"=>25, "B3"=>35}]
613
+ #
614
+ ---
615
+ name: flowmap2
616
+ desc: flow style map nested
617
+ #
618
+ input: |
619
+ A: { x: {y: {z: 10}}}
620
+ B: { a: 1, b:{c: 2, d: 3, e:{f: 4}}, g: 5}
621
+ #
622
+ expected: |
623
+ {"A"=>{"x"=>{"y"=>{"z"=>10}}},
624
+ "B"=>{"a"=>1, "b"=>{"c"=>2, "d"=>3, "e"=>{"f"=>4}}, "g"=>5}}
625
+ #
626
+ ---
627
+ name: flowmap3
628
+ desc: flow style map with some lines
629
+ #
630
+ input: |
631
+ A: { x:
632
+ {y:
633
+ {z: 10}
634
+ }
635
+ }
636
+ B: {
637
+ a: 1,
638
+ b: {
639
+ c: 2,
640
+ d: 3,
641
+ e: {
642
+ f: 4
643
+ }
644
+ },
645
+ g: 5
646
+ }
647
+ #
648
+ expected: |
649
+ {"A"=>{"x"=>{"y"=>{"z"=>10}}},
650
+ "B"=>{"a"=>1, "b"=>{"c"=>2, "d"=>3, "e"=>{"f"=>4}}, "g"=>5}}
651
+ #
652
+ ---
653
+ name: flowmap4
654
+ desc: invalid flow style map (mapping item required (or last comma is extra).)
655
+ mesg: mapping item required (or last comma is extra).
656
+ error: Kwalify::ParseError
657
+ #
658
+ input: |
659
+ - {A: 10, B: 20, }
660
+ #
661
+ expected: |
662
+ #
663
+ ---
664
+ name: flowmap5
665
+ desc: invalid flow style map (flow style mapping requires '}').
666
+ mesg: flow style mapping requires '}'
667
+ error: Kwalify::ParseError
668
+ #
669
+ input: |
670
+ - {A: { x: 10, y: 20 }
671
+ - {A: { x: 11, y: 21 }}
672
+ #
673
+ expected: |
674
+ #
675
+ ---
676
+ name: flowmap6
677
+ desc: invalid flow style map (flow style mapping requires ']').
678
+ mesg: flow style mapping is closed but got '}'.
679
+ error: Kwalify::ParseError
680
+ #
681
+ input: |
682
+ { x: 10 }}
683
+ #
684
+ expected: |
685
+ #
686
+ ---
687
+ name: parse61
688
+ desc: combination of flow style seq and map
689
+ #
690
+ input: |
691
+ [
692
+ {name: ' foo ',
693
+ e-mail: foo@mail.com},
694
+ {name: ba z,
695
+ e-mail: ba__z@mail.com }
696
+ ]
697
+ #
698
+ expected: |
699
+ [{"name"=>" foo ", "e-mail"=>"foo@mail.com"},
700
+ {"name"=>"ba z", "e-mail"=>"ba__z@mail.com"}]
701
+ #
702
+ ---
703
+ name: block_text1
704
+ desc: parse_block_text
705
+ #
706
+ input: |
707
+ - text1: |
708
+ foo
709
+ bar
710
+ baz
711
+ - text2: |
712
+ aaa
713
+ bbb
714
+ ccc
715
+ - |
716
+ foo
717
+ bar
718
+ baz
719
+ - |
720
+ aaa
721
+ bbb
722
+ ccc
723
+ #
724
+ expected: |
725
+ [{"text1"=>"foo\nbar\nbaz\n"},
726
+ {"text2"=>" aaa\nbbb\n ccc\n"},
727
+ "foo\nbar\nbaz\n",
728
+ " aaa\nbbb\n ccc\n"]
729
+ #
730
+ ---
731
+ name: block_text2
732
+ desc: block text with '|+' or '|-'
733
+ #
734
+ input: |
735
+ - text1: |
736
+ A
737
+
738
+ B
739
+ C
740
+
741
+
742
+ - text2: |+
743
+ A
744
+
745
+ B
746
+ C
747
+
748
+
749
+ - text3: |-
750
+ A
751
+
752
+ B
753
+ C
754
+
755
+
756
+ #
757
+ expected: |
758
+ [{"text1"=>"A\n\nB\nC\n"},
759
+ {"text2"=>"A\n\nB\nC\n\n\n"},
760
+ {"text3"=>"A\n\nB\nC"}]
761
+ #
762
+ ---
763
+ name: block_text3
764
+ desc: block text with '| foo'
765
+ #
766
+ input: |
767
+ - text1: | foo
768
+ A
769
+
770
+ B
771
+ C
772
+
773
+ - | foo
774
+ A
775
+ B
776
+ C
777
+ #
778
+ expected: |
779
+ [{"text1"=>"foo A\n\nB\nC\n"}, "fooA\n B\n C\n"]
780
+ #
781
+ ---
782
+ name: block_text4
783
+ desc: block text with '#' (comment)
784
+ #
785
+ input: |
786
+ #
787
+ - text1: |
788
+ A
789
+ #
790
+ B
791
+ #
792
+ text2: |
793
+ #
794
+ #
795
+ #
796
+ - |
797
+ A
798
+ #
799
+ B
800
+ #
801
+ - |
802
+ #
803
+ #
804
+ #
805
+ - x
806
+
807
+ #
808
+ expected: |
809
+ [{"text1"=>"A\n#\nB\n", "text2"=>"#\n#\n"}, "A\n#\nB\n", "#\n#\n", "x"]
810
+ #
811
+ ---
812
+ name: block_text6
813
+ desc: parse_block_text (>)
814
+ #
815
+ input: |
816
+ - text1: >
817
+ foo
818
+ bar
819
+ baz
820
+ - text2: >
821
+ aaa
822
+ bbb
823
+ ccc
824
+ - >
825
+ foo
826
+ bar
827
+ baz
828
+ - >
829
+ aaa
830
+ bbb
831
+ ccc
832
+ #
833
+ expected: |
834
+ [{"text1"=>"foo bar baz\n"},
835
+ {"text2"=>" aaa bbb ccc\n"},
836
+ "foo bar baz\n",
837
+ " aaa bbb ccc\n"]
838
+ #
839
+ ---
840
+ name: block_text7
841
+ desc: block text with '>+' or '>-'
842
+ #
843
+ input: |
844
+ - text1: >
845
+ A
846
+
847
+ B
848
+ C
849
+
850
+
851
+ - text2: >+
852
+ A
853
+
854
+ B
855
+ C
856
+
857
+
858
+ - text3: >-
859
+ A
860
+
861
+ B
862
+ C
863
+
864
+
865
+ #
866
+ expected: |
867
+ [{"text1"=>"A\nB C\n"}, {"text2"=>"A\nB C\n\n"}, {"text3"=>"A\nB C"}]
868
+ #
869
+ ---
870
+ name: block_text8
871
+ desc: block text with '> foo'
872
+ #
873
+ input: |
874
+ - text1: > foo
875
+ A
876
+
877
+ B
878
+ C
879
+
880
+ - > foo
881
+ A
882
+ B
883
+ C
884
+ #
885
+ expected: |
886
+ [{"text1"=>"foo A\nB C\n"}, "fooA B C\n"]
887
+ #
888
+ ---
889
+ name: block_text9
890
+ desc: block text with '#' (comment)
891
+ #
892
+ input: |
893
+ #
894
+ - text1: >
895
+ AA
896
+ ##
897
+ BB
898
+ #
899
+ text2: >
900
+ #
901
+ #
902
+ #
903
+ - >
904
+ AA
905
+ ##
906
+ BB
907
+ #
908
+ - >
909
+ #
910
+ #
911
+ #
912
+ - x
913
+
914
+ #
915
+ expected: |
916
+ [{"text1"=>"AA ## BB\n", "text2"=>"# #\n"}, "AA ## BB\n", "# #\n", "x"]
917
+ #
918
+ ---
919
+ name: anchor1
920
+ desc: parse_anchor, parse_alias
921
+ #
922
+ input: |
923
+ - &a1 foo
924
+ - &a2
925
+ bar
926
+ - *a1
927
+ - *a2
928
+ #
929
+ expected: |
930
+ ["foo", "bar", "foo", "bar"]
931
+ #
932
+ ---
933
+ name: anchor2
934
+ desc: parse_anchor, parse_alias
935
+ #
936
+ input: |
937
+ - A: &a1
938
+ x: 10
939
+ y: 20
940
+ - B: bar
941
+ - C: *a1
942
+ #
943
+ expected: |
944
+ [{"A"=>{"x"=>10, "y"=>20}}, {"B"=>"bar"}, {"C"=>{"x"=>10, "y"=>20}}]
945
+ #
946
+ ---
947
+ name: anchor3
948
+ desc: anchor on child node
949
+ #
950
+ input: |
951
+ - A: &a1
952
+ x: 10
953
+ y: 20
954
+ z: *a1
955
+ #
956
+ expected: |
957
+ [{"A"=>{"x"=>10, "y"=>20, "z"=>{...}}}]
958
+ #
959
+ ---
960
+ name: anchor4
961
+ desc: backward anchor
962
+ #
963
+ input: |
964
+ - *a1
965
+ - *a1
966
+ - foo
967
+ - &a1 bar
968
+ #
969
+ expected: |
970
+ ["bar", "bar", "foo", "bar"]
971
+ #
972
+ ---
973
+ name: anchor5
974
+ desc: anchor not found
975
+ error: Kwalify::ParseError
976
+ mesg: anchor 'a2' not found (Kwalify::ParseError)
977
+ #
978
+ input: |
979
+ - &a1 foo
980
+ - bar
981
+ - *a2
982
+ #
983
+ expected: |
984
+ #
985
+ ---
986
+ name: anchor6
987
+ desc: anchor on child node
988
+ #
989
+ input: |
990
+ type: seq
991
+ sequence:
992
+ - &employee
993
+ type: map
994
+ mapping:
995
+ name:
996
+ type: str
997
+ post:
998
+ type: str
999
+ enum:
1000
+ - exective
1001
+ - manager
1002
+ - clerk
1003
+ supervisor: *employee
1004
+ #
1005
+ expected: |
1006
+ {"sequence"=>
1007
+ [{"type"=>"map",
1008
+ "mapping"=>
1009
+ {"name"=>{"type"=>"str"},
1010
+ "post"=>{"type"=>"str", "enum"=>["exective", "manager", "clerk"]},
1011
+ "supervisor"=>{...}}}],
1012
+ "type"=>"seq"}
1013
+ #
1014
+ ---
1015
+ name: tag1
1016
+ desc: tag
1017
+ #
1018
+ input: |
1019
+ - !str 123
1020
+ - foo: !text 123
1021
+ #
1022
+ expected: |
1023
+ [123, {"foo"=>123}]
1024
+ #
1025
+ ---
1026
+ name: docend1
1027
+ desc: ... (document end)
1028
+ #
1029
+ input: |
1030
+ - aaa
1031
+ - bbb
1032
+ ...
1033
+ - ccc
1034
+ #
1035
+ expected: |
1036
+ ["aaa", "bbb"]
1037
+ #
1038
+ ---
1039
+ name: docend2
1040
+ desc: ... (document end) in block text
1041
+ #
1042
+ input: |
1043
+ - |
1044
+ foo
1045
+ ...
1046
+ bar
1047
+ #
1048
+ expected: |
1049
+ ["foo\n...\nbar\n"]
1050
+ #
1051
+ ---
1052
+ name: docstart1
1053
+ desc: --- (document start)
1054
+ #
1055
+ input: |
1056
+ # comment
1057
+ ---
1058
+ - foo
1059
+ - bar
1060
+ #
1061
+ expected: |
1062
+ ["foo", "bar"]
1063
+ #
1064
+ ---
1065
+ name: docstart2
1066
+ desc: --- (document start) with tag
1067
+ #
1068
+ input: |
1069
+ # comment
1070
+ --- %YAML !seq
1071
+ - foo
1072
+ - bar
1073
+ #
1074
+ expected: |
1075
+ ["foo", "bar"]
1076
+ #
1077
+ ---
1078
+ name: docstart3
1079
+ desc: --- (document start) with tag
1080
+ #
1081
+ input: |
1082
+ - |
1083
+ foo
1084
+ ---
1085
+ bar
1086
+ ---
1087
+ baz
1088
+ #
1089
+ expected: |
1090
+ ["foo\n---\nbar\n---\nbaz\n"]
1091
+ #
1092
+ ---
1093
+ name: default1
1094
+ desc: map default value
1095
+ #
1096
+ input: |
1097
+ A: 10
1098
+ B: 20
1099
+ =: 0
1100
+ #
1101
+ expected: |
1102
+ {"A"=>10, "B"=>20}
1103
+ #
1104
+ ---
1105
+ name: merge1
1106
+ desc: merge key '<<'
1107
+ #
1108
+ input: |
1109
+ - &a1
1110
+ A: 10
1111
+ B: 20
1112
+ - C: 30
1113
+ <<: *a1
1114
+ A: ~
1115
+ #
1116
+ expected: |
1117
+ [{"A"=>10, "B"=>20}, {"A"=>nil, "B"=>20, "C"=>30}]
1118
+ ---
1119
+ name: example1
1120
+ desc: complex combination of seq and map
1121
+ #
1122
+ input: |
1123
+ columns:
1124
+ - name: id
1125
+ type: integer
1126
+ primary-key: yes
1127
+ sequence: yes
1128
+
1129
+ - name: name
1130
+ type: string
1131
+ not-null: yes
1132
+ width: 63
1133
+
1134
+ - name: desc
1135
+ type: string
1136
+
1137
+ - name: email
1138
+ type: string
1139
+ width: 63
1140
+
1141
+ - name: birth
1142
+ type: date
1143
+
1144
+ - name: age
1145
+ type: integer
1146
+
1147
+ - name: last_update
1148
+ type: timestamp
1149
+
1150
+ - name: gender
1151
+ type: string
1152
+ values:
1153
+ - M
1154
+ - F
1155
+
1156
+ tables:
1157
+ - name: groups
1158
+ class: Group
1159
+ desc: Group master table
1160
+ columns:
1161
+ - name: id
1162
+ - name: name
1163
+ - name: desc
1164
+
1165
+ - name: users
1166
+ class: User
1167
+ desc: User master table
1168
+ columns:
1169
+ - name: id
1170
+ - name: name
1171
+ - name: desc
1172
+ - name: email
1173
+ - name: group_id
1174
+ type: ref
1175
+ ref: groups.id
1176
+ - name: account
1177
+ type: string
1178
+ maxlength: 31
1179
+ not-null: yes
1180
+ - name: password
1181
+ not-null: yes
1182
+ #
1183
+ expected: |
1184
+ {"columns"=>
1185
+ [{"name"=>"id", "sequence"=>true, "type"=>"integer", "primary-key"=>true},
1186
+ {"name"=>"name", "not-null"=>true, "type"=>"string", "width"=>63},
1187
+ {"name"=>"desc", "type"=>"string"},
1188
+ {"name"=>"email", "type"=>"string", "width"=>63},
1189
+ {"name"=>"birth", "type"=>"date"},
1190
+ {"name"=>"age", "type"=>"integer"},
1191
+ {"name"=>"last_update", "type"=>"timestamp"},
1192
+ {"name"=>"gender", "type"=>"string", "values"=>["M", "F"]}],
1193
+ "tables"=>
1194
+ [{"columns"=>[{"name"=>"id"}, {"name"=>"name"}, {"name"=>"desc"}],
1195
+ "name"=>"groups",
1196
+ "class"=>"Group",
1197
+ "desc"=>"Group master table"},
1198
+ {"columns"=>
1199
+ [{"name"=>"id"},
1200
+ {"name"=>"name"},
1201
+ {"name"=>"desc"},
1202
+ {"name"=>"email"},
1203
+ {"name"=>"group_id", "type"=>"ref", "ref"=>"groups.id"},
1204
+ {"name"=>"account", "not-null"=>true, "type"=>"string", "maxlength"=>31},
1205
+ {"name"=>"password", "not-null"=>true}],
1206
+ "name"=>"users",
1207
+ "class"=>"User",
1208
+ "desc"=>"User master table"}]}
1209
+ #
1210
+ ---
1211
+ name: example2
1212
+ desc: invoice
1213
+ #
1214
+ input: |
1215
+ invoice: 34843
1216
+ date : 2001-01-23
1217
+ bill-to: &id001
1218
+ given : Chris
1219
+ family : Dumars
1220
+ address:
1221
+ lines: |
1222
+ 458 Walkman Dr.
1223
+ Suite #292
1224
+ city : Royal Oak
1225
+ state : MI
1226
+ postal : 48046
1227
+ ship-to: *id001
1228
+ product:
1229
+ - sku : BL394D
1230
+ quantity : 4
1231
+ description : Basketball
1232
+ price : 450.00
1233
+ - sku : BL4438H
1234
+ quantity : 1
1235
+ description : Super Hoop
1236
+ price : 2392.00
1237
+ tax : 251.42
1238
+ total: 4443.52
1239
+ comments: >
1240
+ Late afternoon is best.
1241
+ Backup contact is Nancy
1242
+ Billsmer @ 338-4338.
1243
+ #
1244
+ expected: |
1245
+ {"tax"=>251.42,
1246
+ "bill-to"=>
1247
+ {"given"=>"Chris",
1248
+ "family"=>"Dumars",
1249
+ "address"=>
1250
+ {"postal"=>48046,
1251
+ "city"=>"Royal Oak",
1252
+ "lines"=>"458 Walkman Dr.\nSuite #292\n",
1253
+ "state"=>"MI"}},
1254
+ "comments"=>
1255
+ "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n",
1256
+ "invoice"=>34843,
1257
+ "date"=>#<Date: 4903865/2,0,2299161>,
1258
+ "total"=>4443.52,
1259
+ "product"=>
1260
+ [{"price"=>450.0,
1261
+ "quantity"=>4,
1262
+ "description"=>"Basketball",
1263
+ "sku"=>"BL394D"},
1264
+ {"price"=>2392.0,
1265
+ "quantity"=>1,
1266
+ "description"=>"Super Hoop",
1267
+ "sku"=>"BL4438H"}],
1268
+ "ship-to"=>
1269
+ {"given"=>"Chris",
1270
+ "family"=>"Dumars",
1271
+ "address"=>
1272
+ {"postal"=>48046,
1273
+ "city"=>"Royal Oak",
1274
+ "lines"=>"458 Walkman Dr.\nSuite #292\n",
1275
+ "state"=>"MI"}}}
1276
+ #