RbYAML 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +19 -0
- data/README +31 -0
- data/lib/rbyaml.rb +378 -0
- data/lib/rbyaml/composer.rb +189 -0
- data/lib/rbyaml/constructor.rb +374 -0
- data/lib/rbyaml/detector.rb +44 -0
- data/lib/rbyaml/dumper.rb +40 -0
- data/lib/rbyaml/emitter.rb +1116 -0
- data/lib/rbyaml/error.rb +81 -0
- data/lib/rbyaml/events.rb +92 -0
- data/lib/rbyaml/loader.rb +49 -0
- data/lib/rbyaml/nodes.rb +69 -0
- data/lib/rbyaml/parser.rb +488 -0
- data/lib/rbyaml/reader.rb +127 -0
- data/lib/rbyaml/representer.rb +183 -0
- data/lib/rbyaml/scanner.rb +1258 -0
- data/lib/rbyaml/serializer.rb +120 -0
- data/lib/rbyaml/test.rb +56 -0
- data/lib/rbyaml/tokens.rb +163 -0
- data/lib/rbyaml/yaml.rb +143 -0
- data/test/test_rbyaml.rb +18 -0
- data/test/yaml/gems.yml +130951 -0
- data/test/yaml/gems2.yml +113 -0
- data/test/yaml/test1.yml +3 -0
- data/test/yaml/test10.yml +8 -0
- data/test/yaml/test12.yml +8 -0
- data/test/yaml/test13.yml +4 -0
- data/test/yaml/test14.yml +4 -0
- data/test/yaml/test15.yml +8 -0
- data/test/yaml/test16.yml +7 -0
- data/test/yaml/test18.yml +6 -0
- data/test/yaml/test19.yml +5 -0
- data/test/yaml/test2.yml +3 -0
- data/test/yaml/test20.yml +6 -0
- data/test/yaml/test21.yml +4 -0
- data/test/yaml/test22.yml +4 -0
- data/test/yaml/test23.yml +13 -0
- data/test/yaml/test24.yml +14 -0
- data/test/yaml/test25.yml +7 -0
- data/test/yaml/test26.yml +7 -0
- data/test/yaml/test27.yml +29 -0
- data/test/yaml/test28.yml +26 -0
- data/test/yaml/test29.yml +13 -0
- data/test/yaml/test3.yml +8 -0
- data/test/yaml/test30.yml +7 -0
- data/test/yaml/test31.yml +2 -0
- data/test/yaml/test32.yml +13 -0
- data/test/yaml/test33.yml +2 -0
- data/test/yaml/test34.yml +8 -0
- data/test/yaml/test35.yml +4 -0
- data/test/yaml/test36.yml +8 -0
- data/test/yaml/test37.yml +2 -0
- data/test/yaml/test38.yml +8 -0
- data/test/yaml/test39.yml +2 -0
- data/test/yaml/test4.yml +8 -0
- data/test/yaml/test40.yml +3 -0
- data/test/yaml/test41.yml +5 -0
- data/test/yaml/test42.yml +12 -0
- data/test/yaml/test43.yml +15 -0
- data/test/yaml/test44.yml +23 -0
- data/test/yaml/test5.yml +3 -0
- data/test/yaml/test6.yml +5 -0
- data/test/yaml/test7.yml +10 -0
- data/test/yaml/test8.yml +10 -0
- data/test/yaml/test9.yml +8 -0
- metadata +111 -0
@@ -0,0 +1,1116 @@
|
|
1
|
+
# Emitter expects events obeying the following grammar:
|
2
|
+
# stream ::= STREAM-START document* STREAM-END
|
3
|
+
# document ::= DOCUMENT-START node DOCUMENT-END
|
4
|
+
# node ::= SCALAR | sequence | mapping
|
5
|
+
# sequence ::= SEQUENCE-START node* SEQUENCE-END
|
6
|
+
# mapping ::= MAPPING-START (node node)* MAPPING-END
|
7
|
+
|
8
|
+
require 'rbyaml/error'
|
9
|
+
require 'rbyaml/events'
|
10
|
+
|
11
|
+
module RbYAML
|
12
|
+
class EmitterError < YAMLError
|
13
|
+
end
|
14
|
+
|
15
|
+
class ScalarAnalysis
|
16
|
+
attr_accessor :scalar,:empty,:multiline,:allow_flow_plain,:allow_block_plain,:allow_single_quoted,:allow_double_quoted,:allow_block
|
17
|
+
def initialize(scalar,empty,multiline,allow_flow_plain, allow_block_plain,allow_single_quoted, allow_double_quoted,allow_block)
|
18
|
+
@scalar = scalar
|
19
|
+
@empty = empty
|
20
|
+
@multiline = multiline
|
21
|
+
@allow_flow_plain = allow_flow_plain
|
22
|
+
@allow_block_plain = allow_block_plain
|
23
|
+
@allow_single_quoted = allow_single_quoted
|
24
|
+
@allow_double_quoted = allow_double_quoted
|
25
|
+
@allow_block = allow_block
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Emitter
|
30
|
+
DEFAULT_TAG_PREFIXES = {
|
31
|
+
"!" => "!",
|
32
|
+
"tag:yaml.org,2002:" => "!!"
|
33
|
+
}
|
34
|
+
|
35
|
+
def initialize_emitter(stream, canonical=nil, indent=nil, width=nil,line_break=nil)
|
36
|
+
# The stream should have the methods `write` and possibly `flush`.
|
37
|
+
@stream = stream
|
38
|
+
|
39
|
+
# Emitter is a state machine with a stack of states to handle nested
|
40
|
+
# structures.
|
41
|
+
@states = []
|
42
|
+
@state = :expect_stream_start
|
43
|
+
|
44
|
+
# Current event and the event queue.
|
45
|
+
@events = []
|
46
|
+
@event = nil
|
47
|
+
|
48
|
+
# The current indentation level and the stack of previous indents.
|
49
|
+
@indents = []
|
50
|
+
@indent = nil
|
51
|
+
|
52
|
+
# Flow level.
|
53
|
+
@flow_level = 0
|
54
|
+
|
55
|
+
# Contexts.
|
56
|
+
@root_context = false
|
57
|
+
@sequence_context = false
|
58
|
+
@mapping_context = false
|
59
|
+
@simple_key_context = false
|
60
|
+
|
61
|
+
# Characteristics of the last emitted character:
|
62
|
+
# - current position.
|
63
|
+
# - is it a whitespace?
|
64
|
+
# - is it an indention character
|
65
|
+
# (indentation space, '-', '?', or ':')?
|
66
|
+
@line = 0
|
67
|
+
@column = 0
|
68
|
+
@whitespace = true
|
69
|
+
@indention = true
|
70
|
+
|
71
|
+
# Formatting details.
|
72
|
+
@canonical = canonical
|
73
|
+
@best_indent = 2
|
74
|
+
@best_indent = indent if indent && indent!=0 && 1 < indent && indent < 10
|
75
|
+
|
76
|
+
@best_width = 80
|
77
|
+
@best_width = width if width && width != 0 && width > @best_indent*2
|
78
|
+
|
79
|
+
@best_line_break = "\n"
|
80
|
+
@best_line_break = line_break if ["\r", "\n", "\r\n"].include?(line_break)
|
81
|
+
|
82
|
+
# Tag prefixes.
|
83
|
+
@tag_prefixes = nil
|
84
|
+
|
85
|
+
# Prepared anchor and tag.
|
86
|
+
@prepared_anchor = nil
|
87
|
+
@prepared_tag = nil
|
88
|
+
|
89
|
+
# Scalar analysis and style.
|
90
|
+
@analysis = nil
|
91
|
+
@style = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def emit(event)
|
95
|
+
@events << event
|
96
|
+
while !need_more_events
|
97
|
+
@event = @events.shift
|
98
|
+
send(@state)
|
99
|
+
@event = nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# In some cases, we wait for a few next events before emitting.
|
104
|
+
|
105
|
+
def need_more_events
|
106
|
+
return true if @events.empty?
|
107
|
+
event = @events.first
|
108
|
+
if DocumentStartEvent === event
|
109
|
+
need_events(1)
|
110
|
+
elsif SequenceStartEvent === event
|
111
|
+
need_events(2)
|
112
|
+
elsif MappingStartEvent === event
|
113
|
+
need_events(3)
|
114
|
+
else
|
115
|
+
false
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def need_events(count)
|
120
|
+
level = 0
|
121
|
+
for event in @events[1..-1]
|
122
|
+
if DocumentStartEvent === event || CollectionStartEvent === event
|
123
|
+
level += 1
|
124
|
+
elsif DocumentEndEvent === event || CollectionEndEvent === event
|
125
|
+
level -= 1
|
126
|
+
elsif StreamEndEvent === event
|
127
|
+
level = -1
|
128
|
+
end
|
129
|
+
if level < 0
|
130
|
+
return false
|
131
|
+
end
|
132
|
+
end
|
133
|
+
@events.length < count+1
|
134
|
+
end
|
135
|
+
|
136
|
+
def increase_indent(flow=false, indentless=false)
|
137
|
+
@indents << @indent
|
138
|
+
if @indent.nil?
|
139
|
+
if flow
|
140
|
+
@indent = @best_indent
|
141
|
+
else
|
142
|
+
@indent = 0
|
143
|
+
end
|
144
|
+
elsif !indentless
|
145
|
+
@indent += @best_indent
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# States.
|
150
|
+
|
151
|
+
# Stream handlers.
|
152
|
+
|
153
|
+
def expect_stream_start
|
154
|
+
if StreamStartEvent === @event
|
155
|
+
write_stream_start
|
156
|
+
@state = :expect_first_document_start
|
157
|
+
else
|
158
|
+
raise EmitterError.new("expected StreamStartEvent, but got #{@event}")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def expect_nothing
|
163
|
+
raise EmitterError.new("expected nothing, but got #{@event}")
|
164
|
+
end
|
165
|
+
|
166
|
+
# Document handlers.
|
167
|
+
|
168
|
+
def expect_first_document_start
|
169
|
+
expect_document_start(true)
|
170
|
+
end
|
171
|
+
|
172
|
+
def expect_document_start(first=false)
|
173
|
+
if DocumentStartEvent === @event
|
174
|
+
if @event.version
|
175
|
+
version_text = prepare_version(@event.version)
|
176
|
+
write_version_directive(version_text)
|
177
|
+
end
|
178
|
+
@tag_prefixes = Emitter::DEFAULT_TAG_PREFIXES.dup
|
179
|
+
if @event.tags
|
180
|
+
handles = @event.tags.keys
|
181
|
+
handles.sort!
|
182
|
+
for handle in handles
|
183
|
+
prefix = @event.tags[handle]
|
184
|
+
@tag_prefixes[prefix] = handle
|
185
|
+
handle_text = prepare_tag_handle(handle)
|
186
|
+
prefix_text = prepare_tag_prefix(prefix)
|
187
|
+
write_tag_directive(handle_text, prefix_text)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
implicit = first && !@event.explicit && !@canonical && !@event.version && !@event.tags && !check_empty_document
|
191
|
+
if !implicit
|
192
|
+
write_indent
|
193
|
+
write_indicator("---",true)
|
194
|
+
if @canonical
|
195
|
+
write_indent
|
196
|
+
end
|
197
|
+
end
|
198
|
+
@state = :expect_document_root
|
199
|
+
elsif StreamEndEvent === @event
|
200
|
+
write_stream_end
|
201
|
+
@state = :expect_nothing
|
202
|
+
else
|
203
|
+
raise EmitterError.new("expected DocumentStartEvent, but got #{@event}")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def expect_document_end
|
208
|
+
if DocumentEndEvent === @event
|
209
|
+
write_indent
|
210
|
+
if @event.explicit
|
211
|
+
write_indicator("...", true)
|
212
|
+
write_indent
|
213
|
+
end
|
214
|
+
flush_stream
|
215
|
+
@state = :expect_document_start
|
216
|
+
else
|
217
|
+
raise EmitterError.new("expected DocumentEndEvent, but got #{@event}")
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def expect_document_root
|
222
|
+
@states << :expect_document_end
|
223
|
+
expect_node(true)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Node handlers.
|
227
|
+
|
228
|
+
def expect_node(root=false, sequence=false, mapping=false, simple_key=false)
|
229
|
+
@root_context = root
|
230
|
+
@sequence_context = sequence
|
231
|
+
@mapping_context = mapping
|
232
|
+
@simple_key_context = simple_key
|
233
|
+
if AliasEvent === @event
|
234
|
+
expect_alias
|
235
|
+
elsif ScalarEvent === @event || CollectionStartEvent === @event
|
236
|
+
process_anchor("&")
|
237
|
+
process_tag
|
238
|
+
if ScalarEvent === @event
|
239
|
+
expect_scalar
|
240
|
+
elsif SequenceStartEvent === @event
|
241
|
+
if @flow_level!=0 || @canonical || @event.flow_style || check_empty_sequence
|
242
|
+
expect_flow_sequence
|
243
|
+
else
|
244
|
+
expect_block_sequence
|
245
|
+
end
|
246
|
+
elsif MappingStartEvent === @event
|
247
|
+
if @flow_level!=0 || @canonical || @event.flow_style || check_empty_mapping
|
248
|
+
expect_flow_mapping
|
249
|
+
else
|
250
|
+
expect_block_mapping
|
251
|
+
end
|
252
|
+
end
|
253
|
+
else
|
254
|
+
raise EmitterError.new("expected NodeEvent, but got #{@event}")
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def expect_alias
|
259
|
+
raise EmitterError.new("anchor is not specified for alias") if @event.anchor.nil?
|
260
|
+
process_anchor("*")
|
261
|
+
@state = @states.pop
|
262
|
+
end
|
263
|
+
|
264
|
+
def expect_scalar
|
265
|
+
increase_indent(true)
|
266
|
+
process_scalar
|
267
|
+
@indent = @indents.pop
|
268
|
+
@state = @states.pop
|
269
|
+
end
|
270
|
+
|
271
|
+
# Flow sequence handlers.
|
272
|
+
|
273
|
+
def expect_flow_sequence
|
274
|
+
write_indicator("[", true, true)
|
275
|
+
@flow_level += 1
|
276
|
+
increase_indent(true)
|
277
|
+
@state = :expect_first_flow_sequence_item
|
278
|
+
end
|
279
|
+
|
280
|
+
def expect_first_flow_sequence_item
|
281
|
+
if SequenceEndEvent === @event
|
282
|
+
@indent = @indents.pop
|
283
|
+
@flow_level -= 1
|
284
|
+
write_indicator("]", false)
|
285
|
+
@state = @states.pop
|
286
|
+
else
|
287
|
+
write_indent if @canonical || @column > @best_width
|
288
|
+
@states << :expect_flow_sequence_item
|
289
|
+
expect_node(false,true)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def expect_flow_sequence_item
|
294
|
+
if SequenceEndEvent === @event
|
295
|
+
@indent = @indents.pop
|
296
|
+
@flow_level -= 1
|
297
|
+
if @canonical
|
298
|
+
write_indicator(",",false)
|
299
|
+
write_indent
|
300
|
+
end
|
301
|
+
write_indicator("]",false)
|
302
|
+
@state = @states.pop
|
303
|
+
else
|
304
|
+
write_indicator(",", false)
|
305
|
+
write_indent if @canonical or @column > @best_width
|
306
|
+
@states << :expect_flow_sequence_item
|
307
|
+
expect_node(false,true)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
# Flow mapping handlers.
|
312
|
+
|
313
|
+
def expect_flow_mapping
|
314
|
+
write_indicator("{", true, true)
|
315
|
+
@flow_level += 1
|
316
|
+
increase_indent(true)
|
317
|
+
@state = :expect_first_flow_mapping_key
|
318
|
+
end
|
319
|
+
|
320
|
+
def expect_first_flow_mapping_key
|
321
|
+
if MappingEndEvent === @event
|
322
|
+
@indent = @indents.pop
|
323
|
+
@flow_level -= 1
|
324
|
+
write_indicator("}", false)
|
325
|
+
@state = @states.pop
|
326
|
+
else
|
327
|
+
write_indent if @canonical || @column > @best_width
|
328
|
+
if !@canonical && check_simple_key
|
329
|
+
@states << :expect_flow_mapping_simple_value
|
330
|
+
expect_node(false,false,true,true)
|
331
|
+
else
|
332
|
+
write_indicator("?", true)
|
333
|
+
@states << :expect_flow_mapping_value
|
334
|
+
expect_node(false,false,true)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
def expect_flow_mapping_key
|
340
|
+
if MappingEndEvent === @event
|
341
|
+
@indent = @indents.pop
|
342
|
+
@flow_level -= 1
|
343
|
+
if @canonical
|
344
|
+
write_indicator(",", false)
|
345
|
+
write_indent
|
346
|
+
end
|
347
|
+
write_indicator("}", false)
|
348
|
+
@state = @states.pop
|
349
|
+
else
|
350
|
+
write_indicator(",", false)
|
351
|
+
write_indent if @canonical || @column > @best_width
|
352
|
+
if !@canonical && check_simple_key
|
353
|
+
@states << :expect_flow_mapping_simple_value
|
354
|
+
expect_node(false,false,true,true)
|
355
|
+
else
|
356
|
+
write_indicator("?", true)
|
357
|
+
@states << :expect_flow_mapping_value
|
358
|
+
expect_node(false,false,true)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def expect_flow_mapping_simple_value
|
364
|
+
write_indicator(":", false)
|
365
|
+
@states << :expect_flow_mapping_key
|
366
|
+
expect_node(false,false,true)
|
367
|
+
end
|
368
|
+
|
369
|
+
def expect_flow_mapping_value
|
370
|
+
write_indent if @canonical || @column > @best_width
|
371
|
+
write_indicator(":", true)
|
372
|
+
@states << :expect_flow_mapping_key
|
373
|
+
expect_node(false,false,true)
|
374
|
+
end
|
375
|
+
|
376
|
+
# Block sequence handlers.
|
377
|
+
|
378
|
+
def expect_block_sequence
|
379
|
+
indentless = @mapping_context && !@indention
|
380
|
+
increase_indent(false,indentless)
|
381
|
+
@state = :expect_first_block_sequence_item
|
382
|
+
end
|
383
|
+
|
384
|
+
def expect_first_block_sequence_item
|
385
|
+
expect_block_sequence_item(true)
|
386
|
+
end
|
387
|
+
|
388
|
+
def expect_block_sequence_item(first=false)
|
389
|
+
if !first && SequenceEndEvent === @event
|
390
|
+
@indent = @indents.pop
|
391
|
+
@state = @states.pop
|
392
|
+
else
|
393
|
+
write_indent
|
394
|
+
write_indicator("-", true, false, true)
|
395
|
+
@states << :expect_block_sequence_item
|
396
|
+
expect_node(false,true)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# Block mapping handlers.
|
401
|
+
|
402
|
+
def expect_block_mapping
|
403
|
+
increase_indent(false)
|
404
|
+
@state = :expect_first_block_mapping_key
|
405
|
+
end
|
406
|
+
|
407
|
+
def expect_first_block_mapping_key
|
408
|
+
expect_block_mapping_key(true)
|
409
|
+
end
|
410
|
+
|
411
|
+
def expect_block_mapping_key(first=false)
|
412
|
+
if !first && MappingEndEvent === @event
|
413
|
+
@indent = @indents.pop
|
414
|
+
@state = @states.pop
|
415
|
+
else
|
416
|
+
write_indent
|
417
|
+
if check_simple_key
|
418
|
+
@states << :expect_block_mapping_simple_value
|
419
|
+
expect_node(false,false,true,true)
|
420
|
+
else
|
421
|
+
write_indicator("?", true, false, true)
|
422
|
+
@states << :expect_block_mapping_value
|
423
|
+
expect_node(false,false,true)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def expect_block_mapping_simple_value
|
429
|
+
write_indicator(":", false)
|
430
|
+
@states << :expect_block_mapping_key
|
431
|
+
expect_node(false,false,true)
|
432
|
+
end
|
433
|
+
|
434
|
+
def expect_block_mapping_value
|
435
|
+
write_indent
|
436
|
+
write_indicator(":",true,false,true)
|
437
|
+
@states << :expect_block_mapping_key
|
438
|
+
expect_node(false,false,true)
|
439
|
+
end
|
440
|
+
|
441
|
+
# Checkers.
|
442
|
+
|
443
|
+
def check_empty_sequence
|
444
|
+
SequenceStartEvent === @event && !@events.empty? && SequenceEndEvent === @events.first
|
445
|
+
end
|
446
|
+
|
447
|
+
def check_empty_mapping
|
448
|
+
MappingStartEvent === @event && !@events.empty? && MappingEndEvent === @events.first
|
449
|
+
end
|
450
|
+
|
451
|
+
def check_empty_document
|
452
|
+
return false if !DocumentStartEvent === @event || @events.empty?
|
453
|
+
event = @events.first
|
454
|
+
ScalarEvent === event && event.anchor.nil? && event.tag.nil? && event.implicit && event.value == ""
|
455
|
+
end
|
456
|
+
|
457
|
+
def check_simple_key
|
458
|
+
length = 0
|
459
|
+
if NodeEvent === @event && !@event.anchor.nil?
|
460
|
+
@prepared_anchor = prepare_anchor(@event.anchor) if @prepared_anchor.nil?
|
461
|
+
length += @prepared_anchor.length
|
462
|
+
end
|
463
|
+
if (ScalarEvent === @event || CollectionStartEvent === @event) && !@event.tag.nil?
|
464
|
+
@prepared_tag = prepare_tag(@event.tag) if @prepared_tag.nil?
|
465
|
+
length += @prepared_tag.length
|
466
|
+
end
|
467
|
+
if ScalarEvent === @event
|
468
|
+
@analysis = analyze_scalar(@event.value) if @analysis.nil?
|
469
|
+
length += @analysis.scalar.length
|
470
|
+
end
|
471
|
+
|
472
|
+
(length < 128 && (AliasEvent === @event ||
|
473
|
+
(ScalarEvent === @event && !@analysis.empty && !@analysis.multiline) ||
|
474
|
+
check_empty_sequence || check_empty_mapping))
|
475
|
+
end
|
476
|
+
|
477
|
+
|
478
|
+
# Anchor, Tag, and Scalar processors.
|
479
|
+
|
480
|
+
def process_anchor(indicator)
|
481
|
+
if @event.anchor.nil?
|
482
|
+
@prepared_anchor = nil
|
483
|
+
return nil
|
484
|
+
end
|
485
|
+
@prepared_anchor = prepare_anchor(@event.anchor) if @prepared_anchor.nil?
|
486
|
+
write_indicator(indicator+@prepared_anchor, true) if @prepared_anchor && !@prepared_anchor.empty?
|
487
|
+
@prepared_anchor = nil
|
488
|
+
end
|
489
|
+
|
490
|
+
def process_tag
|
491
|
+
tag = @event.tag
|
492
|
+
if ScalarEvent === @event
|
493
|
+
@style = choose_scalar_style if @style.nil?
|
494
|
+
if @style == ""
|
495
|
+
@prepared_tag = nil
|
496
|
+
return nil
|
497
|
+
end
|
498
|
+
if @event.implicit && !tag
|
499
|
+
tag = "!"
|
500
|
+
@prepared_tag = nil
|
501
|
+
end
|
502
|
+
end
|
503
|
+
if !tag
|
504
|
+
@prepared_tag = nil
|
505
|
+
return nil
|
506
|
+
end
|
507
|
+
@prepared_tag = prepare_tag(tag) if @prepared_tag.nil?
|
508
|
+
write_indicator(@prepared_tag, true) if @prepared_tag && !@prepared_tag.empty?
|
509
|
+
@prepared_tag = nil
|
510
|
+
end
|
511
|
+
|
512
|
+
def choose_scalar_style
|
513
|
+
@analysis = analyze_scalar(@event.value) if @analysis.nil?
|
514
|
+
return '"' if @event.style == '"' || @canonical
|
515
|
+
if !@event.style && @event.implicit
|
516
|
+
if !(@simple_key_context && (@analysis.empty || @analysis.multiline)) && ((@flow_level!=0 && @analysis.allow_flow_plain) || (@flow_level == 0 && @analysis.allow_block_plain))
|
517
|
+
return ""
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
|
522
|
+
|
523
|
+
if !@event.style && @event.implicit && (!(@simple_key_context && (@analysis.empty || @analysis.multiline)) &&
|
524
|
+
(@flow_level!=0 && @analysis.allow_flow_plain || (@flow_level==0 && @analysis.allow_block_plain)))
|
525
|
+
return ""
|
526
|
+
end
|
527
|
+
return @event.style if @event.style && /^[|>]$/ =~ @event.style && @flow_level==0 && @analysis.allow_block
|
528
|
+
return "'" if (!@event.style || @event.style == "'") && (@analysis.allow_single_quoted && !(@simple_key_context && @analysis.multiline))
|
529
|
+
return '"'
|
530
|
+
end
|
531
|
+
|
532
|
+
def process_scalar
|
533
|
+
@analysis = analyze_scalar(@event.value) if @analysis.nil?
|
534
|
+
@style = choose_scalar_style if @style.nil?
|
535
|
+
split = !@simple_key_context
|
536
|
+
if @style == '"'
|
537
|
+
write_double_quoted(@analysis.scalar, split)
|
538
|
+
elsif @style == "'"
|
539
|
+
write_single_quoted(@analysis.scalar, split)
|
540
|
+
elsif @style == ">"
|
541
|
+
write_folded(@analysis.scalar)
|
542
|
+
elsif @style == "|"
|
543
|
+
write_literal(@analysis.scalar)
|
544
|
+
else
|
545
|
+
write_plain(@analysis.scalar, split)
|
546
|
+
end
|
547
|
+
@analysis = nil
|
548
|
+
@style = nil
|
549
|
+
end
|
550
|
+
|
551
|
+
# Analyzers.
|
552
|
+
|
553
|
+
def prepare_version(version)
|
554
|
+
major, minor = version
|
555
|
+
raise EmitterError.new("unsupported YAML version: #{major}.#{minor}") if major != 1
|
556
|
+
"#{major}.#{minor}"
|
557
|
+
end
|
558
|
+
|
559
|
+
def prepare_tag_handle(handle)
|
560
|
+
raise EmitterError.new("tag handle must not be empty") if handle.nil? || handle.empty?
|
561
|
+
raise EmitterError("tag handle must start and end with '!': #{handle}") if handle[0] != ?! || handle[-1] != ?!
|
562
|
+
raise EmitterError.new("invalid character #{$&} in the tag handle: #{handle}") if /[^-\w]/ =~ handle[1...-1]
|
563
|
+
handle
|
564
|
+
end
|
565
|
+
|
566
|
+
def prepare_tag_prefix(prefix)
|
567
|
+
raise EmitterError.new("tag prefix must not be empty") if prefix.nil? || prefix.empty?
|
568
|
+
chunks = []
|
569
|
+
start = ending = 0
|
570
|
+
ending = 1 if prefix[0] == ?!
|
571
|
+
ending += 1 while ending < prefix.length
|
572
|
+
chunks << prefix[start...ending] if start < ending
|
573
|
+
chunks.join("")
|
574
|
+
end
|
575
|
+
|
576
|
+
def prepare_tag(tag)
|
577
|
+
raise EmitterError.new("tag must not be empty") if tag.nil? || tag.empty?
|
578
|
+
return tag if tag == "!"
|
579
|
+
handle = nil
|
580
|
+
suffix = tag
|
581
|
+
for prefix in @tag_prefixes.keys
|
582
|
+
if Regexp.new("^"+Regexp.escape(prefix)) =~ tag && (prefix == "!" || prefix.length < tag.length)
|
583
|
+
handle = @tag_prefixes[prefix]
|
584
|
+
suffix = tag[prefix.length..-1]
|
585
|
+
end
|
586
|
+
end
|
587
|
+
chunks = []
|
588
|
+
start = ending = 0
|
589
|
+
ending += 1 while ending < suffix.length
|
590
|
+
chunks << suffix[start...ending] if start < ending
|
591
|
+
suffix_text = chunks.join("")
|
592
|
+
if handle
|
593
|
+
"#{handle}#{suffix_text}"
|
594
|
+
else
|
595
|
+
"!<#{suffix_text}>"
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
def prepare_anchor(anchor)
|
600
|
+
raise EmitterError.new("anchor must not be empty") if anchor.nil? || anchor.empty?
|
601
|
+
raise EmitterError.new("invalid character #{$&} in the anchor: #{anchor}") if /[^-\w]/ =~ anchor
|
602
|
+
anchor
|
603
|
+
end
|
604
|
+
|
605
|
+
def analyze_scalar(scalar)
|
606
|
+
# Empty scalar is a special case.
|
607
|
+
return ScalarAnalysis.new(scalar,true,false,false,true,true,true,false) if scalar.nil? || scalar.empty?
|
608
|
+
# Indicators and special characters.
|
609
|
+
block_indicators = false
|
610
|
+
flow_indicators = false
|
611
|
+
line_breaks = false
|
612
|
+
special_characters = false
|
613
|
+
|
614
|
+
# Whitespaces.
|
615
|
+
inline_spaces = false # non-space space+ non-space
|
616
|
+
inline_breaks = false # non-space break+ non-space
|
617
|
+
leading_spaces = false # ^ space+ (non-space | $)
|
618
|
+
leading_breaks = false # ^ break+ (non-space | $)
|
619
|
+
trailing_spaces = false # (^ | non-space) space+ $
|
620
|
+
trailing_breaks = false # (^ | non-space) break+ $
|
621
|
+
inline_breaks_spaces = false # non-space break+ space+ non-space
|
622
|
+
mixed_breaks_spaces = false # anything else
|
623
|
+
|
624
|
+
# Check document indicators.
|
625
|
+
if /^(---|\.\.\.)/ =~ scalar
|
626
|
+
block_indicators = true
|
627
|
+
flow_indicators = true
|
628
|
+
end
|
629
|
+
|
630
|
+
# First character or preceded by a whitespace.
|
631
|
+
preceeded_by_space = true
|
632
|
+
|
633
|
+
# Last character or followed by a whitespace.
|
634
|
+
followed_by_space = scalar.length == 1 || "\0 \t\r\n\x85".include?(scalar[1])
|
635
|
+
|
636
|
+
# The current series of whitespaces contain plain spaces.
|
637
|
+
spaces = false
|
638
|
+
|
639
|
+
# The current series of whitespaces contain line breaks.
|
640
|
+
breaks = false
|
641
|
+
|
642
|
+
# The current series of whitespaces contain a space followed by a
|
643
|
+
# break.
|
644
|
+
mixed = false
|
645
|
+
|
646
|
+
# The current series of whitespaces start at the beginning of the
|
647
|
+
# scalar.
|
648
|
+
leading = false
|
649
|
+
|
650
|
+
index = 0
|
651
|
+
while index < scalar.length
|
652
|
+
ch = scalar[index]
|
653
|
+
|
654
|
+
# Check for indicators.
|
655
|
+
|
656
|
+
if index == 0
|
657
|
+
# Leading indicators are special characters.
|
658
|
+
if "#,[]{}#&*!|>'\"%@`".include?(ch)
|
659
|
+
flow_indicators = true
|
660
|
+
block_indicators = true
|
661
|
+
end
|
662
|
+
if "?:".include?(ch)
|
663
|
+
flow_indicators = true
|
664
|
+
if followed_by_space
|
665
|
+
block_indicators = true
|
666
|
+
end
|
667
|
+
end
|
668
|
+
if ch == ?- && followed_by_space
|
669
|
+
flow_indicators = true
|
670
|
+
block_indicators = true
|
671
|
+
end
|
672
|
+
else
|
673
|
+
# Some indicators cannot appear within a scalar as well.
|
674
|
+
flow_indicators = true if ",?[]{}".include?(ch)
|
675
|
+
if ch == ?:
|
676
|
+
flow_indicators = true
|
677
|
+
block_indicators = true if followed_by_space
|
678
|
+
end
|
679
|
+
if ch == ?# && preceeded_by_space
|
680
|
+
flow_indicators = true
|
681
|
+
block_indicators = true
|
682
|
+
end
|
683
|
+
end
|
684
|
+
# Check for line breaks, special, and unicode characters.
|
685
|
+
line_breaks = true if "\n\x85".include?(ch)
|
686
|
+
if !(ch == ?\n || (?\x20 <= ch && ch <= ?\x7E))
|
687
|
+
special_characters = true
|
688
|
+
end
|
689
|
+
# Spaces, line breaks, and how they are mixed. State machine.
|
690
|
+
|
691
|
+
# Start or continue series of whitespaces.
|
692
|
+
if " \n\x85".include?(ch)
|
693
|
+
if spaces && breaks
|
694
|
+
mixed = true if ch != 32 # break+ (space+ break+) => mixed
|
695
|
+
elsif spaces
|
696
|
+
if ch != 32 # (space+ break+) => mixed
|
697
|
+
breaks = true
|
698
|
+
mixed = true
|
699
|
+
end
|
700
|
+
elsif breaks
|
701
|
+
spaces = true if ch == 32 # break+ space+
|
702
|
+
else
|
703
|
+
leading = (index == 0)
|
704
|
+
if ch == 32 # space+
|
705
|
+
spaces = true
|
706
|
+
else # break+
|
707
|
+
breaks = true
|
708
|
+
end
|
709
|
+
end
|
710
|
+
# Series of whitespaces ended with a non-space.
|
711
|
+
elsif spaces || breaks
|
712
|
+
if leading
|
713
|
+
if spaces && breaks
|
714
|
+
mixed_breaks_spaces = true
|
715
|
+
elsif spaces
|
716
|
+
leading_spaces = true
|
717
|
+
elsif breaks
|
718
|
+
leading_breaks = true
|
719
|
+
end
|
720
|
+
else
|
721
|
+
if mixed
|
722
|
+
mixed_breaks_spaces = true
|
723
|
+
elsif spaces && breaks
|
724
|
+
inline_breaks_spaces = true
|
725
|
+
elsif spaces
|
726
|
+
inline_spaces = true
|
727
|
+
elsif breaks
|
728
|
+
inline_breaks = true
|
729
|
+
end
|
730
|
+
end
|
731
|
+
spaces = breaks = mixed = leading = false
|
732
|
+
end
|
733
|
+
|
734
|
+
# Series of whitespaces reach the end.
|
735
|
+
if (spaces || breaks) && (index == scalar.length-1)
|
736
|
+
if spaces && breaks
|
737
|
+
mixed_breaks_spaces = true
|
738
|
+
elsif spaces
|
739
|
+
trailing_spaces = true
|
740
|
+
leading_spaces = true if leading
|
741
|
+
elsif breaks
|
742
|
+
trailing_breaks = true
|
743
|
+
leading_breaks = true if leading
|
744
|
+
end
|
745
|
+
spaces = breaks = mixed = leading = false
|
746
|
+
end
|
747
|
+
# Prepare for the next character.
|
748
|
+
index += 1
|
749
|
+
preceeded_by_space = "\0 \t\r\n\x85".include?(ch)
|
750
|
+
followed_by_space = index+1 >= scalar.length || "\0 \t\r\n\x85".include?(scalar[index+1])
|
751
|
+
end
|
752
|
+
# Let's decide what styles are allowed.
|
753
|
+
allow_flow_plain = true
|
754
|
+
allow_block_plain = true
|
755
|
+
allow_single_quoted = true
|
756
|
+
allow_double_quoted = true
|
757
|
+
allow_block = true
|
758
|
+
# Leading and trailing whitespace are bad for plain scalars. We also
|
759
|
+
# do not want to mess with leading whitespaces for block scalars.
|
760
|
+
allow_flow_plain = allow_block_plain = allow_block = false if leading_spaces || leading_breaks || trailing_spaces
|
761
|
+
|
762
|
+
# Trailing breaks are fine for block scalars, but unacceptable for
|
763
|
+
# plain scalars.
|
764
|
+
allow_flow_plain = allow_block_plain = false if trailing_breaks
|
765
|
+
|
766
|
+
# The combination of (space+ break+) is only acceptable for block
|
767
|
+
# scalars.
|
768
|
+
allow_flow_plain = allow_block_plain = allow_single_quoted = false if inline_breaks_spaces
|
769
|
+
|
770
|
+
# Mixed spaces and breaks, as well as special character are only
|
771
|
+
# allowed for double quoted scalars.
|
772
|
+
allow_flow_plain = allow_block_plain = allow_single_quoted = allow_block = false if mixed_breaks_spaces || special_characters
|
773
|
+
|
774
|
+
# We don't emit multiline plain scalars.
|
775
|
+
allow_flow_plain = allow_block_plain = false if line_breaks
|
776
|
+
|
777
|
+
# Flow indicators are forbidden for flow plain scalars.
|
778
|
+
allow_flow_plain = false if flow_indicators
|
779
|
+
|
780
|
+
# Block indicators are forbidden for block plain scalars.
|
781
|
+
allow_block_plain = false if block_indicators
|
782
|
+
|
783
|
+
ScalarAnalysis.new(scalar,false,line_breaks,allow_flow_plain,allow_block_plain,allow_single_quoted,allow_double_quoted,allow_block)
|
784
|
+
end
|
785
|
+
|
786
|
+
# Writers.
|
787
|
+
|
788
|
+
def flush_stream
|
789
|
+
@stream.flush if @stream.respond_to?(:flush)
|
790
|
+
end
|
791
|
+
|
792
|
+
def write_stream_start
|
793
|
+
end
|
794
|
+
|
795
|
+
def write_stream_end
|
796
|
+
flush_stream
|
797
|
+
end
|
798
|
+
|
799
|
+
def write_indicator(indicator, need_whitespace,whitespace=false,indention=false)
|
800
|
+
if @whitespace || !need_whitespace
|
801
|
+
data = indicator
|
802
|
+
else
|
803
|
+
data = " "+indicator
|
804
|
+
end
|
805
|
+
|
806
|
+
@whitespace = whitespace
|
807
|
+
@indention = @indention && indention
|
808
|
+
@column += data.length
|
809
|
+
@stream.write(data)
|
810
|
+
end
|
811
|
+
|
812
|
+
def write_indent
|
813
|
+
indent = @indent || 0
|
814
|
+
write_line_break if !@indention || @column > indent || (@column == indent && !@whitespace)
|
815
|
+
if @column < indent
|
816
|
+
@whitespace = true
|
817
|
+
data = " "*(indent-@column)
|
818
|
+
@column = indent
|
819
|
+
@stream.write(data)
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
def write_line_break(data=nil)
|
824
|
+
data = @best_line_break if data.nil?
|
825
|
+
@whitespace = true
|
826
|
+
@indention = true
|
827
|
+
@line += 1
|
828
|
+
@column = 0
|
829
|
+
@stream.write(data)
|
830
|
+
end
|
831
|
+
|
832
|
+
|
833
|
+
def write_version_directive(version_text)
|
834
|
+
data = "%YAML #{version_text}"
|
835
|
+
@stream.write(data)
|
836
|
+
write_line_break
|
837
|
+
end
|
838
|
+
|
839
|
+
def write_tag_directive(handle_text, prefix_text)
|
840
|
+
data = "%TAG #{handle_text} #{prefix_text}"
|
841
|
+
@stream.write(data)
|
842
|
+
write_line_break
|
843
|
+
end
|
844
|
+
|
845
|
+
# Scalar streams.
|
846
|
+
|
847
|
+
def write_single_quoted(text, split=true)
|
848
|
+
write_indicator("'",true)
|
849
|
+
spaces = false
|
850
|
+
breaks = false
|
851
|
+
start = ending = 0
|
852
|
+
while ending <= text.length
|
853
|
+
ch = nil
|
854
|
+
ch = text[ending] if ending < text.length
|
855
|
+
if spaces
|
856
|
+
if ch.nil? || ch != 32
|
857
|
+
if start+1 == ending && @column > @best_width && split && start != 0 && ending != text.length
|
858
|
+
write_indent
|
859
|
+
else
|
860
|
+
data = text[start...ending]
|
861
|
+
@column += data.length
|
862
|
+
@stream.write(data)
|
863
|
+
end
|
864
|
+
start = ending
|
865
|
+
end
|
866
|
+
elsif breaks
|
867
|
+
if ch.nil? or !"\n\x85".include?(ch)
|
868
|
+
write_line_break if text[start] == ?\n
|
869
|
+
(text[start...ending]).each_byte { |br|
|
870
|
+
if br == ?\n
|
871
|
+
write_line_break
|
872
|
+
else
|
873
|
+
write_line_break(br)
|
874
|
+
end
|
875
|
+
}
|
876
|
+
write_indent
|
877
|
+
start = ending
|
878
|
+
end
|
879
|
+
else
|
880
|
+
if ch.nil? || "' \n\x85".include?(ch)
|
881
|
+
if start < ending
|
882
|
+
data = text[start...ending]
|
883
|
+
@column += data.length
|
884
|
+
@stream.write(data)
|
885
|
+
start = ending
|
886
|
+
end
|
887
|
+
if ch == ?'
|
888
|
+
data = "''"
|
889
|
+
@column += 2
|
890
|
+
@stream.write(data)
|
891
|
+
start = ending + 1
|
892
|
+
end
|
893
|
+
end
|
894
|
+
end
|
895
|
+
|
896
|
+
if !ch.nil?
|
897
|
+
spaces = ch == 32
|
898
|
+
breaks = "\n\x85".include?(ch)
|
899
|
+
end
|
900
|
+
|
901
|
+
ending += 1
|
902
|
+
end
|
903
|
+
write_indicator("'", false)
|
904
|
+
end
|
905
|
+
|
906
|
+
ESCAPE_REPLACEMENTS = {
|
907
|
+
?\0 => "0",
|
908
|
+
?\x07 => "a",
|
909
|
+
?\x08 => "b",
|
910
|
+
?\x09 => "t",
|
911
|
+
?\x0A => "n",
|
912
|
+
?\x0B => "v",
|
913
|
+
?\x0C => "f",
|
914
|
+
?\x0D => "r",
|
915
|
+
?\x1B => "e",
|
916
|
+
?" => "\"",
|
917
|
+
?\\ => "\\",
|
918
|
+
?\x85 => "N",
|
919
|
+
?\xA0 => "_"
|
920
|
+
}
|
921
|
+
|
922
|
+
def write_double_quoted(text, split=true)
|
923
|
+
write_indicator('"', true)
|
924
|
+
start = ending = 0
|
925
|
+
while ending <= text.length
|
926
|
+
ch = nil
|
927
|
+
ch = text[ending] if ending < text.length
|
928
|
+
if ch.nil? || '"\\'.include?(ch) || !(?\x20 <= ch && ch <= ?\x7E)
|
929
|
+
if start < ending
|
930
|
+
data = text[start...ending]
|
931
|
+
@column += data.length
|
932
|
+
@stream.write(data)
|
933
|
+
start = ending
|
934
|
+
end
|
935
|
+
if !ch.nil?
|
936
|
+
if ESCAPE_REPLACEMENTS.include?(ch)
|
937
|
+
data = "\\"+ESCAPE_REPLACEMENTS[ch]
|
938
|
+
elsif ch <= ?\xFF
|
939
|
+
data = "\\x%02X" % ch
|
940
|
+
end
|
941
|
+
@column += data.length
|
942
|
+
@stream.write(data)
|
943
|
+
start = ending+1
|
944
|
+
end
|
945
|
+
end
|
946
|
+
if (0 < ending && ending < text.length-1) && (ch == 32 || start >= ending) && @column+(ending-start) > @best_width && split
|
947
|
+
data = text[start...ending]+"\\"
|
948
|
+
start = ending if start < ending
|
949
|
+
@column += data.length
|
950
|
+
@stream.write(data)
|
951
|
+
write_indent
|
952
|
+
@whitespace = false
|
953
|
+
@indention = false
|
954
|
+
if ch == 32
|
955
|
+
data = "\\"
|
956
|
+
@column += data.length
|
957
|
+
@stream.write(data)
|
958
|
+
end
|
959
|
+
end
|
960
|
+
ending += 1
|
961
|
+
end
|
962
|
+
write_indicator('"', false)
|
963
|
+
end
|
964
|
+
|
965
|
+
def determine_chomp(text)
|
966
|
+
tail = text[-2..-1]
|
967
|
+
tail = " "+tail while tail.length < 2
|
968
|
+
"\n\x85".include?(tail[-1])? ("\n\x85".include?(tail[-2])? "+" : "" ) : "-"
|
969
|
+
end
|
970
|
+
|
971
|
+
def write_folded(text)
|
972
|
+
chomp = determine_chomp(text)
|
973
|
+
write_indicator(">"+chomp, true)
|
974
|
+
write_indent
|
975
|
+
leading_space = false
|
976
|
+
spaces = false
|
977
|
+
breaks = false
|
978
|
+
start = ending = 0
|
979
|
+
while ending <= text.length
|
980
|
+
ch = nil
|
981
|
+
ch = text[ending] if ending < text.length
|
982
|
+
if breaks
|
983
|
+
if ch.nil? || !"\n\x85".include?(ch)
|
984
|
+
write_line_break if !leading_space && !ch.nil? && ch != 32 && text[start] == ?\n
|
985
|
+
leading_space = ch == 32
|
986
|
+
(text[start...ending]).each_byte { |br|
|
987
|
+
if br == ?\n
|
988
|
+
write_line_break
|
989
|
+
else
|
990
|
+
write_line_break(br)
|
991
|
+
end
|
992
|
+
}
|
993
|
+
write_indent if !ch.nil?
|
994
|
+
start = ending
|
995
|
+
end
|
996
|
+
elsif spaces
|
997
|
+
if ch != 32
|
998
|
+
if start+1 == ending && @column > @best_width
|
999
|
+
write_indent
|
1000
|
+
else
|
1001
|
+
data = text[start...ending]
|
1002
|
+
@column += data.length
|
1003
|
+
@stream.write(data)
|
1004
|
+
end
|
1005
|
+
start = ending
|
1006
|
+
end
|
1007
|
+
else
|
1008
|
+
if ch.nil? || " \n\x85".include?(ch)
|
1009
|
+
data = text[start...ending]
|
1010
|
+
@stream.write(data)
|
1011
|
+
write_line_break if ch.nil?
|
1012
|
+
start = ending
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
if !ch.nil?
|
1016
|
+
breaks = "\n\x85".include?(ch)
|
1017
|
+
spaces = ch == 32
|
1018
|
+
end
|
1019
|
+
ending += 1
|
1020
|
+
end
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
def write_literal(text)
|
1024
|
+
chomp = determine_chomp(text)
|
1025
|
+
write_indicator("|"+chomp, true)
|
1026
|
+
write_indent
|
1027
|
+
breaks = false
|
1028
|
+
start = ending = 0
|
1029
|
+
while ending <= text.length
|
1030
|
+
ch = nil
|
1031
|
+
ch = text[ending] if ending < text.length
|
1032
|
+
if breaks
|
1033
|
+
if ch.nil? || !"\n\x85".include?(ch)
|
1034
|
+
(text[start...ending]).each_byte { |br|
|
1035
|
+
if br == ?\n
|
1036
|
+
write_line_break
|
1037
|
+
else
|
1038
|
+
write_line_break(br)
|
1039
|
+
end
|
1040
|
+
}
|
1041
|
+
write_indent if !ch.nil?
|
1042
|
+
start = ending
|
1043
|
+
end
|
1044
|
+
else
|
1045
|
+
if ch.nil? || "\n\x85".include?(ch)
|
1046
|
+
data = text[start...ending]
|
1047
|
+
@stream.write(data)
|
1048
|
+
write_line_break if ch.nil?
|
1049
|
+
start = ending
|
1050
|
+
end
|
1051
|
+
end
|
1052
|
+
breaks = "\n\x85".include?(ch) if !ch.nil?
|
1053
|
+
ending += 1
|
1054
|
+
end
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def write_plain(text, split=true)
|
1058
|
+
return nil if text.nil? || text.empty?
|
1059
|
+
if !@whitespace
|
1060
|
+
data = " "
|
1061
|
+
@column += data.length
|
1062
|
+
@stream.write(data)
|
1063
|
+
end
|
1064
|
+
@writespace = false
|
1065
|
+
@indention = false
|
1066
|
+
spaces = false
|
1067
|
+
breaks = false
|
1068
|
+
start = ending = 0
|
1069
|
+
while ending <= text.length
|
1070
|
+
ch = nil
|
1071
|
+
ch = text[ending] if ending < text.length
|
1072
|
+
if spaces
|
1073
|
+
if ch != 32
|
1074
|
+
if start+1 == ending && @column > @best_width && split
|
1075
|
+
write_indent
|
1076
|
+
@writespace = false
|
1077
|
+
@indention = false
|
1078
|
+
else
|
1079
|
+
data = text[start...ending]
|
1080
|
+
@column += data.length
|
1081
|
+
@stream.write(data)
|
1082
|
+
end
|
1083
|
+
start = ending
|
1084
|
+
end
|
1085
|
+
elsif breaks
|
1086
|
+
if !"\n\x85".include?(ch)
|
1087
|
+
write_line_break if text[start] == ?\n
|
1088
|
+
(text[start...ending]).each_byte { |br|
|
1089
|
+
if br == ?\n
|
1090
|
+
write_line_break
|
1091
|
+
else
|
1092
|
+
write_line_break(br)
|
1093
|
+
end
|
1094
|
+
}
|
1095
|
+
write_indent
|
1096
|
+
@whitespace = false
|
1097
|
+
@indention = false
|
1098
|
+
start = ending
|
1099
|
+
end
|
1100
|
+
else
|
1101
|
+
if ch.nil? || " \n\x85".include?(ch)
|
1102
|
+
data = text[start...ending]
|
1103
|
+
@column += data.length
|
1104
|
+
@stream.write(data)
|
1105
|
+
start = ending
|
1106
|
+
end
|
1107
|
+
end
|
1108
|
+
if !ch.nil?
|
1109
|
+
spaces = ch == 32
|
1110
|
+
breaks = "\n\x85".include?(ch)
|
1111
|
+
end
|
1112
|
+
ending += 1
|
1113
|
+
end
|
1114
|
+
end
|
1115
|
+
end
|
1116
|
+
end
|