rubysl-yaml 2.0.0 → 2.0.2

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/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
+