@@ -18,8 +18,12 @@ module NodeUtils
18
18
19
19
module_function def stringify_adjust_scalar ( node , indent = 0 )
20
20
node2 = Psych ::Nodes ::Scalar . new ( node . value , nil , nil , node . plain , node . quoted , node . style )
21
- if node . tag && !node . quoted
22
- node2 . quoted = true
21
+ if node . tag
22
+ if node . style == Psych ::Nodes ::Scalar ::PLAIN
23
+ node2 . plain = true
24
+ else
25
+ node2 . quoted = true
26
+ end
23
27
end
24
28
25
29
s = stringify_node ( node2 ) . sub ( /\n \z / , "" )
@@ -55,13 +59,18 @@ module NodeUtils
55
59
end
56
60
end
57
61
end
58
- private_constant :NodeUtils
62
+ # private_constant :NodeUtils
59
63
60
64
class Emitter
61
65
include NodeUtils
62
66
63
67
INDENT = " "
64
68
69
+ DEFAULT_TAGMAP = {
70
+ '!' => '!' ,
71
+ '!!' => 'tag:yaml.org,2002:' ,
72
+ } . freeze
73
+
65
74
attr_reader :out
66
75
67
76
def initialize
@@ -70,6 +79,7 @@ def initialize
70
79
@indent = 0
71
80
@flow = false
72
81
@comment_lookahead = [ ]
82
+ @tagmap = DEFAULT_TAGMAP
73
83
end
74
84
75
85
def print ( text )
@@ -106,6 +116,15 @@ def emit(node)
106
116
print "&#{ node . anchor } "
107
117
space!
108
118
end
119
+ if node . tag
120
+ handle , suffix = decompose_tag ( node . tag )
121
+ if suffix
122
+ print "#{ handle } #{ suffix } "
123
+ else
124
+ print "!<#{ node . tag } >"
125
+ end
126
+ space!
127
+ end
109
128
case node
110
129
when Psych ::Nodes ::Scalar , Psych ::Nodes ::Alias
111
130
if node . is_a? ( Psych ::Nodes ::Alias )
@@ -131,10 +150,6 @@ def emit(node)
131
150
end
132
151
print "}"
133
152
else
134
- if node . children . empty?
135
- print "{}"
136
- return
137
- end
138
153
newline!
139
154
node . children . each_slice ( 2 ) do |( key , value ) |
140
155
emit ( key )
@@ -168,10 +183,6 @@ def emit(node)
168
183
end
169
184
print "]"
170
185
else
171
- if node . children . empty?
172
- print "[]"
173
- return
174
- end
175
186
newline!
176
187
node . children . each do |subnode |
177
188
emit_lookahead_comments ( subnode ) unless @flow
@@ -185,15 +196,26 @@ def emit(node)
185
196
end
186
197
end
187
198
when Psych ::Nodes ::Document
188
- emit ( node . root )
189
- when Psych ::Nodes ::Stream
190
- if node . children . size == 1 && node . children [ 0 ] . implicit
191
- emit ( node . children [ 0 ] )
192
- return
199
+ node . tag_directives . each do |( handle , prefix ) |
200
+ newline!
201
+ print "%TAG #{ handle } #{ prefix } "
202
+ newline!
193
203
end
194
- node . children . each do |subnode |
204
+ unless node . implicit
205
+ newline!
195
206
print "---"
196
207
newline!
208
+ end
209
+ set_tagmap ( node ) do
210
+ emit ( node . root )
211
+ end
212
+ unless node . implicit_end
213
+ newline!
214
+ print "..."
215
+ newline!
216
+ end
217
+ when Psych ::Nodes ::Stream
218
+ node . children . each do |subnode |
197
219
emit ( subnode )
198
220
end
199
221
else
@@ -239,6 +261,33 @@ def flow?(node)
239
261
@flow || node . style == Psych ::Nodes ::Sequence ::FLOW || node . children . empty?
240
262
end
241
263
end
264
+
265
+ # @param tag [String]
266
+ def decompose_tag ( tag )
267
+ @tagmap . each do |handle , prefix |
268
+ if tag . start_with? ( prefix )
269
+ suffix = tag . delete_prefix ( prefix )
270
+ if /\A (?:%[0-9a-fA-F]{2}|[-0-9a-z#;\/ ?:@&=+$_.~*'()])*\z / . match? ( suffix )
271
+ return [ handle , suffix ]
272
+ end
273
+ end
274
+ end
275
+ [ nil , nil ]
276
+ end
277
+
278
+ # @param node [Psych::Nodes::Document]
279
+ def set_tagmap ( node , &block )
280
+ new_tagmap = DEFAULT_TAGMAP . dup
281
+ node . tag_directives . each do |( handle , prefix ) |
282
+ new_tagmap [ handle ] = prefix
283
+ end
284
+ old_tagmap , @tagmap = @tagmap , new_tagmap
285
+ begin
286
+ block . ( )
287
+ ensure
288
+ @tagmap = old_tagmap
289
+ end
290
+ end
242
291
end
243
292
244
293
private_constant :Emitter
0 commit comments