Ruby 2.4

Psych

module Psych

概观

Psych 是一个 YAML 解析器和发射器。由于其 YAML 解析和发射功能,Psych 可以利用 libyaml [主页:pyyaml.org/wiki/LibYAML ]或[HG repo:bitbucket.org/xi/libyaml ]。除了包装 libyaml 外,Psych 还知道如何序列化和反序列化大多数 Ruby 对象与 YAML 格式的序列化和反序列化。

I NEED TO PARSE OR EMIT YAML RIGHT NOW!

# Parse some YAML Psych.load("--- foo") # => "foo" # Emit some YAML Psych.dump("foo") # => "--- foo\n...\n" { :a => 'b'}.to_yaml # => "---\n:a: b\n"

你的手上有更多的时间?继续阅读!

YAML Parsing

Psych 提供了一系列接口,用于解析从低级到高级的 YAML 文档,具体取决于您的解析需求。在最底层,是基于事件的解析器。中级可访问原始 YAML AST,最高级别是将 YAML 解组到 Ruby 对象的能力。

YAML Emitting

Psych 提供一系列接口,从低到高生成 YAML 文档。与 YAML 解析接口非常相似,Psych 在最低级别提供基于事件的系统,中级正在构建 YAML AST,最高级别将 Ruby 对象直接转换为 YAML 文档。

高级 API

解析

由 Psych 提供的高级 YAML 解析器只需将 YAML 作为输入并返回一个 Ruby 数据结构。有关使用高级解析器 see :: load 的信息

从字符串中读取

Psych.load("--- a") # => 'a' Psych.load("---\n - a\n - b") # => ['a', 'b']

从文件中读取

Psych.load_file("database.yml")

handling

begin # The second argument changes only the exception contents Psych.parse("--- `", "file.txt") rescue Psych::SyntaxError => ex ex.file # => 'file.txt' ex.message # => "(file.txt): found character that cannot start any token" end

Emitting

高级别发射器具有最简单的接口。Psych 只需要一个 Ruby 数据结构并将其转换为 YAML 文档。有关转储 Ruby 数据结构的更多信息,请参阅:转储。

写入字符串

# Dump an array, get back a YAML string Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" # Dump an array to an IO object Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> # Dump an array with indentation set Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" # Dump an array to an IO with indentation set Psych.dump(['a', ['b']], StringIO.new, :indentation => 3)

写入文件

目前没有用于将 Ruby 结构转储到文件的直接 API:

File.open('database.yml', 'w') do |file| file.write(Psych.dump(['a', 'b'])) end

中级 API

Parsing

Psych 提供对解析 YAML 文档产生的 AST 的访问。这棵树是使用 Psych :: Parser 和 Psych :: TreeBuilder 构建的。AST 可以自由检查和操纵。有关处理 YAML 语法树的更多信息,请参阅 :: parse_stream,Psych :: Nodes 和 Psych :: Nodes :: Node。

从字符串中读取

# Returns Psych::Nodes::Stream Psych.parse_stream("---\n - a\n - b") # Returns Psych::Nodes::Document Psych.parse("---\n - a\n - b")

从文件中读取

# Returns Psych::Nodes::Stream Psych.parse_stream(File.read('database.yml')) # Returns Psych::Nodes::Document Psych.parse_file('database.yml')

handling

begin # The second argument changes only the exception contents Psych.parse("--- `", "file.txt") rescue Psych::SyntaxError => ex ex.file # => 'file.txt' ex.message # => "(file.txt): found character that cannot start any token" end

Emitting

在中层建立一个 AST。这个 AST 与解析 YAML 文档时使用的 AST 完全相同。用户可以手动构建 AST,AST 知道如何将自己作为YAML文档发布。有关构建 YAML AST 的更多信息,请参阅 Psych :: Nodes,Psych :: Nodes :: Node 和 Psych :: TreeBuilder。

写入字符串

# We need Psych::Nodes::Stream (not Psych::Nodes::Document) stream = Psych.parse_stream("---\n - a\n - b") stream.to_yaml # => "---\n- a\n- b\n"

