psych 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/.autotest +18 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +3 -0
  4. data/Manifest.txt +87 -0
  5. data/README.rdoc +50 -0
  6. data/Rakefile +66 -0
  7. data/ext/psych/emitter.c +517 -0
  8. data/ext/psych/emitter.h +8 -0
  9. data/ext/psych/extconf.rb +22 -0
  10. data/ext/psych/parser.c +384 -0
  11. data/ext/psych/parser.h +6 -0
  12. data/ext/psych/psych.c +34 -0
  13. data/ext/psych/psych.h +20 -0
  14. data/ext/psych/to_ruby.c +41 -0
  15. data/ext/psych/to_ruby.h +8 -0
  16. data/ext/psych/yaml_tree.c +24 -0
  17. data/ext/psych/yaml_tree.h +8 -0
  18. data/lib/psych.rb +263 -0
  19. data/lib/psych/coder.rb +94 -0
  20. data/lib/psych/core_ext.rb +39 -0
  21. data/lib/psych/deprecated.rb +82 -0
  22. data/lib/psych/handler.rb +221 -0
  23. data/lib/psych/json.rb +6 -0
  24. data/lib/psych/json/ruby_events.rb +19 -0
  25. data/lib/psych/json/stream.rb +15 -0
  26. data/lib/psych/json/tree_builder.rb +12 -0
  27. data/lib/psych/json/yaml_events.rb +29 -0
  28. data/lib/psych/nodes.rb +77 -0
  29. data/lib/psych/nodes/alias.rb +18 -0
  30. data/lib/psych/nodes/document.rb +60 -0
  31. data/lib/psych/nodes/mapping.rb +56 -0
  32. data/lib/psych/nodes/node.rb +52 -0
  33. data/lib/psych/nodes/scalar.rb +67 -0
  34. data/lib/psych/nodes/sequence.rb +81 -0
  35. data/lib/psych/nodes/stream.rb +37 -0
  36. data/lib/psych/omap.rb +4 -0
  37. data/lib/psych/parser.rb +47 -0
  38. data/lib/psych/scalar_scanner.rb +105 -0
  39. data/lib/psych/set.rb +4 -0
  40. data/lib/psych/stream.rb +36 -0
  41. data/lib/psych/streaming.rb +22 -0
  42. data/lib/psych/tree_builder.rb +94 -0
  43. data/lib/psych/visitors.rb +6 -0
  44. data/lib/psych/visitors/depth_first.rb +26 -0
  45. data/lib/psych/visitors/emitter.rb +44 -0
  46. data/lib/psych/visitors/json_tree.rb +21 -0
  47. data/lib/psych/visitors/to_ruby.rb +267 -0
  48. data/lib/psych/visitors/visitor.rb +19 -0
  49. data/lib/psych/visitors/yaml_tree.rb +373 -0
  50. data/test/psych/helper.rb +63 -0
  51. data/test/psych/json/test_stream.rb +109 -0
  52. data/test/psych/nodes/test_enumerable.rb +43 -0
  53. data/test/psych/test_alias_and_anchor.rb +26 -0
  54. data/test/psych/test_array.rb +19 -0
  55. data/test/psych/test_boolean.rb +36 -0
  56. data/test/psych/test_class.rb +17 -0
  57. data/test/psych/test_coder.rb +184 -0
  58. data/test/psych/test_date_time.rb +17 -0
  59. data/test/psych/test_deprecated.rb +210 -0
  60. data/test/psych/test_document.rb +46 -0
  61. data/test/psych/test_emitter.rb +94 -0
  62. data/test/psych/test_encoding.rb +179 -0
  63. data/test/psych/test_engine_manager.rb +57 -0
  64. data/test/psych/test_exception.rb +39 -0
  65. data/test/psych/test_hash.rb +30 -0
  66. data/test/psych/test_json_tree.rb +65 -0
  67. data/test/psych/test_merge_keys.rb +72 -0
  68. data/test/psych/test_nil.rb +18 -0
  69. data/test/psych/test_null.rb +19 -0
  70. data/test/psych/test_object.rb +27 -0
  71. data/test/psych/test_omap.rb +68 -0
  72. data/test/psych/test_parser.rb +297 -0
  73. data/test/psych/test_psych.rb +168 -0
  74. data/test/psych/test_scalar.rb +11 -0
  75. data/test/psych/test_scalar_scanner.rb +69 -0
  76. data/test/psych/test_serialize_subclasses.rb +38 -0
  77. data/test/psych/test_set.rb +49 -0
  78. data/test/psych/test_stream.rb +49 -0
  79. data/test/psych/test_string.rb +49 -0
  80. data/test/psych/test_struct.rb +51 -0
  81. data/test/psych/test_symbol.rb +17 -0
  82. data/test/psych/test_to_yaml_properties.rb +63 -0
  83. data/test/psych/test_tree_builder.rb +79 -0
  84. data/test/psych/test_yaml.rb +1256 -0
  85. data/test/psych/visitors/test_depth_first.rb +49 -0
  86. data/test/psych/visitors/test_emitter.rb +144 -0
  87. data/test/psych/visitors/test_to_ruby.rb +325 -0
  88. data/test/psych/visitors/test_yaml_tree.rb +155 -0
  89. metadata +232 -0
