psych-shopifork 2.0.0

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