1 | # -*- mode: ruby; ruby-indent-level: 4; tab-width: 4 -*- vim: sw=4 ts=4
|
---|
2 | require 'date'
|
---|
3 |
|
---|
4 | class Class
|
---|
5 | def to_yaml( opts = {} )
|
---|
6 | raise TypeError, "can't dump anonymous class %s" % self.class
|
---|
7 | end
|
---|
8 | end
|
---|
9 |
|
---|
10 | class Object
|
---|
11 | yaml_as "tag:ruby.yaml.org,2002:object"
|
---|
12 | def to_yaml_style; end
|
---|
13 | def to_yaml_properties; instance_variables.sort; end
|
---|
14 | def to_yaml( opts = {} )
|
---|
15 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
16 | out.map( taguri, to_yaml_style ) do |map|
|
---|
17 | to_yaml_properties.each do |m|
|
---|
18 | map.add( m[1..-1], instance_variable_get( m ) )
|
---|
19 | end
|
---|
20 | end
|
---|
21 | end
|
---|
22 | end
|
---|
23 | end
|
---|
24 |
|
---|
25 | class Hash
|
---|
26 | yaml_as "tag:ruby.yaml.org,2002:hash"
|
---|
27 | yaml_as "tag:yaml.org,2002:map"
|
---|
28 | def yaml_initialize( tag, val )
|
---|
29 | if Array === val
|
---|
30 | update Hash.[]( *val ) # Convert the map to a sequence
|
---|
31 | elsif Hash === val
|
---|
32 | update val
|
---|
33 | else
|
---|
34 | raise YAML::TypeError, "Invalid map explicitly tagged #{ tag }: " + val.inspect
|
---|
35 | end
|
---|
36 | end
|
---|
37 | def to_yaml( opts = {} )
|
---|
38 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
39 | out.map( taguri, to_yaml_style ) do |map|
|
---|
40 | each do |k, v|
|
---|
41 | map.add( k, v )
|
---|
42 | end
|
---|
43 | end
|
---|
44 | end
|
---|
45 | end
|
---|
46 | end
|
---|
47 |
|
---|
48 | class Struct
|
---|
49 | yaml_as "tag:ruby.yaml.org,2002:struct"
|
---|
50 | def self.yaml_tag_class_name; self.name.gsub( "Struct::", "" ); end
|
---|
51 | def self.yaml_tag_read_class( name ); "Struct::#{ name }"; end
|
---|
52 | def self.yaml_new( klass, tag, val )
|
---|
53 | if Hash === val
|
---|
54 | struct_type = nil
|
---|
55 |
|
---|
56 | #
|
---|
57 | # Use existing Struct if it exists
|
---|
58 | #
|
---|
59 | props = {}
|
---|
60 | val.delete_if { |k,v| props[k] = v if k =~ /^@/ }
|
---|
61 | begin
|
---|
62 | struct_name, struct_type = YAML.read_type_class( tag, Struct )
|
---|
63 | rescue NameError
|
---|
64 | end
|
---|
65 | if not struct_type
|
---|
66 | struct_def = [ tag.split( ':', 4 ).last ]
|
---|
67 | struct_type = Struct.new( *struct_def.concat( val.keys.collect { |k| k.intern } ) )
|
---|
68 | end
|
---|
69 |
|
---|
70 | #
|
---|
71 | # Set the Struct properties
|
---|
72 | #
|
---|
73 | st = YAML::object_maker( struct_type, {} )
|
---|
74 | st.members.each do |m|
|
---|
75 | st.send( "#{m}=", val[m] )
|
---|
76 | end
|
---|
77 | props.each do |k,v|
|
---|
78 | st.instance_variable_set(k, v)
|
---|
79 | end
|
---|
80 | st
|
---|
81 | else
|
---|
82 | raise YAML::TypeError, "Invalid Ruby Struct: " + val.inspect
|
---|
83 | end
|
---|
84 | end
|
---|
85 | def to_yaml( opts = {} )
|
---|
86 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
87 | #
|
---|
88 | # Basic struct is passed as a YAML map
|
---|
89 | #
|
---|
90 | out.map( taguri, to_yaml_style ) do |map|
|
---|
91 | self.members.each do |m|
|
---|
92 | map.add( m, self[m] )
|
---|
93 | end
|
---|
94 | self.to_yaml_properties.each do |m|
|
---|
95 | map.add( m, instance_variable_get( m ) )
|
---|
96 | end
|
---|
97 | end
|
---|
98 | end
|
---|
99 | end
|
---|
100 | end
|
---|
101 |
|
---|
102 | class Array
|
---|
103 | yaml_as "tag:ruby.yaml.org,2002:array"
|
---|
104 | yaml_as "tag:yaml.org,2002:seq"
|
---|
105 | def yaml_initialize( tag, val ); concat( val.to_a ); end
|
---|
106 | def to_yaml( opts = {} )
|
---|
107 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
108 | out.seq( taguri, to_yaml_style ) do |seq|
|
---|
109 | each do |x|
|
---|
110 | seq.add( x )
|
---|
111 | end
|
---|
112 | end
|
---|
113 | end
|
---|
114 | end
|
---|
115 | end
|
---|
116 |
|
---|
117 | class Exception
|
---|
118 | yaml_as "tag:ruby.yaml.org,2002:exception"
|
---|
119 | def Exception.yaml_new( klass, tag, val )
|
---|
120 | o = YAML.object_maker( klass, { 'mesg' => val.delete( 'message' ) } )
|
---|
121 | val.each_pair do |k,v|
|
---|
122 | o.instance_variable_set("@#{k}", v)
|
---|
123 | end
|
---|
124 | o
|
---|
125 | end
|
---|
126 | def to_yaml( opts = {} )
|
---|
127 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
128 | out.map( taguri, to_yaml_style ) do |map|
|
---|
129 | map.add( 'message', message )
|
---|
130 | to_yaml_properties.each do |m|
|
---|
131 | map.add( m[1..-1], instance_variable_get( m ) )
|
---|
132 | end
|
---|
133 | end
|
---|
134 | end
|
---|
135 | end
|
---|
136 | end
|
---|
137 |
|
---|
138 | class String
|
---|
139 | yaml_as "tag:ruby.yaml.org,2002:string"
|
---|
140 | yaml_as "tag:yaml.org,2002:binary"
|
---|
141 | yaml_as "tag:yaml.org,2002:str"
|
---|
142 | def is_complex_yaml?
|
---|
143 | to_yaml_style or not to_yaml_properties.empty? or self =~ /\n.+/
|
---|
144 | end
|
---|
145 | def is_binary_data?
|
---|
146 | ( self.count( "^ -~", "^\r\n" ) / self.size > 0.3 || self.count( "\x00" ) > 0 ) unless empty?
|
---|
147 | end
|
---|
148 | def String.yaml_new( klass, tag, val )
|
---|
149 | val = val.unpack("m")[0] if tag == "tag:yaml.org,2002:binary"
|
---|
150 | val = { 'str' => val } if String === val
|
---|
151 | if Hash === val
|
---|
152 | s = klass.allocate
|
---|
153 | # Thank you, NaHi
|
---|
154 | String.instance_method(:initialize).
|
---|
155 | bind(s).
|
---|
156 | call( val.delete( 'str' ) )
|
---|
157 | val.each { |k,v| s.instance_variable_set( k, v ) }
|
---|
158 | s
|
---|
159 | else
|
---|
160 | raise YAML::TypeError, "Invalid String: " + val.inspect
|
---|
161 | end
|
---|
162 | end
|
---|
163 | def to_yaml( opts = {} )
|
---|
164 | YAML::quick_emit( is_complex_yaml? ? object_id : nil, opts ) do |out|
|
---|
165 | if is_binary_data?
|
---|
166 | out.scalar( "tag:yaml.org,2002:binary", [self].pack("m"), :literal )
|
---|
167 | elsif to_yaml_properties.empty?
|
---|
168 | out.scalar( taguri, self, self =~ /^:/ ? :quote2 : to_yaml_style )
|
---|
169 | else
|
---|
170 | out.map( taguri, to_yaml_style ) do |map|
|
---|
171 | map.add( 'str', "#{self}" )
|
---|
172 | to_yaml_properties.each do |m|
|
---|
173 | map.add( m, instance_variable_get( m ) )
|
---|
174 | end
|
---|
175 | end
|
---|
176 | end
|
---|
177 | end
|
---|
178 | end
|
---|
179 | end
|
---|
180 |
|
---|
181 | class Symbol
|
---|
182 | yaml_as "tag:ruby.yaml.org,2002:symbol"
|
---|
183 | yaml_as "tag:ruby.yaml.org,2002:sym"
|
---|
184 | def Symbol.yaml_new( klass, tag, val )
|
---|
185 | if String === val
|
---|
186 | val = YAML::load( val ) if val =~ /\A(["']).*\1\z/
|
---|
187 | val.intern
|
---|
188 | else
|
---|
189 | raise YAML::TypeError, "Invalid Symbol: " + val.inspect
|
---|
190 | end
|
---|
191 | end
|
---|
192 | def to_yaml( opts = {} )
|
---|
193 | YAML::quick_emit( nil, opts ) do |out|
|
---|
194 | out.scalar( "tag:yaml.org,2002:str", self.inspect, :plain )
|
---|
195 | end
|
---|
196 | end
|
---|
197 | end
|
---|
198 |
|
---|
199 | class Range
|
---|
200 | yaml_as "tag:ruby.yaml.org,2002:range"
|
---|
201 | def Range.yaml_new( klass, tag, val )
|
---|
202 | inr = %r'(\w+|[+-]?\d+(?:\.\d+)?(?:e[+-]\d+)?|"(?:[^\\"]|\\.)*")'
|
---|
203 | opts = {}
|
---|
204 | if String === val and val =~ /^#{inr}(\.{2,3})#{inr}$/o
|
---|
205 | r1, rdots, r2 = $1, $2, $3
|
---|
206 | opts = {
|
---|
207 | 'begin' => YAML.load( "--- #{r1}" ),
|
---|
208 | 'end' => YAML.load( "--- #{r2}" ),
|
---|
209 | 'excl' => rdots.length == 3
|
---|
210 | }
|
---|
211 | val = {}
|
---|
212 | elsif Hash === val
|
---|
213 | opts['begin'] = val.delete('begin')
|
---|
214 | opts['end'] = val.delete('end')
|
---|
215 | opts['excl'] = val.delete('excl')
|
---|
216 | end
|
---|
217 | if Hash === opts
|
---|
218 | r = YAML::object_maker( klass, {} )
|
---|
219 | # Thank you, NaHi
|
---|
220 | Range.instance_method(:initialize).
|
---|
221 | bind(r).
|
---|
222 | call( opts['begin'], opts['end'], opts['excl'] )
|
---|
223 | val.each { |k,v| r.instance_variable_set( k, v ) }
|
---|
224 | r
|
---|
225 | else
|
---|
226 | raise YAML::TypeError, "Invalid Range: " + val.inspect
|
---|
227 | end
|
---|
228 | end
|
---|
229 | def to_yaml( opts = {} )
|
---|
230 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
231 | # if self.begin.is_complex_yaml? or self.begin.respond_to? :to_str or
|
---|
232 | # self.end.is_complex_yaml? or self.end.respond_to? :to_str or
|
---|
233 | # not to_yaml_properties.empty?
|
---|
234 | out.map( taguri, to_yaml_style ) do |map|
|
---|
235 | map.add( 'begin', self.begin )
|
---|
236 | map.add( 'end', self.end )
|
---|
237 | map.add( 'excl', self.exclude_end? )
|
---|
238 | to_yaml_properties.each do |m|
|
---|
239 | map.add( m, instance_variable_get( m ) )
|
---|
240 | end
|
---|
241 | end
|
---|
242 | # else
|
---|
243 | # out.scalar( taguri ) do |sc|
|
---|
244 | # sc.embed( self.begin )
|
---|
245 | # sc.concat( self.exclude_end? ? "..." : ".." )
|
---|
246 | # sc.embed( self.end )
|
---|
247 | # end
|
---|
248 | # end
|
---|
249 | end
|
---|
250 | end
|
---|
251 | end
|
---|
252 |
|
---|
253 | class Regexp
|
---|
254 | yaml_as "tag:ruby.yaml.org,2002:regexp"
|
---|
255 | def Regexp.yaml_new( klass, tag, val )
|
---|
256 | if String === val and val =~ /^\/(.*)\/([mix]*)$/
|
---|
257 | val = { 'regexp' => $1, 'mods' => $2 }
|
---|
258 | end
|
---|
259 | if Hash === val
|
---|
260 | mods = nil
|
---|
261 | unless val['mods'].to_s.empty?
|
---|
262 | mods = 0x00
|
---|
263 | mods |= Regexp::EXTENDED if val['mods'].include?( 'x' )
|
---|
264 | mods |= Regexp::IGNORECASE if val['mods'].include?( 'i' )
|
---|
265 | mods |= Regexp::MULTILINE if val['mods'].include?( 'm' )
|
---|
266 | end
|
---|
267 | val.delete( 'mods' )
|
---|
268 | r = YAML::object_maker( klass, {} )
|
---|
269 | Regexp.instance_method(:initialize).
|
---|
270 | bind(r).
|
---|
271 | call( val.delete( 'regexp' ), mods )
|
---|
272 | val.each { |k,v| r.instance_variable_set( k, v ) }
|
---|
273 | r
|
---|
274 | else
|
---|
275 | raise YAML::TypeError, "Invalid Regular expression: " + val.inspect
|
---|
276 | end
|
---|
277 | end
|
---|
278 | def to_yaml( opts = {} )
|
---|
279 | YAML::quick_emit( nil, opts ) do |out|
|
---|
280 | if to_yaml_properties.empty?
|
---|
281 | out.scalar( taguri, self.inspect, :plain )
|
---|
282 | else
|
---|
283 | out.map( taguri, to_yaml_style ) do |map|
|
---|
284 | src = self.inspect
|
---|
285 | if src =~ /\A\/(.*)\/([a-z]*)\Z/
|
---|
286 | map.add( 'regexp', $1 )
|
---|
287 | map.add( 'mods', $2 )
|
---|
288 | else
|
---|
289 | raise YAML::TypeError, "Invalid Regular expression: " + src
|
---|
290 | end
|
---|
291 | to_yaml_properties.each do |m|
|
---|
292 | map.add( m, instance_variable_get( m ) )
|
---|
293 | end
|
---|
294 | end
|
---|
295 | end
|
---|
296 | end
|
---|
297 | end
|
---|
298 | end
|
---|
299 |
|
---|
300 | class Time
|
---|
301 | yaml_as "tag:ruby.yaml.org,2002:time"
|
---|
302 | yaml_as "tag:yaml.org,2002:timestamp"
|
---|
303 | def Time.yaml_new( klass, tag, val )
|
---|
304 | if Hash === val
|
---|
305 | t = val.delete( 'at' )
|
---|
306 | val.each { |k,v| t.instance_variable_set( k, v ) }
|
---|
307 | t
|
---|
308 | else
|
---|
309 | raise YAML::TypeError, "Invalid Time: " + val.inspect
|
---|
310 | end
|
---|
311 | end
|
---|
312 | def to_yaml( opts = {} )
|
---|
313 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
314 | tz = "Z"
|
---|
315 | # from the tidy Tobias Peters <[email protected]> Thanks!
|
---|
316 | unless self.utc?
|
---|
317 | utc_same_instant = self.dup.utc
|
---|
318 | utc_same_writing = Time.utc(year,month,day,hour,min,sec,usec)
|
---|
319 | difference_to_utc = utc_same_writing - utc_same_instant
|
---|
320 | if (difference_to_utc < 0)
|
---|
321 | difference_sign = '-'
|
---|
322 | absolute_difference = -difference_to_utc
|
---|
323 | else
|
---|
324 | difference_sign = '+'
|
---|
325 | absolute_difference = difference_to_utc
|
---|
326 | end
|
---|
327 | difference_minutes = (absolute_difference/60).round
|
---|
328 | tz = "%s%02d:%02d" % [ difference_sign, difference_minutes / 60, difference_minutes % 60]
|
---|
329 | end
|
---|
330 | standard = self.strftime( "%Y-%m-%d %H:%M:%S" )
|
---|
331 | standard += ".%06d" % [usec] if usec.nonzero?
|
---|
332 | standard += " %s" % [tz]
|
---|
333 | if to_yaml_properties.empty?
|
---|
334 | out.scalar( taguri, standard, :plain )
|
---|
335 | else
|
---|
336 | out.map( taguri, to_yaml_style ) do |map|
|
---|
337 | map.add( 'at', standard )
|
---|
338 | to_yaml_properties.each do |m|
|
---|
339 | map.add( m, instance_variable_get( m ) )
|
---|
340 | end
|
---|
341 | end
|
---|
342 | end
|
---|
343 | end
|
---|
344 | end
|
---|
345 | end
|
---|
346 |
|
---|
347 | class Date
|
---|
348 | yaml_as "tag:yaml.org,2002:timestamp#ymd"
|
---|
349 | def to_yaml( opts = {} )
|
---|
350 | YAML::quick_emit( object_id, opts ) do |out|
|
---|
351 | out.scalar( "tag:yaml.org,2002:timestamp", self.to_s, :plain )
|
---|
352 | end
|
---|
353 | end
|
---|
354 | end
|
---|
355 |
|
---|
356 | class Integer
|
---|
357 | yaml_as "tag:yaml.org,2002:int"
|
---|
358 | def to_yaml( opts = {} )
|
---|
359 | YAML::quick_emit( nil, opts ) do |out|
|
---|
360 | out.scalar( "tag:yaml.org,2002:int", self.to_s, :plain )
|
---|
361 | end
|
---|
362 | end
|
---|
363 | end
|
---|
364 |
|
---|
365 | class Float
|
---|
366 | yaml_as "tag:yaml.org,2002:float"
|
---|
367 | def to_yaml( opts = {} )
|
---|
368 | YAML::quick_emit( nil, opts ) do |out|
|
---|
369 | str = self.to_s
|
---|
370 | if str == "Infinity"
|
---|
371 | str = ".Inf"
|
---|
372 | elsif str == "-Infinity"
|
---|
373 | str = "-.Inf"
|
---|
374 | elsif str == "NaN"
|
---|
375 | str = ".NaN"
|
---|
376 | end
|
---|
377 | out.scalar( "tag:yaml.org,2002:float", str, :plain )
|
---|
378 | end
|
---|
379 | end
|
---|
380 | end
|
---|
381 |
|
---|
382 | class TrueClass
|
---|
383 | yaml_as "tag:yaml.org,2002:bool#yes"
|
---|
384 | def to_yaml( opts = {} )
|
---|
385 | YAML::quick_emit( nil, opts ) do |out|
|
---|
386 | out.scalar( taguri, "true", :plain )
|
---|
387 | end
|
---|
388 | end
|
---|
389 | end
|
---|
390 |
|
---|
391 | class FalseClass
|
---|
392 | yaml_as "tag:yaml.org,2002:bool#no"
|
---|
393 | def to_yaml( opts = {} )
|
---|
394 | YAML::quick_emit( nil, opts ) do |out|
|
---|
395 | out.scalar( taguri, "false", :plain )
|
---|
396 | end
|
---|
397 | end
|
---|
398 | end
|
---|
399 |
|
---|
400 | class NilClass
|
---|
401 | yaml_as "tag:yaml.org,2002:null"
|
---|
402 | def to_yaml( opts = {} )
|
---|
403 | YAML::quick_emit( nil, opts ) do |out|
|
---|
404 | out.scalar( taguri, "", :plain )
|
---|
405 | end
|
---|
406 | end
|
---|
407 | end
|
---|
408 |
|
---|