@@ -0,0 +1,17 @@
1
+ require 'psych/helper'
2
+
3
+ module Psych
4
+ class TestSymbol < TestCase
5
+ def test_cycle
6
+ assert_cycle :a
7
+ end
8
+
9
+ def test_stringy
10
+ assert_cycle :"1"
11
+ end
12
+
13
+ def test_load_quoted
14
+ assert_equal :"1", Psych.load("--- :'1'\n")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,63 @@
1
+ require 'psych/helper'
2
+
3
+ module Psych
4
+ class TestToYamlProperties < MiniTest::Unit::TestCase
5
+ class Foo
6
+ attr_accessor :a, :b, :c
7
+ def initialize
8
+ @a = 1
9
+ @b = 2
10
+ @c = 3
11
+ end
12
+
13
+ def to_yaml_properties
14
+ [:@a, :@b]
15
+ end
16
+ end
17
+
18
+ def test_object_dump_yaml_properties
19
+ foo = Psych.load(Psych.dump(Foo.new))
20
+ assert_equal 1, foo.a
21
+ assert_equal 2, foo.b
22
+ assert_nil foo.c
23
+ end
24
+
25
+ class Bar < Struct.new(:foo, :bar)
26
+ attr_reader :baz
27
+ def initialize *args
28
+ super
29
+ @baz = 'hello'
30
+ end
31
+
32
+ def to_yaml_properties
33
+ []
34
+ end
35
+ end
36
+
37
+ def test_struct_dump_yaml_properties
38
+ bar = Psych.load(Psych.dump(Bar.new('a', 'b')))
39
+ assert_equal 'a', bar.foo
40
+ assert_equal 'b', bar.bar
41
+ assert_nil bar.baz
42
+ end
43
+
44
+ def test_string_dump
45
+ string = "okonomiyaki"
46
+ class << string
47
+ def to_yaml_properties
48
+ [:@tastes]
49
+ end
50
+ end
51
+
52
+ string.instance_variable_set(:@tastes, 'delicious')
53
+ v = Psych.load Psych.dump string
54
+ assert_equal 'delicious', v.instance_variable_get(:@tastes)
55
+ end
56
+
57
+ def test_string_load_syck
58
+ str = Psych.load("--- !str \nstr: okonomiyaki\n:@tastes: delicious\n")
59
+ assert_equal 'okonomiyaki', str
60
+ assert_equal 'delicious', str.instance_variable_get(:@tastes)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,79 @@
1
+ require 'psych/helper'
2
+
3
+ module Psych
4
+ class TestTreeBuilder < TestCase
5
+ def setup
6
+ super
7
+ @parser = Psych::Parser.new TreeBuilder.new
8
+ @parser.parse(<<-eoyml)
9
+ %YAML 1.1
10
+ ---
11
+ - foo
12
+ - {
13
+ bar : &A !!str baz,
14
+ boo : *A
15
+ }
16
+ - *A
17
+ eoyml
18
+ @tree = @parser.handler.root
19
+ end
20
+
21
+ def test_stream
22
+ assert_instance_of Nodes::Stream, @tree
23
+ end
24
+
25
+ def test_documents
26
+ assert_equal 1, @tree.children.length
27
+ assert_instance_of Nodes::Document, @tree.children.first
28
+ doc = @tree.children.first
29
+
30
+ assert_equal [1,1], doc.version
31
+ assert_equal [], doc.tag_directives
32
+ assert_equal false, doc.implicit
33
+ end
34
+
35
+ def test_sequence
36
+ doc = @tree.children.first
37
+ assert_equal 1, doc.children.length
38
+
39
+ seq = doc.children.first
40
+ assert_instance_of Nodes::Sequence, seq
41
+ assert_nil seq.anchor
42
+ assert_nil seq.tag
43
+ assert_equal true, seq.implicit
44
+ assert_equal Nodes::Sequence::BLOCK, seq.style
45
+ end
46
+
47
+ def test_scalar
48
+ doc = @tree.children.first
49
+ seq = doc.children.first
50
+
51
+ assert_equal 3, seq.children.length
52
+ scalar = seq.children.first
53
+ assert_instance_of Nodes::Scalar, scalar
54
+ assert_equal 'foo', scalar.value
55
+ assert_nil scalar.anchor
56
+ assert_nil scalar.tag
57
+ assert_equal true, scalar.plain
58
+ assert_equal false, scalar.quoted
59
+ assert_equal Nodes::Scalar::PLAIN, scalar.style
60
+ end
61
+
62
+ def test_mapping
63
+ doc = @tree.children.first
64
+ seq = doc.children.first
65
+ map = seq.children[1]
66
+
67
+ assert_instance_of Nodes::Mapping, map
68
+ end
69
+
70
+ def test_alias
71
+ doc = @tree.children.first
72
+ seq = doc.children.first
73
+ assert_equal 3, seq.children.length
74
+ al = seq.children[2]
75
+ assert_instance_of Nodes::Alias, al
76
+ assert_equal 'A', al.anchor
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,1256 @@
1
+ # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*-
2
+ # vim:sw=4:ts=4
3
+ # $Id$
4
+ #
5
+ require 'psych/helper'
6
+
7
+ # [ruby-core:01946]
8
+ module Psych_Tests
9
+ StructTest = Struct::new( :c )
10
+ end
11
+
12
+ class Psych_Unit_Tests < Psych::TestCase
13
+ def teardown
14
+ Psych.domain_types.clear
15
+ end
16
+
17
+ # [ruby-core:34969]
18
+ def test_regexp_with_n
19
+ assert_cycle(Regexp.new('',0,'n'))
20
+ end
21
+ #
22
+ # Tests modified from 00basic.t in Psych.pm
23
+ #
24
+ def test_basic_map
25
+ # Simple map
26
+ assert_parse_only(
27
+ { 'one' => 'foo', 'three' => 'baz', 'two' => 'bar' }, <<EOY
28
+ one: foo
29
+ two: bar
30
+ three: baz
31
+ EOY
32
+ )
33
+ end
34
+
35
+ def test_basic_strings
36
+ # Common string types
37
+ assert_cycle("x")
38
+ assert_cycle(":x")
39
+ assert_cycle(":")
40
+ assert_parse_only(
41
+ { 1 => 'simple string', 2 => 42, 3 => '1 Single Quoted String',
42
+ 4 => 'Psych\'s Double "Quoted" String', 5 => "A block\n with several\n lines.\n",
43
+ 6 => "A \"chomped\" block", 7 => "A folded\n string\n", 8 => ": started string" },
44
+ <<EOY
45
+ 1: simple string
46
+ 2: 42
47
+ 3: '1 Single Quoted String'
48
+ 4: "Psych's Double \\\"Quoted\\\" String"
49
+ 5: |
50
+ A block
51
+ with several
52
+ lines.
53
+ 6: |-
54
+ A "chomped" block
55
+ 7: >
56
+ A
57
+ folded
58
+ string
59
+ 8: ": started string"
60
+ EOY
61
+ )
62
+ end
63
+
64
+ #
65
+ # Test the specification examples
66
+ # - Many examples have been changes because of whitespace problems that
67
+ # caused the two to be inequivalent, or keys to be sorted wrong
68
+ #
69
+
70
+ def test_spec_simple_implicit_sequence
71
+ # Simple implicit sequence
72
+ assert_to_yaml(
73
+ [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ], <<EOY
74
+ - Mark McGwire
75
+ - Sammy Sosa
76
+ - Ken Griffey
77
+ EOY
78
+ )
79
+ end
80
+
81
+ def test_spec_simple_implicit_map
82
+ # Simple implicit map
83
+ assert_to_yaml(
84
+ { 'hr' => 65, 'avg' => 0.278, 'rbi' => 147 }, <<EOY
85
+ avg: 0.278
86
+ hr: 65
87
+ rbi: 147
88
+ EOY
89
+ )
90
+ end
91
+
92
+ def test_spec_simple_map_with_nested_sequences
93
+ # Simple mapping with nested sequences
94
+ assert_to_yaml(
95
+ { 'american' =>
96
+ [ 'Boston Red Sox', 'Detroit Tigers', 'New York Yankees' ],
97
+ 'national' =>
98
+ [ 'New York Mets', 'Chicago Cubs', 'Atlanta Braves' ] }, <<EOY
99
+ american:
100
+ - Boston Red Sox
101
+ - Detroit Tigers
102
+ - New York Yankees
103
+ national:
104
+ - New York Mets
105
+ - Chicago Cubs
106
+ - Atlanta Braves
107
+ EOY
108
+ )
109
+ end
110
+
111
+ def test_spec_simple_sequence_with_nested_map
112
+ # Simple sequence with nested map
113
+ assert_to_yaml(
114
+ [
115
+ {'name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278},
116
+ {'name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288}
117
+ ], <<EOY
118
+ -
119
+ avg: 0.278
120
+ hr: 65
121
+ name: Mark McGwire
122
+ -
123
+ avg: 0.288
124
+ hr: 63
125
+ name: Sammy Sosa
126
+ EOY
127
+ )
128
+ end
129
+
130
+ def test_spec_sequence_of_sequences
131
+ # Simple sequence with inline sequences
132
+ assert_parse_only(
133
+ [
134
+ [ 'name', 'hr', 'avg' ],
135
+ [ 'Mark McGwire', 65, 0.278 ],
136
+ [ 'Sammy Sosa', 63, 0.288 ]
137
+ ], <<EOY
138
+ - [ name , hr , avg ]
139
+ - [ Mark McGwire , 65 , 0.278 ]
140
+ - [ Sammy Sosa , 63 , 0.288 ]
141
+ EOY
142
+ )
143
+ end
144
+
145
+ def test_spec_mapping_of_mappings
146
+ # Simple map with inline maps
147
+ assert_parse_only(
148
+ { 'Mark McGwire' =>
149
+ { 'hr' => 65, 'avg' => 0.278 },
150
+ 'Sammy Sosa' =>
151
+ { 'hr' => 63, 'avg' => 0.288 }
152
+ }, <<EOY
153
+ Mark McGwire: {hr: 65, avg: 0.278}
154
+ Sammy Sosa: {hr: 63,
155
+ avg: 0.288}
156
+ EOY
157
+ )
158
+ end
159
+
160
+ def test_ambiguous_comments
161
+ # [ruby-talk:88012]
162
+ assert_to_yaml( "Call the method #dave", <<EOY )
163
+ --- "Call the method #dave"
164
+ EOY
165
+ end
166
+
167
+ def test_spec_nested_comments
168
+ # Map and sequences with comments
169
+ assert_parse_only(
170
+ { 'hr' => [ 'Mark McGwire', 'Sammy Sosa' ],
171
+ 'rbi' => [ 'Sammy Sosa', 'Ken Griffey' ] }, <<EOY
172
+ hr: # 1998 hr ranking
173
+ - Mark McGwire
174
+ - Sammy Sosa
175
+ rbi:
176
+ # 1998 rbi ranking
177
+ - Sammy Sosa
178
+ - Ken Griffey
179
+ EOY
180
+ )
181
+ end
182
+
183
+ def test_spec_anchors_and_aliases
184
+ # Anchors and aliases
185
+ assert_parse_only(
186
+ { 'hr' =>
187
+ [ 'Mark McGwire', 'Sammy Sosa' ],
188
+ 'rbi' =>
189
+ [ 'Sammy Sosa', 'Ken Griffey' ] }, <<EOY
190
+ hr:
191
+ - Mark McGwire
192
+ # Name "Sammy Sosa" scalar SS
193
+ - &SS Sammy Sosa
194
+ rbi:
195
+ # So it can be referenced later.
196
+ - *SS
197
+ - Ken Griffey
198
+ EOY
199
+ )
200
+
201
+ assert_to_yaml(
202
+ [{"arrival"=>"EDI", "departure"=>"LAX", "fareref"=>"DOGMA", "currency"=>"GBP"}, {"arrival"=>"MEL", "departure"=>"SYD", "fareref"=>"MADF", "currency"=>"AUD"}, {"arrival"=>"MCO", "departure"=>"JFK", "fareref"=>"DFSF", "currency"=>"USD"}], <<EOY
203
+ -
204
+ &F fareref: DOGMA
205
+ &C currency: GBP
206
+ &D departure: LAX
207
+ &A arrival: EDI
208
+ - { *F: MADF, *C: AUD, *D: SYD, *A: MEL }
209
+ - { *F: DFSF, *C: USD, *D: JFK, *A: MCO }
210
+ EOY
211
+ )
212
+
213
+ assert_to_yaml(
214
+ {"ALIASES"=>["fareref", "currency", "departure", "arrival"], "FARES"=>[{"arrival"=>"EDI", "departure"=>"LAX", "fareref"=>"DOGMA", "currency"=>"GBP"}, {"arrival"=>"MEL", "departure"=>"SYD", "fareref"=>"MADF", "currency"=>"AUD"}, {"arrival"=>"MCO", "departure"=>"JFK", "fareref"=>"DFSF", "currency"=>"USD"}]}, <<EOY
215
+ ---
216
+ ALIASES: [&f fareref, &c currency, &d departure, &a arrival]
217
+ FARES:
218
+ - *f: DOGMA
219
+ *c: GBP
220
+ *d: LAX
221
+ *a: EDI
222
+
223
+ - *f: MADF
224
+ *c: AUD
225
+ *d: SYD
226
+ *a: MEL
227
+
228
+ - *f: DFSF
229
+ *c: USD
230
+ *d: JFK
231
+ *a: MCO
232
+
233
+ EOY
234
+ )
235
+
236
+ end
237
+
238
+ def test_spec_mapping_between_sequences
239
+ # Complex key #1
240
+ dj = Date.new( 2001, 7, 23 )
241
+ assert_parse_only(
242
+ { [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ],
243
+ [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ] }, <<EOY
244
+ ? # PLAY SCHEDULE
245
+ - Detroit Tigers
246
+ - Chicago Cubs
247
+ :
248
+ - 2001-07-23
249
+
250
+ ? [ New York Yankees,
251
+ Atlanta Braves ]
252
+ : [ 2001-07-02, 2001-08-12,
253
+ 2001-08-14 ]
254
+ EOY
255
+ )
256
+
257
+ # Complex key #2
258
+ assert_parse_only(
259
+ { [ 'New York Yankees', 'Atlanta Braves' ] =>
260
+ [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ),
261
+ Date.new( 2001, 8, 14 ) ],
262
+ [ 'Detroit Tigers', 'Chicago Cubs' ] =>
263
+ [ Date.new( 2001, 7, 23 ) ]
264
+ }, <<EOY
265
+ ?
266
+ - New York Yankees
267
+ - Atlanta Braves
268
+ :
269
+ - 2001-07-02
270
+ - 2001-08-12
271
+ - 2001-08-14
272
+ ?
273
+ - Detroit Tigers
274
+ - Chicago Cubs
275
+ :
276
+ - 2001-07-23
277
+ EOY
278
+ )
279
+ end
280
+
281
+ def test_spec_sequence_key_shortcut
282
+ # Shortcut sequence map
283
+ assert_parse_only(
284
+ { 'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
285
+ 'bill-to' => 'Chris Dumars', 'product' =>
286
+ [ { 'item' => 'Super Hoop', 'quantity' => 1 },
287
+ { 'item' => 'Basketball', 'quantity' => 4 },
288
+ { 'item' => 'Big Shoes', 'quantity' => 1 } ] }, <<EOY
289
+ invoice: 34843
290
+ date : 2001-01-23
291
+ bill-to: Chris Dumars
292
+ product:
293
+ - item : Super Hoop
294
+ quantity: 1
295
+ - item : Basketball
296
+ quantity: 4
297
+ - item : Big Shoes
298
+ quantity: 1
299
+ EOY
300
+ )
301
+ end
302
+
303
+ def test_spec_sequence_in_sequence_shortcut
304
+ # Seq-in-seq
305
+ assert_parse_only( [ [ [ 'one', 'two', 'three' ] ] ], <<EOY )
306
+ - - - one
307
+ - two
308
+ - three
309
+ EOY
310
+ end
311
+
312
+ def test_spec_sequence_shortcuts
313
+ # Sequence shortcuts combined
314
+ assert_parse_only(
315
+ [
316
+ [
317
+ [ [ 'one' ] ],
318
+ [ 'two', 'three' ],
319
+ { 'four' => nil },
320
+ [ { 'five' => [ 'six' ] } ],
321
+ [ 'seven' ]
322
+ ],
323
+ [ 'eight', 'nine' ]
324
+ ], <<EOY )
325
+ - - - - one
326
+ - - two
327
+ - three
328
+ - four:
329
+ - - five:
330
+ - six
331
+ - - seven
332
+ - - eight
333
+ - nine
334
+ EOY
335
+ end
336
+
337
+ def test_spec_single_literal
338
+ # Literal scalar block
339
+ assert_parse_only( [ "\\/|\\/|\n/ | |_\n" ], <<EOY )
340
+ - |
341
+ \\/|\\/|
342
+ / | |_
343
+ EOY
344
+ end
345
+
346
+ def test_spec_single_folded
347
+ # Folded scalar block
348
+ assert_parse_only(
349
+ [ "Mark McGwire's year was crippled by a knee injury.\n" ], <<EOY
350
+ - >
351
+ Mark McGwire\'s
352
+ year was crippled
353
+ by a knee injury.
354
+ EOY
355
+ )
356
+ end
357
+
358
+ def test_spec_preserve_indent
359
+ # Preserve indented spaces
360
+ assert_parse_only(
361
+ "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n", <<EOY
362
+ --- >
363
+ Sammy Sosa completed another
364
+ fine season with great stats.
365
+
366
+ 63 Home Runs
367
+ 0.288 Batting Average
368
+
369
+ What a year!
370
+ EOY
371
+ )
372
+ end
373
+
374
+ def test_spec_indentation_determines_scope
375
+ assert_parse_only(
376
+ { 'name' => 'Mark McGwire', 'accomplishment' => "Mark set a major league home run record in 1998.\n",
377
+ 'stats' => "65 Home Runs\n0.278 Batting Average\n" }, <<EOY
378
+ name: Mark McGwire
379
+ accomplishment: >
380
+ Mark set a major league
381
+ home run record in 1998.
382
+ stats: |
383
+ 65 Home Runs
384
+ 0.278 Batting Average
385
+ EOY
386
+ )
387
+ end
388
+
389
+ def test_spec_multiline_scalars
390
+ # Multiline flow scalars
391
+ assert_parse_only(
392
+ { 'plain' => 'This unquoted scalar spans many lines.',
393
+ 'quoted' => "So does this quoted scalar.\n" }, <<EOY
394
+ plain: This unquoted
395
+ scalar spans
396
+ many lines.
397
+ quoted: "\\
398
+ So does this quoted
399
+ scalar.\\n"
400
+ EOY
401
+ )
402
+ end
403
+
404
+ def test_spec_type_int
405
+ assert_parse_only(
406
+ { 'canonical' => 12345, 'decimal' => 12345, 'octal' => '014'.oct, 'hexadecimal' => '0xC'.hex }, <<EOY
407
+ canonical: 12345
408
+ decimal: +12,345
409
+ octal: 014
410
+ hexadecimal: 0xC
411
+ EOY
412
+ )
413
+ assert_parse_only(
414
+ { 'canonical' => 685230, 'decimal' => 685230, 'octal' => 02472256, 'hexadecimal' => 0x0A74AE, 'sexagesimal' => 685230 }, <<EOY)
415
+ canonical: 685230
416
+ decimal: +685,230
417
+ octal: 02472256
418
+ hexadecimal: 0x0A,74,AE
419
+ sexagesimal: 190:20:30
420
+ EOY
421
+ end
422
+
423
+ def test_spec_type_float
424
+ assert_parse_only(
425
+ { 'canonical' => 1230.15, 'exponential' => 1230.15, 'fixed' => 1230.15,
426
+ 'negative infinity' => -1.0/0.0 }, <<EOY)
427
+ canonical: 1.23015e+3
428
+ exponential: 12.3015e+02
429
+ fixed: 1,230.15
430
+ negative infinity: -.inf
431
+ EOY
432
+ nan = Psych::load( <<EOY )
433
+ not a number: .NaN
434
+ EOY
435
+ assert( nan['not a number'].nan? )
436
+ end
437
+
438
+ def test_spec_type_misc
439
+ assert_parse_only(
440
+ { nil => nil, true => true, false => false, 'string' => '12345' }, <<EOY
441
+ null: ~
442
+ true: yes
443
+ false: no
444
+ string: '12345'
445
+ EOY
446
+ )
447
+ end
448
+
449
+ def test_spec_complex_invoice
450
+ # Complex invoice type
451
+ id001 = { 'given' => 'Chris', 'family' => 'Dumars', 'address' =>
452
+ { 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak',
453
+ 'state' => 'MI', 'postal' => 48046 } }
454
+ assert_parse_only(
455
+ { 'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ),
456
+ 'bill-to' => id001, 'ship-to' => id001, 'product' =>
457
+ [ { 'sku' => 'BL394D', 'quantity' => 4,
458
+ 'description' => 'Basketball', 'price' => 450.00 },
459
+ { 'sku' => 'BL4438H', 'quantity' => 1,
460
+ 'description' => 'Super Hoop', 'price' => 2392.00 } ],
461
+ 'tax' => 251.42, 'total' => 4443.52,
462
+ 'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" }, <<EOY
463
+ invoice: 34843
464
+ date : 2001-01-23
465
+ bill-to: &id001
466
+ given : Chris
467
+ family : !str Dumars
468
+ address:
469
+ lines: |
470
+ 458 Walkman Dr.
471
+ Suite #292
472
+ city : Royal Oak
473
+ state : MI
474
+ postal : 48046
475
+ ship-to: *id001
476
+ product:
477
+ - !map
478
+ sku : BL394D
479
+ quantity : 4
480
+ description : Basketball
481
+ price : 450.00
482
+ - sku : BL4438H
483
+ quantity : 1
484
+ description : Super Hoop
485
+ price : 2392.00
486
+ tax : 251.42
487
+ total: 4443.52
488
+ comments: >
489
+ Late afternoon is best.
490
+ Backup contact is Nancy
491
+ Billsmer @ 338-4338.
492
+ EOY
493
+ )
494
+ end
495
+
496
+ def test_spec_log_file
497
+ doc_ct = 0
498
+ Psych::load_documents( <<EOY
499
+ ---
500
+ Time: 2001-11-23 15:01:42 -05:00
501
+ User: ed
502
+ Warning: >
503
+ This is an error message
504
+ for the log file
505
+ ---
506
+ Time: 2001-11-23 15:02:31 -05:00
507
+ User: ed
508
+ Warning: >
509
+ A slightly different error
510
+ message.
511
+ ---
512
+ Date: 2001-11-23 15:03:17 -05:00
513
+ User: ed
514
+ Fatal: >
515
+ Unknown variable "bar"
516
+ Stack:
517
+ - file: TopClass.py
518
+ line: 23
519
+ code: |
520
+ x = MoreObject("345\\n")
521
+ - file: MoreClass.py
522
+ line: 58
523
+ code: |-
524
+ foo = bar
525
+ EOY
526
+ ) { |doc|
527
+ case doc_ct
528
+ when 0
529
+ assert_equal( doc, { 'Time' => mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ),
530
+ 'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } )
531
+ when 1
532
+ assert_equal( doc, { 'Time' => mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ),
533
+ 'User' => 'ed', 'Warning' => "A slightly different error message.\n" } )
534
+ when 2
535
+ assert_equal( doc, { 'Date' => mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ),
536
+ 'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n",
537
+ 'Stack' => [
538
+ { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" },
539
+ { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } )
540
+ end
541
+ doc_ct += 1
542
+ }
543
+ assert_equal( doc_ct, 3 )
544
+ end
545
+
546
+ def test_spec_root_fold
547
+ y = Psych::load( <<EOY
548
+ ---
549
+ This Psych stream contains a single text value.
550
+ The next stream is a log file - a sequence of
551
+ log entries. Adding an entry to the log is a
552
+ simple matter of appending it at the end.
553
+ EOY
554
+ )
555
+ assert_equal( y, "This Psych stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end." )
556
+ end
557
+
558
+ def test_spec_root_mapping
559
+ y = Psych::load( <<EOY
560
+ # This stream is an example of a top-level mapping.
561
+ invoice : 34843
562
+ date : 2001-01-23
563
+ total : 4443.52
564
+ EOY
565
+ )
566
+ assert_equal( y, { 'invoice' => 34843, 'date' => Date.new( 2001, 1, 23 ), 'total' => 4443.52 } )
567
+ end
568
+
569
+ def test_spec_oneline_docs
570
+ doc_ct = 0
571
+ Psych::load_documents( <<EOY
572
+ # The following is a sequence of three documents.
573
+ # The first contains an empty mapping, the second
574
+ # an empty sequence, and the last an empty string.
575
+ --- {}
576
+ --- [ ]
577
+ --- ''
578
+ EOY
579
+ ) { |doc|
580
+ case doc_ct
581
+ when 0
582
+ assert_equal( doc, {} )
583
+ when 1
584
+ assert_equal( doc, [] )
585
+ when 2
586
+ assert_equal( doc, '' )
587
+ end
588
+ doc_ct += 1
589
+ }
590
+ assert_equal( doc_ct, 3 )
591
+ end
592
+
593
+ def test_spec_domain_prefix
594
+ customer_proc = proc { |type, val|
595
+ if Hash === val
596
+ scheme, domain, type = type.split( ':', 3 )
597
+ val['type'] = "domain #{type}"
598
+ val
599
+ else
600
+ raise ArgumentError, "Not a Hash in domain.tld,2002/invoice: " + val.inspect
601
+ end
602
+ }
603
+ Psych.add_domain_type( "domain.tld,2002", 'invoice', &customer_proc )
604
+ Psych.add_domain_type( "domain.tld,2002", 'customer', &customer_proc )
605
+ assert_parse_only( { "invoice"=> { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } }, <<EOY
606
+ # 'http://domain.tld,2002/invoice' is some type family.
607
+ invoice: !domain.tld,2002/invoice
608
+ # 'seq' is shorthand for 'http://yaml.org/seq'.
609
+ # This does not effect '^customer' below
610
+ # because it is does not specify a prefix.
611
+ customers: !seq
612
+ # '^customer' is shorthand for the full
613
+ # notation 'http://domain.tld,2002/customer'.
614
+ - !customer
615
+ given : Chris
616
+ family : Dumars
617
+ EOY
618
+ )
619
+ end
620
+
621
+ def test_spec_throwaway
622
+ assert_parse_only(
623
+ {"this"=>"contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n"}, <<EOY
624
+ ### These are four throwaway comment ###
625
+
626
+ ### lines (the second line is empty). ###
627
+ this: | # Comments may trail lines.
628
+ contains three lines of text.
629
+ The third one starts with a
630
+ # character. This isn't a comment.
631
+
632
+ # These are three throwaway comment
633
+ # lines (the first line is empty).
634
+ EOY
635
+ )
636
+ end
637
+
638
+ def test_spec_force_implicit
639
+ # Force implicit
640
+ assert_parse_only(
641
+ { 'integer' => 12, 'also int' => 12, 'string' => '12' }, <<EOY
642
+ integer: 12
643
+ also int: ! "12"
644
+ string: !str 12
645
+ EOY
646
+ )
647
+ end
648
+
649
+ ###
650
+ # Commenting out this test. This line:
651
+ #
652
+ # - !domain.tld,2002/type\\x30 value
653
+ #
654
+ # Is invalid according to the YAML spec:
655
+ #
656
+ # http://yaml.org/spec/1.1/#id896876
657
+ #
658
+ # def test_spec_url_escaping
659
+ # Psych.add_domain_type( "domain.tld,2002", "type0" ) { |type, val|
660
+ # "ONE: #{val}"
661
+ # }
662
+ # Psych.add_domain_type( "domain.tld,2002", "type%30" ) { |type, val|
663
+ # "TWO: #{val}"
664
+ # }
665
+ # assert_parse_only(
666
+ # { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value' ] }, <<EOY
667
+ #same:
668
+ # - !domain.tld,2002/type\\x30 value
669
+ # - !domain.tld,2002/type0 value
670
+ #different: # As far as the Psych parser is concerned
671
+ # - !domain.tld,2002/type%30 value
672
+ #EOY
673
+ # )
674
+ # end
675
+
676
+ def test_spec_override_anchor
677
+ # Override anchor
678
+ a001 = "The alias node below is a repeated use of this value.\n"
679
+ assert_parse_only(
680
+ { 'anchor' => 'This scalar has an anchor.', 'override' => a001, 'alias' => a001 }, <<EOY
681
+ anchor : &A001 This scalar has an anchor.
682
+ override : &A001 >
683
+ The alias node below is a
684
+ repeated use of this value.
685
+ alias : *A001
686
+ EOY
687
+ )
688
+ end
689
+
690
+ def test_spec_explicit_families
691
+ Psych.add_domain_type( "somewhere.com,2002", 'type' ) { |type, val|
692
+ "SOMEWHERE: #{val}"
693
+ }
694
+ assert_parse_only(
695
+ { 'not-date' => '2002-04-28', 'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;", 'hmm' => "SOMEWHERE: family above is short for\nhttp://somewhere.com/type\n" }, <<EOY
696
+ not-date: !str 2002-04-28
697
+ picture: !binary |
698
+ R0lGODlhDAAMAIQAAP//9/X
699
+ 17unp5WZmZgAAAOfn515eXv
700
+ Pz7Y6OjuDg4J+fn5OTk6enp
701
+ 56enmleECcgggoBADs=
702
+
703
+ hmm: !somewhere.com,2002/type |
704
+ family above is short for
705
+ http://somewhere.com/type
706
+ EOY
707
+ )
708
+ end
709
+
710
+ def test_spec_application_family
711
+ # Testing the clarkevans.com graphs
712
+ Psych.add_domain_type( "clarkevans.com,2002", 'graph/shape' ) { |type, val|
713
+ if Array === val
714
+ val << "Shape Container"
715
+ val
716
+ else
717
+ raise ArgumentError, "Invalid graph of type #{val.class}: " + val.inspect
718
+ end
719
+ }
720
+ one_shape_proc = Proc.new { |type, val|
721
+ if Hash === val
722
+ type = type.split( /:/ )
723
+ val['TYPE'] = "Shape: #{type[2]}"
724
+ val
725
+ else
726
+ raise ArgumentError, "Invalid graph of type #{val.class}: " + val.inspect
727
+ end
728
+ }
729
+ Psych.add_domain_type( "clarkevans.com,2002", 'graph/circle', &one_shape_proc )
730
+ Psych.add_domain_type( "clarkevans.com,2002", 'graph/line', &one_shape_proc )
731
+ Psych.add_domain_type( "clarkevans.com,2002", 'graph/text', &one_shape_proc )
732
+ # MODIFIED to remove invalid Psych
733
+ assert_parse_only(
734
+ [[{"radius"=>7, "center"=>{"x"=>73, "y"=>129}, "TYPE"=>"Shape: graph/circle"}, {"finish"=>{"x"=>89, "y"=>102}, "TYPE"=>"Shape: graph/line", "start"=>{"x"=>73, "y"=>129}}, {"TYPE"=>"Shape: graph/text", "value"=>"Pretty vector drawing.", "start"=>{"x"=>73, "y"=>129}, "color"=>16772795}, "Shape Container"]], <<EOY
735
+ - !clarkevans.com,2002/graph/shape
736
+ - !/graph/circle
737
+ center: &ORIGIN {x: 73, y: 129}
738
+ radius: 7
739
+ - !/graph/line # !clarkevans.com,2002/graph/line
740
+ start: *ORIGIN
741
+ finish: { x: 89, y: 102 }
742
+ - !/graph/text
743
+ start: *ORIGIN
744
+ color: 0xFFEEBB
745
+ value: Pretty vector drawing.
746
+ EOY
747
+ )
748
+ end
749
+
750
+ def test_spec_float_explicit
751
+ assert_parse_only(
752
+ [ 10.0, 10.0, 10.0, 10.0 ], <<EOY
753
+ # All entries in the sequence
754
+ # have the same type and value.
755
+ - 10.0
756
+ - !float 10
757
+ - !yaml.org,2002/float '10'
758
+ - !yaml.org,2002/float "\\
759
+ 1\\
760
+ 0"
761
+ EOY
762
+ )
763
+ end
764
+
765
+ def test_spec_builtin_seq
766
+ # Assortment of sequences
767
+ assert_parse_only(
768
+ { 'empty' => [], 'in-line' => [ 'one', 'two', 'three', 'four', 'five' ],
769
+ 'nested' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ],
770
+ "A multi-line sequence entry\n", 'Sixth item in top sequence' ] }, <<EOY
771
+ empty: []
772
+ in-line: [ one, two, three # May span lines,
773
+ , four, # indentation is
774
+ five ] # mostly ignored.
775
+ nested:
776
+ - First item in top sequence
777
+ -
778
+ - Subordinate sequence entry
779
+ - >
780
+ A multi-line
781
+ sequence entry
782
+ - Sixth item in top sequence
783
+ EOY
784
+ )
785
+ end
786
+
787
+ def test_spec_builtin_map
788
+ # Assortment of mappings
789
+ assert_parse_only(
790
+ { 'empty' => {}, 'in-line' => { 'one' => 1, 'two' => 2 },
791
+ 'spanning' => { 'one' => 1, 'two' => 2 },
792
+ 'nested' => { 'first' => 'First entry', 'second' =>
793
+ { 'key' => 'Subordinate mapping' }, 'third' =>
794
+ [ 'Subordinate sequence', {}, 'Previous mapping is empty.',
795
+ { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' },
796
+ 'The previous entry is equal to the following one.',
797
+ { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ],
798
+ 12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.',
799
+ "\a" => 'This key had to be escaped.',
800
+ "This is a multi-line folded key\n" => "Whose value is also multi-line.\n",
801
+ [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } }, <<EOY
802
+
803
+ empty: {}
804
+ in-line: { one: 1, two: 2 }
805
+ spanning: { one: 1,
806
+ two: 2 }
807
+ nested:
808
+ first : First entry
809
+ second:
810
+ key: Subordinate mapping
811
+ third:
812
+ - Subordinate sequence
813
+ - { }
814
+ - Previous mapping is empty.
815
+ - A key: value pair in a sequence.
816
+ A second: key:value pair.
817
+ - The previous entry is equal to the following one.
818
+ -
819
+ A key: value pair in a sequence.
820
+ A second: key:value pair.
821
+ !float 12 : This key is a float.
822
+ ? >
823
+ ?
824
+ : This key had to be protected.
825
+ "\\a" : This key had to be escaped.
826
+ ? >
827
+ This is a
828
+ multi-line
829
+ folded key
830
+ : >
831
+ Whose value is
832
+ also multi-line.
833
+ ?
834
+ - This key
835
+ - is a sequence
836
+ :
837
+ - With a sequence value.
838
+ # The following parses correctly,
839
+ # but Ruby 1.6.* fails the comparison!
840
+ # ?
841
+ # This: key
842
+ # is a: mapping
843
+ # :
844
+ # with a: mapping value.
845
+ EOY
846
+ )
847
+ end
848
+
849
+ def test_spec_builtin_literal_blocks
850
+ # Assortment of literal scalar blocks
851
+ assert_parse_only(
852
+ {"both are equal to"=>" This has no newline.", "is equal to"=>"The \\ ' \" characters may be\nfreely used. Leading white\n space is significant.\n\nLine breaks are significant.\nThus this value contains one\nempty line and ends with a\nsingle line break, but does\nnot start with one.\n", "also written as"=>" This has no newline.", "indented and chomped"=>" This has no newline.", "empty"=>"", "literal"=>"The \\ ' \" characters may be\nfreely used. Leading white\n space is significant.\n\nLine breaks are significant.\nThus this value contains one\nempty line and ends with a\nsingle line break, but does\nnot start with one.\n"}, <<EOY
853
+ empty: |
854
+
855
+ literal: |
856
+ The \\\ ' " characters may be
857
+ freely used. Leading white
858
+ space is significant.
859
+
860
+ Line breaks are significant.
861
+ Thus this value contains one
862
+ empty line and ends with a
863
+ single line break, but does
864
+ not start with one.
865
+
866
+ is equal to: "The \\\\ ' \\" characters may \\
867
+ be\\nfreely used. Leading white\\n space \\
868
+ is significant.\\n\\nLine breaks are \\
869
+ significant.\\nThus this value contains \\
870
+ one\\nempty line and ends with a\\nsingle \\
871
+ line break, but does\\nnot start with one.\\n"
872
+
873
+ # Comments may follow a nested
874
+ # scalar value. They must be
875
+ # less indented.
876
+
877
+ # Modifiers may be combined in any order.
878
+ indented and chomped: |2-
879
+ This has no newline.
880
+
881
+ also written as: |-2
882
+ This has no newline.
883
+
884
+ both are equal to: " This has no newline."
885
+ EOY
886
+ )
887
+
888
+ str1 = "This has one newline.\n"
889
+ str2 = "This has no newline."
890
+ str3 = "This has two newlines.\n\n"
891
+ assert_parse_only(
892
+ { 'clipped' => str1, 'same as "clipped" above' => str1,
893
+ 'stripped' => str2, 'same as "stripped" above' => str2,
894
+ 'kept' => str3, 'same as "kept" above' => str3 }, <<EOY
895
+ clipped: |
896
+ This has one newline.
897
+
898
+ same as "clipped" above: "This has one newline.\\n"
899
+
900
+ stripped: |-
901
+ This has no newline.
902
+
903
+ same as "stripped" above: "This has no newline."
904
+
905
+ kept: |+
906
+ This has two newlines.
907
+
908
+ same as "kept" above: "This has two newlines.\\n\\n"
909
+
910
+ EOY
911
+ )
912
+ end
913
+
914
+ def test_spec_span_single_quote
915
+ assert_parse_only( {"third"=>"a single quote ' must be escaped.", "second"=>"! : \\ etc. can be used freely.", "is same as"=>"this contains six spaces\nand one line break", "empty"=>"", "span"=>"this contains six spaces\nand one line break"}, <<EOY
916
+ empty: ''
917
+ second: '! : \\ etc. can be used freely.'
918
+ third: 'a single quote '' must be escaped.'
919
+ span: 'this contains
920
+ six spaces
921
+
922
+ and one
923
+ line break'
924
+ is same as: "this contains six spaces\\nand one line break"
925
+ EOY
926
+ )
927
+ end
928
+
929
+ def test_spec_span_double_quote
930
+ assert_parse_only( {"is equal to"=>"this contains four spaces", "third"=>"a \" or a \\ must be escaped.", "second"=>"! : etc. can be used freely.", "empty"=>"", "fourth"=>"this value ends with an LF.\n", "span"=>"this contains four spaces"}, <<EOY
931
+ empty: ""
932
+ second: "! : etc. can be used freely."
933
+ third: "a \\\" or a \\\\ must be escaped."
934
+ fourth: "this value ends with an LF.\\n"
935
+ span: "this contains
936
+ four \\
937
+ spaces"
938
+ is equal to: "this contains four spaces"
939
+ EOY
940
+ )
941
+ end
942
+
943
+ def test_spec_builtin_time
944
+ # Time
945
+ assert_parse_only(
946
+ { "space separated" => mktime( 2001, 12, 14, 21, 59, 43, ".10", "-05:00" ),
947
+ "canonical" => mktime( 2001, 12, 15, 2, 59, 43, ".10" ),
948
+ "date (noon UTC)" => Date.new( 2002, 12, 14),
949
+ "valid iso8601" => mktime( 2001, 12, 14, 21, 59, 43, ".10", "-05:00" ) }, <<EOY
950
+ canonical: 2001-12-15T02:59:43.1Z
951
+ valid iso8601: 2001-12-14t21:59:43.10-05:00
952
+ space separated: 2001-12-14 21:59:43.10 -05:00
953
+ date (noon UTC): 2002-12-14
954
+ EOY
955
+ )
956
+ end
957
+
958
+ def test_spec_builtin_binary
959
+ arrow_gif = "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236iiiccc\243\243\243\204\204\204\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371!\376\016Made with GIMP\000,\000\000\000\000\f\000\f\000\000\005, \216\2010\236\343@\024\350i\020\304\321\212\010\034\317\200M$z\357\3770\205p\270\2601f\r\e\316\001\303\001\036\020' \202\n\001\000;"
960
+ assert_parse_only(
961
+ { 'canonical' => arrow_gif, 'base64' => arrow_gif,
962
+ 'description' => "The binary value above is a tiny arrow encoded as a gif image.\n" }, <<EOY
963
+ canonical: !binary "\\
964
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf\\
965
+ n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW\\
966
+ NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++\\
967
+ f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg\\
968
+ d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN\\
969
+ AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww\\
970
+ EeECcgggoBADs="
971
+ base64: !binary |
972
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOf
973
+ n515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaW
974
+ NjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++
975
+ f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUg
976
+ d2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuN
977
+ AFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84Bww
978
+ EeECcgggoBADs=
979
+ description: >
980
+ The binary value above is a tiny arrow
981
+ encoded as a gif image.
982
+ EOY
983
+ )
984
+ end
985
+ def test_ruby_regexp
986
+ # Test Ruby regular expressions
987
+ assert_to_yaml(
988
+ { 'simple' => /a.b/, 'complex' => %r'\A"((?:[^"]|\")+)"',
989
+ 'case-insensitive' => /George McFly/i }, <<EOY
990
+ case-insensitive: !ruby/regexp "/George McFly/i"
991
+ complex: !ruby/regexp "/\\\\A\\"((?:[^\\"]|\\\\\\")+)\\"/"
992
+ simple: !ruby/regexp "/a.b/"
993
+ EOY
994
+ )
995
+ end
996
+
997
+ #
998
+ # Test of Ranges
999
+ #
1000
+ def test_ranges
1001
+
1002
+ # Simple numeric
1003
+ assert_to_yaml( 1..3, <<EOY )
1004
+ --- !ruby/range 1..3
1005
+ EOY
1006
+
1007
+ # Simple alphabetic
1008
+ assert_to_yaml( 'a'..'z', <<EOY )
1009
+ --- !ruby/range a..z
1010
+ EOY
1011
+
1012
+ # Float
1013
+ assert_to_yaml( 10.5...30.3, <<EOY )
1014
+ --- !ruby/range 10.5...30.3
1015
+ EOY
1016
+
1017
+ end
1018
+
1019
+ def test_ruby_struct
1020
+ # Ruby structures
1021
+ book_struct = Struct::new( "MyBookStruct", :author, :title, :year, :isbn )
1022
+ assert_to_yaml(
1023
+ [ book_struct.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" ),
1024
+ book_struct.new( [ 'Dave Thomas', 'Andy Hunt' ], "The Pickaxe", 2002,
1025
+ book_struct.new( "This should be the ISBN", "but I have another struct here", 2002, "None" )
1026
+ ) ], <<EOY
1027
+ - !ruby/struct:MyBookStruct
1028
+ author: Yukihiro Matsumoto
1029
+ title: Ruby in a Nutshell
1030
+ year: 2002
1031
+ isbn: 0-596-00214-9
1032
+ - !ruby/struct:MyBookStruct
1033
+ author:
1034
+ - Dave Thomas
1035
+ - Andy Hunt
1036
+ title: The Pickaxe
1037
+ year: 2002
1038
+ isbn: !ruby/struct:MyBookStruct
1039
+ author: This should be the ISBN
1040
+ title: but I have another struct here
1041
+ year: 2002
1042
+ isbn: None
1043
+ EOY
1044
+ )
1045
+
1046
+ assert_to_yaml( Psych_Tests::StructTest.new( 123 ), <<EOY )
1047
+ --- !ruby/struct:Psych_Tests::StructTest
1048
+ c: 123
1049
+ EOY
1050
+
1051
+ end
1052
+
1053
+ def test_ruby_rational
1054
+ assert_to_yaml( Rational(1, 2), <<EOY )
1055
+ --- !ruby/object:Rational
1056
+ numerator: 1
1057
+ denominator: 2
1058
+ EOY
1059
+
1060
+ # Read Psych dumped by the ruby 1.8.3.
1061
+ assert_to_yaml( Rational(1, 2), "!ruby/object:Rational 1/2\n" )
1062
+ assert_raises( ArgumentError ) { Psych.load("!ruby/object:Rational INVALID/RATIONAL\n") }
1063
+ end
1064
+
1065
+ def test_ruby_complex
1066
+ assert_to_yaml( Complex(3, 4), <<EOY )
1067
+ --- !ruby/object:Complex
1068
+ image: 4
1069
+ real: 3
1070
+ EOY
1071
+
1072
+ # Read Psych dumped by the ruby 1.8.3.
1073
+ assert_to_yaml( Complex(3, 4), "!ruby/object:Complex 3+4i\n" )
1074
+ assert_raises( ArgumentError ) { Psych.load("!ruby/object:Complex INVALID+COMPLEXi\n") }
1075
+ end
1076
+
1077
+ def test_emitting_indicators
1078
+ assert_to_yaml( "Hi, from Object 1. You passed: please, pretty please", <<EOY
1079
+ --- "Hi, from Object 1. You passed: please, pretty please"
1080
+ EOY
1081
+ )
1082
+ end
1083
+
1084
+ ##
1085
+ ## Test the Psych::Stream class -- INACTIVE at the moment
1086
+ ##
1087
+ #def test_document
1088
+ # y = Psych::Stream.new( :Indent => 2, :UseVersion => 0 )
1089
+ # y.add(
1090
+ # { 'hi' => 'hello', 'map' =>
1091
+ # { 'good' => 'two' },
1092
+ # 'time' => Time.now,
1093
+ # 'try' => /^po(.*)$/,
1094
+ # 'bye' => 'goodbye'
1095
+ # }
1096
+ # )
1097
+ # y.add( { 'po' => 'nil', 'oper' => 90 } )
1098
+ # y.add( { 'hi' => 'wow!', 'bye' => 'wow!' } )
1099
+ # y.add( { [ 'Red Socks', 'Boston' ] => [ 'One', 'Two', 'Three' ] } )
1100
+ # y.add( [ true, false, false ] )
1101
+ #end
1102
+
1103
+ #
1104
+ # Test YPath choices parsing
1105
+ #
1106
+ #def test_ypath_parsing
1107
+ # assert_path_segments( "/*/((one|three)/name|place)|//place",
1108
+ # [ ["*", "one", "name"],
1109
+ # ["*", "three", "name"],
1110
+ # ["*", "place"],
1111
+ # ["/", "place"] ]
1112
+ # )
1113
+ #end
1114
+
1115
+ #
1116
+ # Tests from Tanaka Akira on [ruby-core]
1117
+ #
1118
+ def test_akira
1119
+
1120
+ # Commas in plain scalars [ruby-core:1066]
1121
+ assert_to_yaml(
1122
+ {"A"=>"A,","B"=>"B"}, <<EOY
1123
+ A: "A,"
1124
+ B: B
1125
+ EOY
1126
+ )
1127
+
1128
+ # Double-quoted keys [ruby-core:1069]
1129
+ assert_to_yaml(
1130
+ {"1"=>2, "2"=>3}, <<EOY
1131
+ '1': 2
1132
+ "2": 3
1133
+ EOY
1134
+ )
1135
+
1136
+ # Anchored mapping [ruby-core:1071]
1137
+ assert_to_yaml(
1138
+ [{"a"=>"b"}] * 2, <<EOY
1139
+ - &id001
1140
+ a: b
1141
+ - *id001
1142
+ EOY
1143
+ )
1144
+
1145
+ # Stress test [ruby-core:1071]
1146
+ # a = []; 1000.times { a << {"a"=>"b", "c"=>"d"} }
1147
+ # Psych::load( a.to_yaml )
1148
+
1149
+ end
1150
+
1151
+ #
1152
+ # Test Time.now cycle
1153
+ #
1154
+ def test_time_now_cycle
1155
+ #
1156
+ # From Minero Aoki [ruby-core:2305]
1157
+ #
1158
+ #require 'yaml'
1159
+ t = Time.now
1160
+ t = Time.at(t.tv_sec, t.tv_usec)
1161
+ 5.times do
1162
+ assert_cycle(t)
1163
+ end
1164
+ end
1165
+
1166
+ #
1167
+ # Test Range cycle
1168
+ #
1169
+ def test_range_cycle
1170
+ #
1171
+ # From Minero Aoki [ruby-core:02306]
1172
+ #
1173
+ assert_cycle("a".."z")
1174
+
1175
+ #
1176
+ # From Nobu Nakada [ruby-core:02311]
1177
+ #
1178
+ assert_cycle(0..1)
1179
+ assert_cycle(1.0e20 .. 2.0e20)
1180
+ assert_cycle("0".."1")
1181
+ assert_cycle(".."..."...")
1182
+ assert_cycle(".rb"..".pl")
1183
+ assert_cycle(".rb"...".pl")
1184
+ assert_cycle('"'...".")
1185
+ assert_cycle("'"...".")
1186
+ end
1187
+
1188
+ #
1189
+ # Circular references
1190
+ #
1191
+ def test_circular_references
1192
+ a = []; a[0] = a; a[1] = a
1193
+ inspect_str = "[[...], [...]]"
1194
+ assert_equal( inspect_str, Psych::load(Psych.dump(a)).inspect )
1195
+ end
1196
+
1197
+ #
1198
+ # Test Symbol cycle
1199
+ #
1200
+ def test_symbol_cycle
1201
+ #
1202
+ # From Aaron Schrab [ruby-Bugs:2535]
1203
+ #
1204
+ assert_cycle(:"^foo")
1205
+ end
1206
+
1207
+ #
1208
+ # Test Numeric cycle
1209
+ #
1210
+ class NumericTest < Numeric
1211
+ def initialize(value)
1212
+ @value = value
1213
+ end
1214
+ def ==(other)
1215
+ @value == other.instance_eval{ @value }
1216
+ end
1217
+ end
1218
+ def test_numeric_cycle
1219
+ assert_cycle(1) # Fixnum
1220
+ assert_cycle(111111111111111111111111111111111) # Bignum
1221
+ assert_cycle(NumericTest.new(3)) # Subclass of Numeric
1222
+ end
1223
+
1224
+ #
1225
+ # Test empty map/seq in map cycle
1226
+ #
1227
+ def test_empty_map_key
1228
+ #
1229
+ # empty seq as key
1230
+ #
1231
+ assert_cycle({[]=>""})
1232
+
1233
+ #
1234
+ # empty map as key
1235
+ #
1236
+ assert_cycle({{}=>""})
1237
+ end
1238
+
1239
+ #
1240
+ # contributed by riley lynch [ruby-Bugs-8548]
1241
+ #
1242
+ def test_object_id_collision
1243
+ omap = Psych::Omap.new
1244
+ 1000.times { |i| omap["key_#{i}"] = { "value" => i } }
1245
+ raise "id collision in ordered map" if Psych.dump(omap) =~ /id\d+/
1246
+ end
1247
+
1248
+ def test_date_out_of_range
1249
+ Psych::load('1900-01-01T00:00:00+00:00')
1250
+ end
1251
+
1252
+ def test_normal_exit
1253
+ Psych.load("2000-01-01 00:00:00.#{"0"*1000} +00:00\n")
1254
+ # '[ruby-core:13735]'
1255
+ end
1256
+ end