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
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2006 Ola Bini
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
= RbYAML - A pure Ruby YAML 1.1 loader and dumper
|
2
|
+
|
3
|
+
Project Contact: Ola Bini <ola@ologix.com>
|
4
|
+
|
5
|
+
The code is based mostly on the Python code written by Kirill Simonov <xi@resolvent.net> for PyYAML3000.
|
6
|
+
|
7
|
+
RbYAML is a project originating in the JRuby project (http://jruby.sourceforge.net), to create a pure Ruby
|
8
|
+
YAML parser for use in JRuby and SYCK cannot be used in this case.
|
9
|
+
Since the effort of writing a new one from scratch seemed like a major undertaking it seemed easier to
|
10
|
+
port an existing one.
|
11
|
+
|
12
|
+
The current functionality is more or less 1.1-compliant. What's missing is the Unicode-support. The idea
|
13
|
+
is to have the interface resemble SYCK as much as possible, but this is still work in progress, since some
|
14
|
+
of the major architectural choices are quite different.
|
15
|
+
|
16
|
+
== Use
|
17
|
+
|
18
|
+
Just require 'rbyaml' and use it as you would use YAML, but in module RbYAML instead:
|
19
|
+
|
20
|
+
require 'rbyaml'
|
21
|
+
|
22
|
+
RbYAML.load("--- \n- A\n- b\n- c\n") ----> ["A","b","c"]
|
23
|
+
"foo".to_yaml ----> "foo\n"
|
24
|
+
|
25
|
+
== More information
|
26
|
+
|
27
|
+
Visit http://rbyaml.ologix.com for more information and updated versions
|
28
|
+
|
29
|
+
== License
|
30
|
+
|
31
|
+
RbYAML is distributed with a MIT license, which can be found in the file LICENSE.
|
data/lib/rbyaml.rb
ADDED
@@ -0,0 +1,378 @@
|
|
1
|
+
|
2
|
+
require 'rbyaml/yaml'
|
3
|
+
|
4
|
+
module RbYAML
|
5
|
+
def self.dump(obj, io = nil)
|
6
|
+
_dump(obj,io)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.load( io )
|
10
|
+
_load(io)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.load_file( filepath )
|
14
|
+
File.open( filepath ) do |f|
|
15
|
+
load( f )
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# this operation does not make sense in RbYAML (right now)
|
20
|
+
def self.parse( io )
|
21
|
+
# yp = @@parser.new( :Model => :Generic ).load( io )
|
22
|
+
end
|
23
|
+
|
24
|
+
# this operation does not make sense in RbYAML (right now)
|
25
|
+
def self.parse_file( filepath )
|
26
|
+
# File.open( filepath ) do |f|
|
27
|
+
# parse( f )
|
28
|
+
# end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.each_document( io, &block )
|
32
|
+
_load_all(io,&block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.load_documents( io, &doc_proc )
|
36
|
+
each_document( io, &doc_proc )
|
37
|
+
end
|
38
|
+
|
39
|
+
# this operation does not make sense in RbYAML (right now)
|
40
|
+
def self.each_node( io, &doc_proc )
|
41
|
+
# yp = @@parser.new( :Model => :Generic ).load_documents( io, &doc_proc )
|
42
|
+
end
|
43
|
+
|
44
|
+
# this operation does not make sense in RbYAML (right now)
|
45
|
+
def self.parse_documents( io, &doc_proc )
|
46
|
+
# YAML.each_node( io, &doc_proc )
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.load_stream( io )
|
50
|
+
d = nil
|
51
|
+
load_documents(io) { |doc|
|
52
|
+
d = Stream.new( nil ) if not d
|
53
|
+
d.add( doc )
|
54
|
+
}
|
55
|
+
d
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.dump_stream( *objs )
|
59
|
+
d = RbYAML::Stream.new
|
60
|
+
objs.each do |doc|
|
61
|
+
d.add( doc )
|
62
|
+
end
|
63
|
+
d.emit
|
64
|
+
end
|
65
|
+
|
66
|
+
# this operation does not make sense in RbYAML (right now)
|
67
|
+
def self.add_domain_type( domain, type_re, &transfer_proc )
|
68
|
+
# @@loader.add_domain_type( domain, type_re, &transfer_proc )
|
69
|
+
end
|
70
|
+
|
71
|
+
# this operation does not make sense in RbYAML (right now)
|
72
|
+
def self.add_builtin_type( type_re, &transfer_proc )
|
73
|
+
# @@loader.add_builtin_type( type_re, &transfer_proc )
|
74
|
+
end
|
75
|
+
|
76
|
+
# this operation does not make sense in RbYAML (right now)
|
77
|
+
def self.add_ruby_type( type_tag, &transfer_proc )
|
78
|
+
# @@loader.add_ruby_type( type, &transfer_proc )
|
79
|
+
end
|
80
|
+
|
81
|
+
# this operation does not make sense in RbYAML (right now)
|
82
|
+
def self.add_private_type( type_re, &transfer_proc )
|
83
|
+
# @@loader.add_private_type( type_re, &transfer_proc )
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.detect_implicit( val )
|
87
|
+
SimpleDetector.detect(val)
|
88
|
+
end
|
89
|
+
|
90
|
+
# this operation does not make sense in RbYAML (right now)
|
91
|
+
def self.transfer( type_id, obj )
|
92
|
+
# @@loader.transfer( type_id, obj )
|
93
|
+
end
|
94
|
+
|
95
|
+
# this operation does not make sense in RbYAML (right now)
|
96
|
+
def self.try_implicit( obj )
|
97
|
+
# YAML.transfer( YAML.detect_implicit( obj ), obj )
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.read_type_class( type, obj_class )
|
101
|
+
scheme, domain, type, tclass = type.split( ':', 4 )
|
102
|
+
tclass.split( "::" ).each { |c| obj_class = obj_class.const_get( c ) } if tclass
|
103
|
+
return [ type, obj_class ]
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.object_maker( obj_class, val )
|
107
|
+
if Hash === val
|
108
|
+
o = obj_class.allocate
|
109
|
+
val.each_pair { |k,v|
|
110
|
+
o.instance_variable_set("@#{k}", v)
|
111
|
+
}
|
112
|
+
o
|
113
|
+
else
|
114
|
+
raise YAMLError, "Invalid object explicitly tagged !ruby/Object: " + val.inspect
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# this operation does not make sense in RbYAML (right now)
|
119
|
+
def self.quick_emit( oid, opts = {}, &e )
|
120
|
+
end
|
121
|
+
|
122
|
+
# A dictionary of taguris which map to
|
123
|
+
# Ruby classes.
|
124
|
+
@@tagged_classes = {}
|
125
|
+
|
126
|
+
#
|
127
|
+
# Associates a taguri _tag_ with a Ruby class _cls_. The taguri is used to give types
|
128
|
+
# to classes when loading YAML. Taguris are of the form:
|
129
|
+
#
|
130
|
+
# tag:authorityName,date:specific
|
131
|
+
#
|
132
|
+
# The +authorityName+ is a domain name or email address. The +date+ is the date the type
|
133
|
+
# was issued in YYYY or YYYY-MM or YYYY-MM-DD format. The +specific+ is a name for
|
134
|
+
# the type being added.
|
135
|
+
#
|
136
|
+
# For example, built-in YAML types have 'yaml.org' as the +authorityName+ and '2002' as the
|
137
|
+
# +date+. The +specific+ is simply the name of the type:
|
138
|
+
#
|
139
|
+
# tag:yaml.org,2002:int
|
140
|
+
# tag:yaml.org,2002:float
|
141
|
+
# tag:yaml.org,2002:timestamp
|
142
|
+
#
|
143
|
+
# The domain must be owned by you on the +date+ declared. If you don't own any domains on the
|
144
|
+
# date you declare the type, you can simply use an e-mail address.
|
145
|
+
#
|
146
|
+
# tag:why@ruby-lang.org,2004:notes/personal
|
147
|
+
#
|
148
|
+
def self.tag_class( tag, cls )
|
149
|
+
if @@tagged_classes.has_key? tag
|
150
|
+
warn "class #{ @@tagged_classes[tag] } held ownership of the #{ tag } tag"
|
151
|
+
end
|
152
|
+
@@tagged_classes[tag] = cls
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns the complete dictionary of taguris, paired with classes. The key for
|
156
|
+
# the dictionary is the full taguri. The value for each key is the class constant
|
157
|
+
# associated to that taguri.
|
158
|
+
#
|
159
|
+
# YAML.tagged_classes["tag:yaml.org,2002:int"] => Integer
|
160
|
+
#
|
161
|
+
def self.tagged_classes
|
162
|
+
@@tagged_classes
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# RbYAML::Stream -- for emitting many documents
|
167
|
+
#
|
168
|
+
class Stream
|
169
|
+
include Enumerable
|
170
|
+
|
171
|
+
attr_accessor :documents, :options
|
172
|
+
def initialize(opts = {})
|
173
|
+
@options = opts
|
174
|
+
@documents = []
|
175
|
+
end
|
176
|
+
|
177
|
+
def [](i)
|
178
|
+
@documents[ i ]
|
179
|
+
end
|
180
|
+
|
181
|
+
def add(doc)
|
182
|
+
@documents << doc
|
183
|
+
end
|
184
|
+
|
185
|
+
def edit(doc_num,doc)
|
186
|
+
@documents[ doc_num ] = doc
|
187
|
+
end
|
188
|
+
|
189
|
+
def each(&block)
|
190
|
+
@documents.each(&block)
|
191
|
+
end
|
192
|
+
|
193
|
+
def emit
|
194
|
+
# TODO: implement
|
195
|
+
|
196
|
+
opts = @options.dup
|
197
|
+
opts[:UseHeader] = true if @documents.length > 1
|
198
|
+
ct = 0
|
199
|
+
out = Emitter.new( opts )
|
200
|
+
@documents.each { |v|
|
201
|
+
if ct > 0
|
202
|
+
out << "\n--- "
|
203
|
+
end
|
204
|
+
v.to_yaml( :Emitter => out )
|
205
|
+
ct += 1
|
206
|
+
}
|
207
|
+
out.end_object
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
if !Object.method_defined?(:to_yaml)
|
213
|
+
class Module # :nodoc: all
|
214
|
+
def yaml_as( tag, sc = true )
|
215
|
+
class_eval <<-"end;", __FILE__, __LINE__+1
|
216
|
+
attr_writer :taguri
|
217
|
+
def taguri
|
218
|
+
return @taguri if defined?(@taguri) and @taguri
|
219
|
+
tag = #{ tag.dump }
|
220
|
+
if self.class.yaml_tag_subclasses? and self.class != RbYAML::tagged_classes[tag]
|
221
|
+
tag = "\#{ tag }:\#{ self.class.yaml_tag_class_name }"
|
222
|
+
end
|
223
|
+
tag
|
224
|
+
end
|
225
|
+
def self.yaml_tag_subclasses?; #{ sc ? 'true' : 'false' }; end
|
226
|
+
end;
|
227
|
+
RbYAML::tag_class tag, self
|
228
|
+
end
|
229
|
+
# Transforms the subclass name into a name suitable for display
|
230
|
+
# in a subclassed tag.
|
231
|
+
def yaml_tag_class_name
|
232
|
+
self.name
|
233
|
+
end
|
234
|
+
# Transforms the subclass name found in the tag into a Ruby
|
235
|
+
# constant name.
|
236
|
+
def yaml_tag_read_class( name )
|
237
|
+
name
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
require 'date'
|
242
|
+
|
243
|
+
class Class
|
244
|
+
def to_yaml( opts = {} )
|
245
|
+
raise RbYAML::TypeError, "can't dump anonymous class %s" % self.class
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
class Object
|
250
|
+
yaml_as "tag:ruby.yaml.org,2002:object"
|
251
|
+
def is_complex_yaml?; true; end
|
252
|
+
def to_yaml_style; end
|
253
|
+
def to_yaml_properties; instance_variables.sort; end
|
254
|
+
def to_yaml( opts = {} )
|
255
|
+
RbYAML::_dump_ruby_object(self)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class Hash
|
260
|
+
yaml_as "tag:ruby.yaml.org,2002:hash"
|
261
|
+
yaml_as "tag:yaml.org,2002:map"
|
262
|
+
def is_complex_yaml?; true; end
|
263
|
+
def yaml_initialize( tag, val )
|
264
|
+
if Array === val
|
265
|
+
update Hash.[]( *val ) # Convert the map to a sequence
|
266
|
+
elsif Hash === val
|
267
|
+
update val
|
268
|
+
else
|
269
|
+
raise RbYAML::TypeError, "Invalid map explicitly tagged #{ tag }: " + val.inspect
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class Array
|
275
|
+
yaml_as "tag:ruby.yaml.org,2002:array"
|
276
|
+
yaml_as "tag:yaml.org,2002:seq"
|
277
|
+
def is_complex_yaml?; true; end
|
278
|
+
def yaml_initialize( tag, val ); concat( val.to_a ); end
|
279
|
+
end
|
280
|
+
|
281
|
+
class Exception
|
282
|
+
yaml_as "tag:ruby.yaml.org,2002:exception"
|
283
|
+
def Exception.yaml_new( klass, tag, val )
|
284
|
+
o = RbYAML.object_maker( klass, { 'mesg' => val.delete( 'message' ) } )
|
285
|
+
val.each_pair do |k,v|
|
286
|
+
o.instance_variable_set("@#{k}", v)
|
287
|
+
end
|
288
|
+
o
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class String
|
293
|
+
yaml_as "tag:ruby.yaml.org,2002:string"
|
294
|
+
yaml_as "tag:yaml.org,2002:binary"
|
295
|
+
yaml_as "tag:yaml.org,2002:str"
|
296
|
+
def is_complex_yaml?
|
297
|
+
to_yaml_style or not to_yaml_properties.empty? or self =~ /\n.+/
|
298
|
+
end
|
299
|
+
def is_binary_data?
|
300
|
+
( self.count( "^ -~", "^\r\n" ) / self.size > 0.3 || self.count( "\x00" ) > 0 ) unless empty?
|
301
|
+
end
|
302
|
+
def String.yaml_new( klass, tag, val )
|
303
|
+
val = val.unpack("m")[0] if tag == "tag:yaml.org,2002:binary"
|
304
|
+
val = { 'str' => val } if String === val
|
305
|
+
if Hash === val
|
306
|
+
s = klass.allocate
|
307
|
+
# Thank you, NaHi
|
308
|
+
String.instance_method(:initialize).
|
309
|
+
bind(s).
|
310
|
+
call( val.delete( 'str' ) )
|
311
|
+
val.each { |k,v| s.instance_variable_set( k, v ) }
|
312
|
+
s
|
313
|
+
else
|
314
|
+
raise RbYAML::TypeError, "Invalid String: " + val.inspect
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
class Symbol
|
320
|
+
yaml_as "tag:ruby.yaml.org,2002:symbol"
|
321
|
+
yaml_as "tag:ruby.yaml.org,2002:sym"
|
322
|
+
def is_complex_yaml?; false; end
|
323
|
+
def Symbol.yaml_new( klass, tag, val )
|
324
|
+
if String === val
|
325
|
+
val.intern
|
326
|
+
else
|
327
|
+
raise RbYAML::TypeError, "Invalid Symbol: " + val.inspect
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
class Time
|
333
|
+
yaml_as "tag:ruby.yaml.org,2002:time"
|
334
|
+
yaml_as "tag:yaml.org,2002:timestamp"
|
335
|
+
def is_complex_yaml?; false; end
|
336
|
+
def Time.yaml_new( klass, tag, val )
|
337
|
+
if Hash === val
|
338
|
+
t = val.delete( 'at' )
|
339
|
+
val.each { |k,v| t.instance_variable_set( k, v ) }
|
340
|
+
t
|
341
|
+
else
|
342
|
+
raise RbYAML::TypeError, "Invalid Time: " + val.inspect
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
class Date
|
348
|
+
yaml_as "tag:yaml.org,2002:timestamp#ymd"
|
349
|
+
def is_complex_yaml?; false; end
|
350
|
+
end
|
351
|
+
|
352
|
+
class Numeric
|
353
|
+
def is_complex_yaml?; false; end
|
354
|
+
end
|
355
|
+
|
356
|
+
class Fixnum
|
357
|
+
yaml_as "tag:yaml.org,2002:int"
|
358
|
+
end
|
359
|
+
|
360
|
+
class Float
|
361
|
+
yaml_as "tag:yaml.org,2002:float"
|
362
|
+
end
|
363
|
+
|
364
|
+
class TrueClass
|
365
|
+
yaml_as "tag:yaml.org,2002:bool#yes"
|
366
|
+
def is_complex_yaml?; false; end
|
367
|
+
end
|
368
|
+
|
369
|
+
class FalseClass
|
370
|
+
yaml_as "tag:yaml.org,2002:bool#no"
|
371
|
+
def is_complex_yaml?; false; end
|
372
|
+
end
|
373
|
+
|
374
|
+
class NilClass
|
375
|
+
yaml_as "tag:yaml.org,2002:null"
|
376
|
+
def is_complex_yaml?; false; end
|
377
|
+
end
|
378
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'rbyaml/error'
|
2
|
+
require 'rbyaml/events'
|
3
|
+
require 'rbyaml/nodes'
|
4
|
+
|
5
|
+
module RbYAML
|
6
|
+
class ComposerError < MarkedYAMLError
|
7
|
+
end
|
8
|
+
|
9
|
+
module BaseComposer
|
10
|
+
@@yaml_resolvers = {}
|
11
|
+
|
12
|
+
def initialize_composer
|
13
|
+
@all_anchors = {}
|
14
|
+
@complete_anchors = {}
|
15
|
+
@resolver_tags = []
|
16
|
+
@resolver_paths = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def check_node
|
20
|
+
!check_event(StreamEndEvent)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_node
|
24
|
+
compose_document if check_node
|
25
|
+
end
|
26
|
+
|
27
|
+
def each_node
|
28
|
+
yield compose_document while check_node
|
29
|
+
end
|
30
|
+
|
31
|
+
def compose_document
|
32
|
+
# Drop the STREAM-START event.
|
33
|
+
get_event if check_event(StreamStartEvent)
|
34
|
+
get_event
|
35
|
+
# Compose the root node.
|
36
|
+
node = compose_node([])
|
37
|
+
# Drop the DOCUMENT-END event.
|
38
|
+
get_event
|
39
|
+
@all_anchors = {}
|
40
|
+
@complete_anchors = {}
|
41
|
+
@resolver_tags = []
|
42
|
+
@resolver_paths = []
|
43
|
+
node
|
44
|
+
end
|
45
|
+
|
46
|
+
def increase_resolver_depth(path)
|
47
|
+
depth = path.length
|
48
|
+
tag = []
|
49
|
+
paths = []
|
50
|
+
if depth == 0
|
51
|
+
for resolver_path in @@yaml_resolvers.keys
|
52
|
+
if resolver_path
|
53
|
+
paths += resolver_path
|
54
|
+
else
|
55
|
+
tag = @@yaml_resolvers[resolver_path]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
else
|
59
|
+
base, index = path[-1]
|
60
|
+
if ScalarNode === index && index.tag == DEFAULT_SCALAR_TAG
|
61
|
+
index = index.value
|
62
|
+
elsif Node === index
|
63
|
+
index = nil
|
64
|
+
end
|
65
|
+
if @resolver_paths[-1]
|
66
|
+
for resolver_path in @resolver_paths[-1]
|
67
|
+
resolver_index = resolver_path[depth-1]
|
68
|
+
if resolver_index.nil? || resolver_index == index
|
69
|
+
if resolver_index.length > depth
|
70
|
+
paths += resolver_path
|
71
|
+
else
|
72
|
+
tag = @@yaml_resolvers[resolver_path]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
@resolver_tags += tag
|
80
|
+
@resolver_paths += paths
|
81
|
+
end
|
82
|
+
|
83
|
+
def decrease_resolver_depth
|
84
|
+
@resolver_tags.pop
|
85
|
+
@resolver_paths.pop
|
86
|
+
end
|
87
|
+
|
88
|
+
def compose_node(path)
|
89
|
+
if check_event(AliasEvent)
|
90
|
+
event = get_event
|
91
|
+
anchor = event.anchor
|
92
|
+
raise ComposerError.new(nil, nil, "found undefined alias #{anchor}", event.start_mark) if !@all_anchors.include?(anchor)
|
93
|
+
if !@complete_anchors.include?(anchor)
|
94
|
+
collection_event = @all_anchors[anchor]
|
95
|
+
raise ComposerError.new("while composing a collection",collection_event.start_mark,"found recursive anchor #{anchor}",event.start_mark)
|
96
|
+
end
|
97
|
+
return @complete_anchors[anchor]
|
98
|
+
end
|
99
|
+
increase_resolver_depth(path)
|
100
|
+
event = peek_event
|
101
|
+
anchor = event.anchor
|
102
|
+
if !anchor.nil?
|
103
|
+
if @all_anchors.include?(anchor)
|
104
|
+
raise ComposerError.new("found duplicate anchor #{anchor}; first occurence", @all_anchors[anchor].start_mark,"second occurence", event.start_mark)
|
105
|
+
end
|
106
|
+
@all_anchors[anchor] = event
|
107
|
+
end
|
108
|
+
if check_event(ScalarEvent)
|
109
|
+
node = compose_scalar_node(path)
|
110
|
+
elsif check_event(SequenceStartEvent)
|
111
|
+
node = compose_sequence_node(path)
|
112
|
+
elsif check_event(MappingStartEvent)
|
113
|
+
node = compose_mapping_node(path)
|
114
|
+
end
|
115
|
+
|
116
|
+
if !anchor.nil?
|
117
|
+
@complete_anchors[anchor] = node
|
118
|
+
end
|
119
|
+
decrease_resolver_depth
|
120
|
+
node
|
121
|
+
end
|
122
|
+
|
123
|
+
def compose_scalar_node(path)
|
124
|
+
event = get_event
|
125
|
+
tag = resolve_scalar(path, event.tag, event.implicit, event.value)
|
126
|
+
ScalarNode.new(tag, event.value,event.start_mark, event.end_mark, style=event.style)
|
127
|
+
end
|
128
|
+
|
129
|
+
def compose_sequence_node(path)
|
130
|
+
start_event = get_event
|
131
|
+
tag = resolve_sequence(path, start_event.tag)
|
132
|
+
node = SequenceNode.new(tag, [],start_event.start_mark, nil,flow_style=start_event.flow_style)
|
133
|
+
index = 0
|
134
|
+
while !check_event(SequenceEndEvent)
|
135
|
+
node.value << compose_node(path+[[node, index]])
|
136
|
+
index += 1
|
137
|
+
end
|
138
|
+
|
139
|
+
end_event = get_event
|
140
|
+
node.end_mark = end_event.end_mark
|
141
|
+
node
|
142
|
+
end
|
143
|
+
|
144
|
+
def compose_mapping_node(path)
|
145
|
+
start_event = get_event
|
146
|
+
tag = resolve_mapping(path, start_event.tag)
|
147
|
+
node = MappingNode.new(tag, {},start_event.start_mark, nil,flow_style=start_event.flow_style)
|
148
|
+
while !check_event(MappingEndEvent)
|
149
|
+
key_event = peek_event
|
150
|
+
item_key = compose_node(path+[[node, nil]])
|
151
|
+
item_value = compose_node(path+[[node, item_key]])
|
152
|
+
if node.value.include?(item_key)
|
153
|
+
raise ComposerError.new("while composing a mapping", start_event.start_mark,"found duplicate key", key_event.start_mark)
|
154
|
+
end
|
155
|
+
node.value[item_key] = item_value
|
156
|
+
end
|
157
|
+
end_event = get_event
|
158
|
+
node.end_mark = end_event.end_mark
|
159
|
+
node
|
160
|
+
end
|
161
|
+
|
162
|
+
def resolve_scalar(path, tag, implicit, value)
|
163
|
+
tag = detect(value) if implicit
|
164
|
+
tag = resolver_tags[-1] if (tag.nil? || tag == []) && @resolver_tags[-1]
|
165
|
+
tag = DEFAULT_SCALAR_TAG if tag.nil? || tag == [] || tag == "!"
|
166
|
+
tag
|
167
|
+
end
|
168
|
+
|
169
|
+
def resolve_sequence(path, tag)
|
170
|
+
tag = resolver_tags[-1] if tag.nil? && @resolver_tags[-1]
|
171
|
+
tag = DEFAULT_SEQUENCE_TAG if tag.nil? || tag == "!"
|
172
|
+
tag
|
173
|
+
end
|
174
|
+
|
175
|
+
def resolve_mapping(path, tag)
|
176
|
+
tag = resolver_tags[-1] if tag.nil? && @resolver_tags[-1]
|
177
|
+
tag = DEFAULT_MAPPING_TAG if tag.nil? || tag == "!"
|
178
|
+
tag
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.add_resolver(tag, path)
|
182
|
+
@@yaml_resolvers[path] = tag
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
module Composer
|
187
|
+
include BaseComposer
|
188
|
+
end
|
189
|
+
end
|