写入文件

# We need Psych::Nodes::Stream (not Psych::Nodes::Document) stream = Psych.parse_stream(File.read('database.yml')) File.open('database.yml', 'w') do |file| file.write(stream.to_yaml) end

低级 API

解析

当 YAML 输入已知时,应使用最低级别的解析器,开发人员不希望支付构建 AST 或自动检测和转换为 Ruby 对象的价格。有关使用基于事件的解析器的更多信息,请参阅 Psych :: Parser。

阅读结构

parser = Psych::Parser.new(TreeBuilder.new) # => #<Psych::Parser> parser = Psych.parser # it's an alias for the above parser.parse("---\n - a\n - b") # => #<Psych::Parser> parser.handler # => #<Psych::TreeBuilder> parser.handler.root # => #<Psych::Nodes::Stream>

接收事件流

parser = Psych::Parser.new(Psych::Handlers::Recorder.new) parser.parse("---\n - a\n - b") parser.events # => [list of [event, args] lists] # event is one of: Psych::Handler::EVENTS # args are the arguments passed to the event

Emitting

最低级别的发射器是基于事件的系统。事件被发送到 Psych :: Emitter 对象。该对象知道如何将事件转换为 YAML 文档。当提前知道文档格式或速度问题时,应使用此界面。有关更多信息,请参阅 Psych :: Emitter。

写入 Ruby 结构

Psych.parser.parse("--- a") # => #<Psych::Parser> parser.handler.first # => #<Psych::Nodes::Stream> parser.handler.first.to_ruby # => ["a"] parser.handler.root.first # => #<Psych::Nodes::Document> parser.handler.root.first.to_ruby # => "a" # You can instantiate an Emitter manually Psych::Visitors::ToRuby.new.accept(parser.handler.root.first) # => "a"

常量

DEFAULT_SNAKEYAML_VERSION LIBYAML_VERSION

libyaml Psych 的版本正在使用

VERSION

该版本是您正在使用的 Psych

公共类方法

add_private_type(type_tag, &block) Show source

# File ext/psych/lib/psych/deprecated.rb, line 49 def self.add_private_type type_tag, &block warn "#{caller[0]}: add_private_type is deprecated, use add_domain_type" if $VERBOSE domain = 'x-private' key = [domain, type_tag].join ':' @domain_types[key] = [key, block] end

add_ruby_type(type_tag, &block) Show source

# File ext/psych/lib/psych/deprecated.rb, line 42 def self.add_ruby_type type_tag, &block warn "#{caller[0]}: add_ruby_type is deprecated, use add_domain_type" if $VERBOSE domain = 'ruby.yaml.org,2002' key = ['tag', domain, type_tag].join ':' @domain_types[key] = [key, block] end

detect_implicit(thing) Show source

# File ext/psych/lib/psych/deprecated.rb, line 34 def self.detect_implicit thing warn "#{caller[0]}: detect_implicit is deprecated" if $VERBOSE return '' unless String === thing return 'null' if '' == thing ss = ScalarScanner.new(ClassLoader.new) ss.tokenize(thing).class.name.downcase end

dump(o) → string of yaml Show source

dump(o, options) → string of yaml

dump(o, io) → io object passed in

dump(o, io, options) → io object passed in

将 Ruby 对象转储o到 YAML 字符串。options可以传入选项来控制输出格式。如果 IO 对象被传入,YAML 将被转储到 IO 对象。

例:

# Dump an array, get back a YAML string Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" # Dump an array to an IO object Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> # Dump an array with indentation set Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" # Dump an array to an IO with indentation set Psych.dump(['a', ['b']], StringIO.new, :indentation => 3)

# File ext/psych/lib/psych.rb, line 408 def self.dump o, io = nil, options = {} if Hash === io options = io io = nil end visitor = Psych::Visitors::YAMLTree.create options visitor << o visitor.tree.yaml io, options end

dump_stream(*objects) Show source

将对象列表作为单独的文档转储到文档流中。

