PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/18/yaml/rubytypes.rb

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