1require 'psych.so' 2require 'psych/nodes' 3require 'psych/streaming' 4require 'psych/visitors' 5require 'psych/handler' 6require 'psych/tree_builder' 7require 'psych/parser' 8require 'psych/omap' 9require 'psych/set' 10require 'psych/coder' 11require 'psych/core_ext' 12require 'psych/deprecated' 13require 'psych/stream' 14require 'psych/json/tree_builder' 15require 'psych/json/stream' 16require 'psych/handlers/document_stream' 17 18### 19# = Overview 20# 21# Psych is a YAML parser and emitter. 22# Psych leverages libyaml [Home page: http://pyyaml.org/wiki/LibYAML] 23# or [Git repo: https://github.com/zerotao/libyaml] for its YAML parsing 24# and emitting capabilities. In addition to wrapping libyaml, Psych also 25# knows how to serialize and de-serialize most Ruby objects to and from 26# the YAML format. 27# 28# = I NEED TO PARSE OR EMIT YAML RIGHT NOW! 29# 30# # Parse some YAML 31# Psych.load("--- foo") # => "foo" 32# 33# # Emit some YAML 34# Psych.dump("foo") # => "--- foo\n...\n" 35# { :a => 'b'}.to_yaml # => "---\n:a: b\n" 36# 37# Got more time on your hands? Keep on reading! 38# 39# == YAML Parsing 40# 41# Psych provides a range of interfaces for parsing a YAML document ranging from 42# low level to high level, depending on your parsing needs. At the lowest 43# level, is an event based parser. Mid level is access to the raw YAML AST, 44# and at the highest level is the ability to unmarshal YAML to ruby objects. 45# 46# === Low level parsing 47# 48# The lowest level parser should be used when the YAML input is already known, 49# and the developer does not want to pay the price of building an AST or 50# automatic detection and conversion to ruby objects. See Psych::Parser for 51# more information on using the event based parser. 52# 53# === Mid level parsing 54# 55# Psych provides access to an AST produced from parsing a YAML document. This 56# tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can 57# be examined and manipulated freely. Please see Psych::parse_stream, 58# Psych::Nodes, and Psych::Nodes::Node for more information on dealing with 59# YAML syntax trees. 60# 61# === High level parsing 62# 63# The high level YAML parser provided by Psych simply takes YAML as input and 64# returns a Ruby data structure. For information on using the high level parser 65# see Psych.load 66# 67# == YAML Emitting 68# 69# Psych provides a range of interfaces ranging from low to high level for 70# producing YAML documents. Very similar to the YAML parsing interfaces, Psych 71# provides at the lowest level, an event based system, mid-level is building 72# a YAML AST, and the highest level is converting a Ruby object straight to 73# a YAML document. 74# 75# === Low level emitting 76# 77# The lowest level emitter is an event based system. Events are sent to a 78# Psych::Emitter object. That object knows how to convert the events to a YAML 79# document. This interface should be used when document format is known in 80# advance or speed is a concern. See Psych::Emitter for more information. 81# 82# === Mid level emitting 83# 84# At the mid level is building an AST. This AST is exactly the same as the AST 85# used when parsing a YAML document. Users can build an AST by hand and the 86# AST knows how to emit itself as a YAML document. See Psych::Nodes, 87# Psych::Nodes::Node, and Psych::TreeBuilder for more information on building 88# a YAML AST. 89# 90# === High level emitting 91# 92# The high level emitter has the easiest interface. Psych simply takes a Ruby 93# data structure and converts it to a YAML document. See Psych.dump for more 94# information on dumping a Ruby data structure. 95 96module Psych 97 # The version is Psych you're using 98 VERSION = '2.0.0' 99 100 # The version of libyaml Psych is using 101 LIBYAML_VERSION = Psych.libyaml_version.join '.' 102 103 class Exception < RuntimeError 104 end 105 106 class BadAlias < Exception 107 end 108 109 ### 110 # Load +yaml+ in to a Ruby data structure. If multiple documents are 111 # provided, the object contained in the first document will be returned. 112 # +filename+ will be used in the exception message if any exception is raised 113 # while parsing. 114 # 115 # Raises a Psych::SyntaxError when a YAML syntax error is detected. 116 # 117 # Example: 118 # 119 # Psych.load("--- a") # => 'a' 120 # Psych.load("---\n - a\n - b") # => ['a', 'b'] 121 # 122 # begin 123 # Psych.load("--- `", "file.txt") 124 # rescue Psych::SyntaxError => ex 125 # ex.file # => 'file.txt' 126 # ex.message # => "(file.txt): found character that cannot start any token" 127 # end 128 def self.load yaml, filename = nil 129 result = parse(yaml, filename) 130 result ? result.to_ruby : result 131 end 132 133 ### 134 # Parse a YAML string in +yaml+. Returns the first object of a YAML AST. 135 # +filename+ is used in the exception message if a Psych::SyntaxError is 136 # raised. 137 # 138 # Raises a Psych::SyntaxError when a YAML syntax error is detected. 139 # 140 # Example: 141 # 142 # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Sequence:0x00> 143 # 144 # begin 145 # Psych.parse("--- `", "file.txt") 146 # rescue Psych::SyntaxError => ex 147 # ex.file # => 'file.txt' 148 # ex.message # => "(file.txt): found character that cannot start any token" 149 # end 150 # 151 # See Psych::Nodes for more information about YAML AST. 152 def self.parse yaml, filename = nil 153 parse_stream(yaml, filename) do |node| 154 return node 155 end 156 false 157 end 158 159 ### 160 # Parse a file at +filename+. Returns the YAML AST. 161 # 162 # Raises a Psych::SyntaxError when a YAML syntax error is detected. 163 def self.parse_file filename 164 File.open filename, 'r:bom|utf-8' do |f| 165 parse f, filename 166 end 167 end 168 169 ### 170 # Returns a default parser 171 def self.parser 172 Psych::Parser.new(TreeBuilder.new) 173 end 174 175 ### 176 # Parse a YAML string in +yaml+. Returns the full AST for the YAML document. 177 # This method can handle multiple YAML documents contained in +yaml+. 178 # +filename+ is used in the exception message if a Psych::SyntaxError is 179 # raised. 180 # 181 # If a block is given, a Psych::Nodes::Document node will be yielded to the 182 # block as it's being parsed. 183 # 184 # Raises a Psych::SyntaxError when a YAML syntax error is detected. 185 # 186 # Example: 187 # 188 # Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00> 189 # 190 # Psych.parse_stream("--- a\n--- b") do |node| 191 # node # => #<Psych::Nodes::Document:0x00> 192 # end 193 # 194 # begin 195 # Psych.parse_stream("--- `", "file.txt") 196 # rescue Psych::SyntaxError => ex 197 # ex.file # => 'file.txt' 198 # ex.message # => "(file.txt): found character that cannot start any token" 199 # end 200 # 201 # See Psych::Nodes for more information about YAML AST. 202 def self.parse_stream yaml, filename = nil, &block 203 if block_given? 204 parser = Psych::Parser.new(Handlers::DocumentStream.new(&block)) 205 parser.parse yaml, filename 206 else 207 parser = self.parser 208 parser.parse yaml, filename 209 parser.handler.root 210 end 211 end 212 213 ### 214 # call-seq: 215 # Psych.dump(o) -> string of yaml 216 # Psych.dump(o, options) -> string of yaml 217 # Psych.dump(o, io) -> io object passed in 218 # Psych.dump(o, io, options) -> io object passed in 219 # 220 # Dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in 221 # to control the output format. If an IO object is passed in, the YAML will 222 # be dumped to that IO object. 223 # 224 # Example: 225 # 226 # # Dump an array, get back a YAML string 227 # Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" 228 # 229 # # Dump an array to an IO object 230 # Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> 231 # 232 # # Dump an array with indentation set 233 # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" 234 # 235 # # Dump an array to an IO with indentation set 236 # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3) 237 def self.dump o, io = nil, options = {} 238 if Hash === io 239 options = io 240 io = nil 241 end 242 243 visitor = Psych::Visitors::YAMLTree.new options 244 visitor << o 245 visitor.tree.yaml io, options 246 end 247 248 ### 249 # Dump a list of objects as separate documents to a document stream. 250 # 251 # Example: 252 # 253 # Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n" 254 def self.dump_stream *objects 255 visitor = Psych::Visitors::YAMLTree.new {} 256 objects.each do |o| 257 visitor << o 258 end 259 visitor.tree.yaml 260 end 261 262 ### 263 # Dump Ruby object +o+ to a JSON string. 264 def self.to_json o 265 visitor = Psych::Visitors::JSONTree.new 266 visitor << o 267 visitor.tree.yaml 268 end 269 270 ### 271 # Load multiple documents given in +yaml+. Returns the parsed documents 272 # as a list. If a block is given, each document will be converted to ruby 273 # and passed to the block during parsing 274 # 275 # Example: 276 # 277 # Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] 278 # 279 # list = [] 280 # Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby| 281 # list << ruby 282 # end 283 # list # => ['foo', 'bar'] 284 # 285 def self.load_stream yaml, filename = nil 286 if block_given? 287 parse_stream(yaml, filename) do |node| 288 yield node.to_ruby 289 end 290 else 291 parse_stream(yaml, filename).children.map { |child| child.to_ruby } 292 end 293 end 294 295 ### 296 # Load the document contained in +filename+. Returns the yaml contained in 297 # +filename+ as a ruby object 298 def self.load_file filename 299 File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename } 300 end 301 302 # :stopdoc: 303 @domain_types = {} 304 def self.add_domain_type domain, type_tag, &block 305 key = ['tag', domain, type_tag].join ':' 306 @domain_types[key] = [key, block] 307 @domain_types["tag:#{type_tag}"] = [key, block] 308 end 309 310 def self.add_builtin_type type_tag, &block 311 domain = 'yaml.org,2002' 312 key = ['tag', domain, type_tag].join ':' 313 @domain_types[key] = [key, block] 314 end 315 316 def self.remove_type type_tag 317 @domain_types.delete type_tag 318 end 319 320 @load_tags = {} 321 @dump_tags = {} 322 def self.add_tag tag, klass 323 @load_tags[tag] = klass 324 @dump_tags[klass] = tag 325 end 326 327 class << self 328 attr_accessor :load_tags 329 attr_accessor :dump_tags 330 attr_accessor :domain_types 331 end 332 # :startdoc: 333end 334