例:

Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n"

# File ext/psych/lib/psych.rb, line 425 def self.dump_stream *objects visitor = Psych::Visitors::YAMLTree.create{}) objects.each do |o| visitor << o end visitor.tree.yaml end

libyaml_version Show source

返回正在使用的 libyaml 的版本

static VALUE libyaml_version(VALUE module) { int major, minor, patch; VALUE list[3]; yaml_get_version(&major, &minor, &patch list[0] = INT2NUM((long)major list[1] = INT2NUM((long)minor list[2] = INT2NUM((long)patch return rb_ary_new4((long)3, list }

load(yaml, filename = nil, fallback = false) Show source

加载yaml到 Ruby 数据结构。如果提供了多个文档,则将返回第一个文档中包含的对象。filename将在异常消息中使用,如果在解析时引发任何异常。

当检测到 YAML 语法错误时引发 Psych :: SyntaxError。

例:

Psych.load("--- a") # => 'a' Psych.load("---\n - a\n - b") # => ['a', 'b'] begin Psych.load("--- `", "file.txt") rescue Psych::SyntaxError => ex ex.file # => 'file.txt' ex.message # => "(file.txt): found character that cannot start any token" end

# File ext/psych/lib/psych.rb, line 250 def self.load yaml, filename = nil, fallback = false result = parse(yaml, filename, fallback) result ? result.to_ruby : result end

load_documents(yaml, &block) Show source

此方法不推荐使用,而是使用 :: load_stream。

# File ext/psych/lib/psych/deprecated.rb, line 25 def self.load_documents yaml, &block if $VERBOSE warn "#{caller[0]}: load_documents is deprecated, use load_stream" end list = load_stream yaml return list unless block_given? list.each(&block) end

load_file(filename, fallback = false) Show source

加载包含的文档filename。返回filename作为 Ruby 对象包含的 yaml ,或者如果该文件为空,则返回指定的默认返回值,默认返回值默认为空 Hash

# File ext/psych/lib/psych.rb, line 470 def self.load_file filename, fallback = false File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename, FALLBACK.new(fallback) } end

load_stream(yaml, filename = nil) { |to_ruby| ... } Show source

载入多个文件yaml。以列表形式返回解析的文档。如果给出了一个块,每个文档都将被转换为 Ruby,并在解析过程中传递给块

例:

Psych.load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] list = [] Psych.load_stream("--- foo\n...\n--- bar\n...") do |ruby| list << ruby end list # => ['foo', 'bar']

# File ext/psych/lib/psych.rb, line 456 def self.load_stream yaml, filename = nil if block_given? parse_stream(yaml, filename) do |node| yield node.to_ruby end else parse_stream(yaml, filename).children.map { |child| child.to_ruby } end end

object_maker(klass, hash) Show source

# File ext/psych/lib/psych/deprecated.rb, line 72 def self.object_maker klass, hash warn "#{caller[0]}: object_maker is deprecated" if $VERBOSE klass.allocate.tap do |obj| hash.each { |k,v| obj.instance_variable_set(:"@#{k}", v) } end end

parse(yaml, filename = nil, fallback = false) Show source

解析一个 YAML 字符串yaml。返回 Psych :: Nodes :: Document。filename在引发一个 Psych :: SyntaxError 异常的消息中使用。

当检测到 YAML 语法错误时引发 Psych :: SyntaxError。

例:

Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00> begin Psych.parse("--- `", "file.txt") rescue Psych::SyntaxError => ex ex.file # => 'file.txt' ex.message # => "(file.txt): found character that cannot start any token" end

有关 YAML AST 的更多信息,请参阅 Psych :: Nodes。

# File ext/psych/lib/psych.rb, line 323 def self.parse yaml, filename = nil, fallback = false parse_stream(yaml, filename) do |node| return node end fallback end

parse_file(filename) Show source

解析文件filename。返回 Psych :: Nodes :: Document。

当检测到 YAML 语法错误时引发 Psych :: SyntaxError。

# File ext/psych/lib/psych.rb, line 334 def self.parse_file filename File.open filename, 'r:bom|utf-8' do |f| parse f, filename end end

parse_stream(yaml, filename = nil, &block) Show source

解析一个 YAML 字符串yaml。返回P sych :: Nodes :: Stream。这个方法可以处理包含在其中的多个YAML文档yamlfilename在引发一个 Psych :: SyntaxError 异常的消息中使用。

如果给出了一个块,一个 Psych :: Nodes :: Document 节点将被解析到块中。

当检测到 YAML 语法错误时引发 Psych :: SyntaxError。

例:

Psych.parse_stream("---\n - a\n - b") # => #<Psych::Nodes::Stream:0x00> Psych.parse_stream("--- a\n--- b") do |node| node # => #<Psych::Nodes::Document:0x00> end begin Psych.parse_stream("--- `", "file.txt") rescue Psych::SyntaxError => ex ex.file # => 'file.txt' ex.message # => "(file.txt): found character that cannot start any token" end

有关 YAML AST 的更多信息,请参阅 Psych :: Nodes。

# File ext/psych/lib/psych.rb, line 373 def self.parse_stream yaml, filename = nil, &block if block_given? parser = Psych::Parser.new(Handlers::DocumentStream.new(&block)) parser.parse yaml, filename else parser = self.parser parser.parse yaml, filename parser.handler.root end end

parser() Show source

返回一个默认的解析器

# File ext/psych/lib/psych.rb, line 342 def self.parser Psych::Parser.new(TreeBuilder.new) end

read_type_class(type, reference) Show source

# File ext/psych/lib/psych/deprecated.rb, line 62 def self.read_type_class type, reference warn "#{caller[0]}: read_type_class is deprecated" if $VERBOSE _, _, type, name = type.split ':', 4 reference = name.split('::').inject(reference) do |k,n| k.const_get(n.to_sym) end if name [type, reference] end

safe_load(yaml, whitelist_classes = [], whitelist_symbols = [], aliases = false, filename = nil) Show source

安全地加载 yaml 字符串yaml。默认情况下,只允许以下类被反序列化:

  • TrueClass

  • FalseClass

  • NilClass

  • Numeric

  • String

  • Array

  • Hash

递归数据结构默认是不允许的。可以通过向这些类添加这些类来允许任意类whitelist。它们是添加剂。例如,要允许日期反序列化:

Psych.safe_load(yaml, [Date])

除了上面列出的类之外,现在还可以加载 Date 类。

别名可以通过更改aliases参数明确允许。例如:

x = [] x << x yaml = Psych.dump x Psych.safe_load yaml # => raises an exception Psych.safe_load yaml, [], [], true # => loads the aliases

如果 yaml 包含不在白名单中的类,则会引发 Psych :: DisallowedClass 异常。

如果 yaml 包含别名,但aliases参数设置为 false,则会引发 Psych :: BadAlias 异常。

# File ext/psych/lib/psych.rb, line 289 def self.safe_load yaml, whitelist_classes = [], whitelist_symbols = [], aliases = false, filename = nil result = parse(yaml, filename) return unless result class_loader = ClassLoader::Restricted.new(whitelist_classes.map(&:to_s), whitelist_symbols.map(&:to_s)) scanner = ScalarScanner.new class_loader if aliases visitor = Visitors::ToRuby.new scanner, class_loader else visitor = Visitors::NoAliasRuby.new scanner, class_loader end visitor.accept result end

tagurize(thing) Show source

# File ext/psych/lib/psych/deprecated.rb, line 56 def self.tagurize thing warn "#{caller[0]}: add_private_type is deprecated, use add_domain_type" if $VERBOSE return thing unless String === thing "tag:yaml.org,2002:#{thing}" end

to_json(object) Show source

将 Ruby 转储object为 JSON 字符串。

# File ext/psych/lib/psych.rb, line 435 def self.to_json object visitor = Psych::Visitors::JSONTree.create visitor << object visitor.tree.yaml end