rubysl-yaml 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/syck.rb ADDED
@@ -0,0 +1,491 @@
1
+ # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4
2
+ # $Id: syck.rb 28681 2010-07-19 04:54:06Z tenderlove $
3
+ #
4
+ # = yaml.rb: top-level module with methods for loading and parsing YAML documents
5
+ #
6
+ # Author:: why the lucky stiff
7
+ #
8
+
9
+ require 'stringio'
10
+ require 'syck/syck'
11
+ require 'syck/error'
12
+ require 'syck/basenode'
13
+ require 'syck/tag'
14
+ require 'syck/stream'
15
+ require 'syck/constants'
16
+ require 'syck/rubytypes'
17
+ require 'syck/types'
18
+
19
+ # == YAML
20
+ #
21
+ # YAML(tm) (rhymes with 'camel') is a
22
+ # straightforward machine parsable data serialization format designed for
23
+ # human readability and interaction with scripting languages such as Perl
24
+ # and Python. YAML is optimized for data serialization, formatted
25
+ # dumping, configuration files, log files, Internet messaging and
26
+ # filtering. This specification describes the YAML information model and
27
+ # serialization format. Together with the Unicode standard for characters, it
28
+ # provides all the information necessary to understand YAML Version 1.0
29
+ # and construct computer programs to process it.
30
+ #
31
+ # See http://yaml.org/ for more information. For a quick tutorial, please
32
+ # visit YAML In Five Minutes (http://yaml.kwiki.org/?YamlInFiveMinutes).
33
+ #
34
+ # == About This Library
35
+ #
36
+ # The YAML 1.0 specification outlines four stages of YAML loading and dumping.
37
+ # This library honors all four of those stages, although data is really only
38
+ # available to you in three stages.
39
+ #
40
+ # The four stages are: native, representation, serialization, and presentation.
41
+ #
42
+ # The native stage refers to data which has been loaded completely into Ruby's
43
+ # own types. (See +YAML::load+.)
44
+ #
45
+ # The representation stage means data which has been composed into
46
+ # +YAML::BaseNode+ objects. In this stage, the document is available as a
47
+ # tree of node objects. You can perform YPath queries and transformations
48
+ # at this level. (See +YAML::parse+.)
49
+ #
50
+ # The serialization stage happens inside the parser. The YAML parser used in
51
+ # Ruby is called Syck. Serialized nodes are available in the extension as
52
+ # SyckNode structs.
53
+ #
54
+ # The presentation stage is the YAML document itself. This is accessible
55
+ # to you as a string. (See +YAML::dump+.)
56
+ #
57
+ # For more information about the various information models, see Chapter
58
+ # 3 of the YAML 1.0 Specification (http://yaml.org/spec/#id2491269).
59
+ #
60
+ # The YAML module provides quick access to the most common loading (YAML::load)
61
+ # and dumping (YAML::dump) tasks. This module also provides an API for registering
62
+ # global types (YAML::add_domain_type).
63
+ #
64
+ # == Example
65
+ #
66
+ # A simple round-trip (load and dump) of an object.
67
+ #
68
+ # require "yaml"
69
+ #
70
+ # test_obj = ["dogs", "cats", "badgers"]
71
+ #
72
+ # yaml_obj = YAML::dump( test_obj )
73
+ # # -> ---
74
+ # - dogs
75
+ # - cats
76
+ # - badgers
77
+ # ruby_obj = YAML::load( yaml_obj )
78
+ # # => ["dogs", "cats", "badgers"]
79
+ # ruby_obj == test_obj
80
+ # # => true
81
+ #
82
+ # To register your custom types with the global resolver, use +add_domain_type+.
83
+ #
84
+ # YAML::add_domain_type( "your-site.com,2004", "widget" ) do |type, val|
85
+ # Widget.new( val )
86
+ # end
87
+ #
88
+ module Syck
89
+
90
+ DefaultResolver.use_types_at( @@tagged_classes )
91
+
92
+ # Returns a new default parser
93
+ def self.parser; Parser.new.set_resolver( self.resolver ); end
94
+
95
+ # Returns a new generic parser
96
+ def self.generic_parser
97
+ warn "#{caller[0]}: YAML.generic_parser is deprecated, switch to psych" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
98
+ Parser.new.set_resolver( GenericResolver )
99
+ end
100
+
101
+ # Returns the default resolver
102
+ def self.resolver
103
+ warn "#{caller[0]}: YAML.resolver is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
104
+ DefaultResolver
105
+ end
106
+
107
+ # Returns a new default emitter
108
+ def self.emitter
109
+ warn "#{caller[0]}: YAML.emitter is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
110
+ Emitter.new.set_resolver( self.resolver )
111
+ end
112
+
113
+ #
114
+ # Converts _obj_ to YAML and writes the YAML result to _io_.
115
+ #
116
+ # File.open( 'animals.yaml', 'w' ) do |out|
117
+ # YAML.dump( ['badger', 'elephant', 'tiger'], out )
118
+ # end
119
+ #
120
+ # If no _io_ is provided, a string containing the dumped YAML
121
+ # is returned.
122
+ #
123
+ # YAML.dump( :locked )
124
+ # #=> "--- :locked"
125
+ #
126
+ def self.dump( obj, io = nil )
127
+ obj.to_yaml( io || io2 = StringIO.new )
128
+ io || ( io2.rewind; io2.read )
129
+ end
130
+
131
+ #
132
+ # Load a document from the current _io_ stream.
133
+ #
134
+ # File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) }
135
+ # #=> ['badger', 'elephant', 'tiger']
136
+ #
137
+ # Can also load from a string.
138
+ #
139
+ # YAML.load( "--- :locked" )
140
+ # #=> :locked
141
+ #
142
+ def self.load( io )
143
+ parser.load( io )
144
+ end
145
+
146
+ #
147
+ # Load a document from the file located at _filepath_.
148
+ #
149
+ # YAML.load_file( 'animals.yaml' )
150
+ # #=> ['badger', 'elephant', 'tiger']
151
+ #
152
+ def self.load_file( filepath )
153
+ File.open( filepath ) do |f|
154
+ load( f )
155
+ end
156
+ end
157
+
158
+ #
159
+ # Parse the first document from the current _io_ stream
160
+ #
161
+ # File.open( 'animals.yaml' ) { |yf| YAML::load( yf ) }
162
+ # #=> #<YAML::Syck::Node:0x82ccce0
163
+ # @kind=:seq,
164
+ # @value=
165
+ # [#<YAML::Syck::Node:0x82ccd94
166
+ # @kind=:scalar,
167
+ # @type_id="str",
168
+ # @value="badger">,
169
+ # #<YAML::Syck::Node:0x82ccd58
170
+ # @kind=:scalar,
171
+ # @type_id="str",
172
+ # @value="elephant">,
173
+ # #<YAML::Syck::Node:0x82ccd1c
174
+ # @kind=:scalar,
175
+ # @type_id="str",
176
+ # @value="tiger">]>
177
+ #
178
+ # Can also load from a string.
179
+ #
180
+ # YAML.parse( "--- :locked" )
181
+ # #=> #<YAML::Syck::Node:0x82edddc
182
+ # @type_id="tag:ruby.yaml.org,2002:sym",
183
+ # @value=":locked", @kind=:scalar>
184
+ #
185
+ def self.parse( io )
186
+ generic_parser.load( io )
187
+ end
188
+
189
+ #
190
+ # Parse a document from the file located at _filepath_.
191
+ #
192
+ # YAML.parse_file( 'animals.yaml' )
193
+ # #=> #<YAML::Syck::Node:0x82ccce0
194
+ # @kind=:seq,
195
+ # @value=
196
+ # [#<YAML::Syck::Node:0x82ccd94
197
+ # @kind=:scalar,
198
+ # @type_id="str",
199
+ # @value="badger">,
200
+ # #<YAML::Syck::Node:0x82ccd58
201
+ # @kind=:scalar,
202
+ # @type_id="str",
203
+ # @value="elephant">,
204
+ # #<YAML::Syck::Node:0x82ccd1c
205
+ # @kind=:scalar,
206
+ # @type_id="str",
207
+ # @value="tiger">]>
208
+ #
209
+ def self.parse_file( filepath )
210
+ File.open( filepath ) do |f|
211
+ parse( f )
212
+ end
213
+ end
214
+
215
+ #
216
+ # Calls _block_ with each consecutive document in the YAML
217
+ # stream contained in _io_.
218
+ #
219
+ # File.open( 'many-docs.yaml' ) do |yf|
220
+ # YAML.each_document( yf ) do |ydoc|
221
+ # ## ydoc contains the single object
222
+ # ## from the YAML document
223
+ # end
224
+ # end
225
+ #
226
+ def self.each_document( io, &block )
227
+ warn "#{caller[0]}: YAML.each_document is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
228
+ parser.load_documents( io, &block )
229
+ end
230
+
231
+ #
232
+ # Calls _block_ with each consecutive document in the YAML
233
+ # stream contained in _io_.
234
+ #
235
+ # File.open( 'many-docs.yaml' ) do |yf|
236
+ # YAML.load_documents( yf ) do |ydoc|
237
+ # ## ydoc contains the single object
238
+ # ## from the YAML document
239
+ # end
240
+ # end
241
+ #
242
+ def self.load_documents( io, &doc_proc )
243
+ parser.load_documents( io, &doc_proc )
244
+ end
245
+
246
+ #
247
+ # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for
248
+ # each consecutive document in the YAML stream contained in _io_.
249
+ #
250
+ # File.open( 'many-docs.yaml' ) do |yf|
251
+ # YAML.each_node( yf ) do |ydoc|
252
+ # ## ydoc contains a tree of nodes
253
+ # ## from the YAML document
254
+ # end
255
+ # end
256
+ #
257
+ def self.each_node( io, &doc_proc )
258
+ warn "#{caller[0]}: YAML.each_node is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
259
+ generic_parser.load_documents( io, &doc_proc )
260
+ end
261
+
262
+ #
263
+ # Calls _block_ with a tree of +YAML::BaseNodes+, one tree for
264
+ # each consecutive document in the YAML stream contained in _io_.
265
+ #
266
+ # File.open( 'many-docs.yaml' ) do |yf|
267
+ # YAML.parse_documents( yf ) do |ydoc|
268
+ # ## ydoc contains a tree of nodes
269
+ # ## from the YAML document
270
+ # end
271
+ # end
272
+ #
273
+ def self.parse_documents( io, &doc_proc )
274
+ warn "#{caller[0]}: YAML.parse_documents is deprecated, use load_stream" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
275
+ self.each_node( io, &doc_proc )
276
+ end
277
+
278
+ #
279
+ # Loads all documents from the current _io_ stream,
280
+ # returning a +YAML::Stream+ object containing all
281
+ # loaded documents.
282
+ #
283
+ def self.load_stream( io )
284
+ d = nil
285
+ parser.load_documents( io ) do |doc|
286
+ d = Stream.new if not d
287
+ d.add( doc )
288
+ end
289
+ return d
290
+ end
291
+
292
+ #
293
+ # Returns a YAML stream containing each of the items in +objs+,
294
+ # each having their own document.
295
+ #
296
+ # YAML.dump_stream( 0, [], {} )
297
+ # #=> --- 0
298
+ # --- []
299
+ # --- {}
300
+ #
301
+ def self.dump_stream( *objs )
302
+ d = Stream.new
303
+ objs.each do |doc|
304
+ d.add( doc )
305
+ end
306
+ d.emit
307
+ end
308
+
309
+ #
310
+ # Add a global handler for a YAML domain type.
311
+ #
312
+ def self.add_domain_type( domain, type_tag, &transfer_proc )
313
+ resolver.add_type( "tag:#{ domain }:#{ type_tag }", transfer_proc )
314
+ end
315
+
316
+ #
317
+ # Add a transfer method for a builtin type
318
+ #
319
+ def self.add_builtin_type( type_tag, &transfer_proc )
320
+ resolver.add_type( "tag:yaml.org,2002:#{ type_tag }", transfer_proc )
321
+ end
322
+
323
+ #
324
+ # Add a transfer method for a builtin type
325
+ #
326
+ def self.add_ruby_type( type_tag, &transfer_proc )
327
+ warn "#{caller[0]}: YAML.add_ruby_type is deprecated, use add_domain_type" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
328
+ resolver.add_type( "tag:ruby.yaml.org,2002:#{ type_tag }", transfer_proc )
329
+ end
330
+
331
+ #
332
+ # Add a private document type
333
+ #
334
+ def self.add_private_type( type_re, &transfer_proc )
335
+ warn "#{caller[0]}: YAML.add_private_type is deprecated, use add_domain_type" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
336
+ resolver.add_type( "x-private:" + type_re, transfer_proc )
337
+ end
338
+
339
+ #
340
+ # Detect typing of a string
341
+ #
342
+ def self.detect_implicit( val )
343
+ warn "#{caller[0]}: YAML.detect_implicit is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
344
+ resolver.detect_implicit( val )
345
+ end
346
+
347
+ #
348
+ # Convert a type_id to a taguri
349
+ #
350
+ def self.tagurize( val )
351
+ warn "#{caller[0]}: YAML.tagurize is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
352
+ resolver.tagurize( val )
353
+ end
354
+
355
+ #
356
+ # Apply a transfer method to a Ruby object
357
+ #
358
+ def self.transfer( type_id, obj )
359
+ warn "#{caller[0]}: YAML.transfer is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
360
+ resolver.transfer( tagurize( type_id ), obj )
361
+ end
362
+
363
+ #
364
+ # Apply any implicit a node may qualify for
365
+ #
366
+ def self.try_implicit( obj )
367
+ warn "#{caller[0]}: YAML.try_implicit is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
368
+ transfer( detect_implicit( obj ), obj )
369
+ end
370
+
371
+ #
372
+ # Method to extract colon-seperated type and class, returning
373
+ # the type and the constant of the class
374
+ #
375
+ def self.read_type_class( type, obj_class )
376
+ warn "#{caller[0]}: YAML.read_type_class is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
377
+ type, tclass = type.split( ':', 4 ).last(2)
378
+ tclass.split( "::" ).each { |c| obj_class = obj_class.const_get( c ) } if tclass
379
+ return [ type, obj_class ]
380
+ end
381
+
382
+ #
383
+ # Allocate blank object
384
+ #
385
+ def self.object_maker( obj_class, val )
386
+ warn "#{caller[0]}: YAML.object_maker is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
387
+ if Hash === val
388
+ o = obj_class.allocate
389
+ val.each_pair { |k,v|
390
+ o.instance_variable_set("@#{k}", v)
391
+ }
392
+ o
393
+ else
394
+ raise Error, "Invalid object explicitly tagged !ruby/Object: " + val.inspect
395
+ end
396
+ end
397
+
398
+ #
399
+ # Allocate an Emitter if needed
400
+ #
401
+ def self.quick_emit( oid, opts = {}, &e )
402
+ warn "#{caller[0]}: YAML.quick_emit is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__))
403
+ out =
404
+ if opts.is_a? Emitter
405
+ opts
406
+ else
407
+ emitter.reset( opts )
408
+ end
409
+ out.emit( oid, &e )
410
+ end
411
+
412
+ #--
413
+ # For Rubinius, replaces the rb_iterate call to syck_set_ivars.
414
+ #++
415
+ def self.set_ivars(hsh, obj)
416
+ hsh.each do |key, value|
417
+ obj.instance_variable_set :"@#{key}", value
418
+ end
419
+ end
420
+
421
+ #--
422
+ # For Rubinius, replaces the rb_iterate call to syck_merge_i.
423
+ #++
424
+ def self.merge_i(ary, hsh)
425
+ ary.each do |entry|
426
+ begin
427
+ entry = Rubinius::Type.coerce_to entry, Hash, :to_hash
428
+ hsh.update entry
429
+ rescue
430
+ # ignore coercion errors
431
+ end
432
+ end
433
+
434
+ nil
435
+ end
436
+
437
+ #--
438
+ # For Rubinius, replaces rb_syck_mktime.
439
+ #++
440
+ def self.mktime(str)
441
+ require "date"
442
+ begin
443
+ DateTime.parse(str).to_time
444
+ rescue ArgumentError
445
+ # nothing
446
+ end
447
+ end
448
+ end
449
+
450
+ module Kernel
451
+ #
452
+ # ryan:: You know how Kernel.p is a really convenient way to dump ruby
453
+ # structures? The only downside is that it's not as legible as
454
+ # YAML.
455
+ #
456
+ # _why:: (listening)
457
+ #
458
+ # ryan:: I know you don't want to urinate all over your users' namespaces.
459
+ # But, on the other hand, convenience of dumping for debugging is,
460
+ # IMO, a big YAML use case.
461
+ #
462
+ # _why:: Go nuts! Have a pony parade!
463
+ #
464
+ # ryan:: Either way, I certainly will have a pony parade.
465
+ #
466
+
467
+ # Prints any supplied _objects_ out in YAML. Intended as
468
+ # a variation on +Kernel::p+.
469
+ #
470
+ # S = Struct.new(:name, :state)
471
+ # s = S['dave', 'TX']
472
+ # y s
473
+ #
474
+ # _produces:_
475
+ #
476
+ # --- !ruby/struct:S
477
+ # name: dave
478
+ # state: TX
479
+ #
480
+ def y( object, *objects )
481
+ objects.unshift object
482
+ puts( if objects.length == 1
483
+ YAML.dump( *objects )
484
+ else
485
+ YAML.dump_stream( *objects )
486
+ end )
487
+ end
488
+ private :y
489
+ end
490
+
491
+