Skip to content

Commit fdf6ea8

Browse files
committed
Emit tags
1 parent e606b18 commit fdf6ea8

File tree

7 files changed

+120
-17
lines changed

7 files changed

+120
-17
lines changed

lib/psych/comments/emitter.rb

+66-17
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ module NodeUtils
1818

1919
module_function def stringify_adjust_scalar(node, indent = 0)
2020
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
2327
end
2428

2529
s = stringify_node(node2).sub(/\n\z/, "")
@@ -55,13 +59,18 @@ module NodeUtils
5559
end
5660
end
5761
end
58-
private_constant :NodeUtils
62+
# private_constant :NodeUtils
5963

6064
class Emitter
6165
include NodeUtils
6266

6367
INDENT = " "
6468

69+
DEFAULT_TAGMAP = {
70+
'!' => '!',
71+
'!!' => 'tag:yaml.org,2002:',
72+
}.freeze
73+
6574
attr_reader :out
6675

6776
def initialize
@@ -70,6 +79,7 @@ def initialize
7079
@indent = 0
7180
@flow = false
7281
@comment_lookahead = []
82+
@tagmap = DEFAULT_TAGMAP
7383
end
7484

7585
def print(text)
@@ -106,6 +116,15 @@ def emit(node)
106116
print "&#{node.anchor}"
107117
space!
108118
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
109128
case node
110129
when Psych::Nodes::Scalar, Psych::Nodes::Alias
111130
if node.is_a?(Psych::Nodes::Alias)
@@ -131,10 +150,6 @@ def emit(node)
131150
end
132151
print "}"
133152
else
134-
if node.children.empty?
135-
print "{}"
136-
return
137-
end
138153
newline!
139154
node.children.each_slice(2) do |(key, value)|
140155
emit(key)
@@ -168,10 +183,6 @@ def emit(node)
168183
end
169184
print "]"
170185
else
171-
if node.children.empty?
172-
print "[]"
173-
return
174-
end
175186
newline!
176187
node.children.each do |subnode|
177188
emit_lookahead_comments(subnode) unless @flow
@@ -185,15 +196,26 @@ def emit(node)
185196
end
186197
end
187198
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!
193203
end
194-
node.children.each do |subnode|
204+
unless node.implicit
205+
newline!
195206
print "---"
196207
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|
197219
emit(subnode)
198220
end
199221
else
@@ -239,6 +261,33 @@ def flow?(node)
239261
@flow || node.style == Psych::Nodes::Sequence::FLOW || node.children.empty?
240262
end
241263
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
242291
end
243292

244293
private_constant :Emitter

spec/emitter/example6-in.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- !ruby/object {}
2+
- !ruby/symbol "foo"
3+
- !!str foo
4+
- !!str &x foo
5+
- &y !!str foo

spec/emitter/example6-out-wc.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- !ruby/object {}
2+
- !ruby/symbol "foo"
3+
- !!str foo
4+
- &x !!str foo
5+
- &y !!str foo

spec/emitter/example6-out.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- !ruby/object {}
2+
- !ruby/symbol "foo"
3+
- !!str foo
4+
- &x !!str foo
5+
- &y !!str foo

spec/emitter/example7-in.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
%TAG !e! tag:example.com,2000:app/
2+
---
3+
- !e!str foo
4+
- !<tag:example.com,2000:app/str> foo
5+
- !<tag:example.com,2000:app2/str> foo
6+
- !<tag:yaml.org,2002:str> foo
7+
...
8+
%TAG ! tag:example.com,2000:bang/
9+
%TAG !! tag:example.com,2000:bangbang/
10+
---
11+
- !<tag:example.com,2000:app/str> foo
12+
- !<tag:example.com,2000:app2/str> foo
13+
- !<tag:yaml.org,2002:str> foo

spec/emitter/example7-out-wc.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
%TAG !e! tag:example.com,2000:app/
2+
---
3+
- !e!str foo
4+
- !e!str foo
5+
- !<tag:example.com,2000:app2/str> foo
6+
- !!str foo
7+
...
8+
%TAG ! tag:example.com,2000:bang/
9+
%TAG !! tag:example.com,2000:bangbang/
10+
---
11+
- !<tag:example.com,2000:app/str> foo
12+
- !<tag:example.com,2000:app2/str> foo
13+
- !<tag:yaml.org,2002:str> foo

spec/emitter/example7-out.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
%TAG !e! tag:example.com,2000:app/
2+
---
3+
- !e!str foo
4+
- !e!str foo
5+
- !<tag:example.com,2000:app2/str> foo
6+
- !!str foo
7+
...
8+
%TAG ! tag:example.com,2000:bang/
9+
%TAG !! tag:example.com,2000:bangbang/
10+
---
11+
- !<tag:example.com,2000:app/str> foo
12+
- !<tag:example.com,2000:app2/str> foo
13+
- !<tag:yaml.org,2002:str> foo

0 commit comments

Comments
 (0)