module Psych
概览
Psych 是一个 YAML 解析器和生成器。 Psych 利用 libyaml [主页:pyyaml.org/wiki/LibYAML] 或 [git 仓库:github.com/yaml/libyaml] 来实现其 YAML 解析和生成能力。除了包装 libyaml 之外,Psych 还知道如何将大多数 Ruby 对象序列化和反序列化为 YAML 格式。
我需要立即解析或生成 YAML!
# 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 解析
Psych 提供了一系列用于解析 YAML 文档的接口,从低级到高级,具体取决于您的解析需求。最低级别是一个基于事件的解析器。中级级别是对原始 YAML AST 的访问,最高级别是将 YAML 反序列化为 Ruby 对象的能力。
YAML 生成
Psych 提供了一系列从低级到高级的接口来生成 YAML 文档。与 YAML 解析接口非常相似,Psych 在最低级别提供基于事件的系统,中级级别是构建 YAML AST,最高级别是将 Ruby 对象直接转换为 YAML 文档。
高级 API
解析
Psych 提供的高级 YAML 解析器只需将 YAML 作为输入并返回 Ruby 数据结构。有关使用高级解析器的信息,请参阅 Psych.load
从字符串读取
Psych.safe_load("--- a") # => 'a' Psych.safe_load("---\n - a\n - b") # => ['a', 'b'] # From a trusted string: Psych.load("--- !ruby/range\nbegin: 0\nend: 42\nexcl: false\n") # => 0..42
从文件读取
Psych.safe_load_file("data.yml", permitted_classes: [Date]) Psych.load_file("trusted_database.yml")
异常处理
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
生成
高级生成器具有最简单的接口。 Psych 仅接受 Ruby 数据结构并将其转换为 YAML 文档。有关转储 Ruby 数据结构的信息,请参阅 Psych.dump。
写入字符串
# 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
解析
Psych 提供对从解析 YAML 文档生成的 AST 的访问。此树使用 Psych::Parser 和 Psych::TreeBuilder 构建。 AST 可以自由检查和操作。请参阅 Psych::parse_stream、Psych::Nodes 和 Psych::Nodes::Node 以获取有关处理 YAML 语法树的更多信息。
从字符串读取
# 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')
异常处理
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
生成
在中级级别是构建 AST。此 AST 与解析 YAML 文档时使用的 AST 完全相同。用户可以手动构建 AST,AST 知道如何将自身作为 YAML 文档生成。请参阅 Psych::Nodes、Psych::Nodes::Node 和 Psych::TreeBuilder 以获取有关构建 YAML AST 的更多信息。
写入字符串
# 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。
读取到 Psych::Nodes::Stream 结构
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>
接收事件流
recorder = Psych::Handlers::Recorder.new parser = Psych::Parser.new(recorder) parser.parse("---\n - a\n - b") recorder.events # => [list of [event, args] lists] # event is one of: Psych::Handler::EVENTS # args are the arguments passed to the event
生成
最低级别的生成器是基于事件的系统。事件被发送到 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"
Constants
Public Class Methods
Source
# File ext/psych/lib/psych.rb, line 515 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
将 Ruby 对象 o 转储到 YAML 字符串。可选的 options 可能被传递以控制输出格式。如果传入 IO 对象,YAML 将被转储到该 IO 对象。
当前支持的选项是
:indentation-
用于缩进的空格数。可接受的值应在
0..9范围内,否则选项将被忽略。默认值:
2。 :line_width-
换行前的最大字符数。无限制行宽请使用
-1。默认值:
0(表示“在 81 处换行”)。 :canonical-
写入“规范”
YAML格式(非常冗长,但严格正式)。默认值:
false。 :header-
在文档开头写入
%YAML [version]。默认值:
false。 :stringify_names-
将
Hash对象中的符号键转储为字符串。默认值:
false。
示例
# 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) # Dump hash with symbol keys as string Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
Source
# File ext/psych/lib/psych.rb, line 613 def self.dump_stream *objects visitor = Psych::Visitors::YAMLTree.create({}) objects.each do |o| visitor << o end visitor.tree.yaml end
将对象列表转储为文档流中的单独文档。
示例
Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n"
Source
static VALUE libyaml_version(VALUE module)
{
int major, minor, patch;
VALUE list[3];
yaml_get_version(&major, &minor, &patch);
list[0] = INT2NUM(major);
list[1] = INT2NUM(minor);
list[2] = INT2NUM(patch);
return rb_ary_new4((long)3, list);
}
返回正在使用的 libyaml 的版本
Source
# File ext/psych/lib/psych.rb, line 369 def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true safe_load yaml, permitted_classes: permitted_classes, permitted_symbols: permitted_symbols, aliases: aliases, filename: filename, fallback: fallback, symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols end
将 yaml 加载到 Ruby 数据结构中。如果提供了多个文档,则返回第一个文档中包含的对象。如果解析过程中出现任何异常,filename 将用于异常消息。如果 yaml 为空,则返回指定的 fallback 返回值,默认为 nil。
当检测到 YAML 语法错误时,会引发 Psych::SyntaxError。
示例
Psych.load("--- a") # => 'a' Psych.load("---\n - a\n - b") # => ['a', 'b'] begin Psych.load("--- `", filename: "file.txt") rescue Psych::SyntaxError => ex ex.file # => 'file.txt' ex.message # => "(file.txt): found character that cannot start any token" end
当可选的 symbolize_names 关键字参数设置为 true 时,返回 Hash 对象中的键的符号(默认:字符串)。
Psych.load("---\n foo: bar") # => {"foo"=>"bar"} Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
当 `yaml` 参数是 NilClass 时,引发 TypeError。此方法类似于 `safe_load`,只是默认允许 `Symbol` 对象。
Source
# File ext/psych/lib/psych.rb, line 716 def self.load_file filename, **kwargs File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename: filename, **kwargs } end
加载 filename 中包含的文档。返回 filename 中包含的 yaml 作为 Ruby 对象,或者如果文件为空,则返回指定的 fallback 返回值,默认为 nil。有关选项,请参阅 load。
Source
# File ext/psych/lib/psych.rb, line 644 def self.load_stream yaml, filename: nil, fallback: [], **kwargs result = if block_given? parse_stream(yaml, filename: filename) do |node| yield node.to_ruby(**kwargs) end else parse_stream(yaml, filename: filename).children.map { |node| node.to_ruby(**kwargs) } end return fallback if result.is_a?(Array) && result.empty? result end
加载 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']
Source
# File ext/psych/lib/psych.rb, line 400 def self.parse yaml, filename: nil parse_stream(yaml, filename: filename) do |node| return node end false end
解析 yaml 中的 YAML 字符串。返回 Psych::Nodes::Document。如果引发 Psych::SyntaxError,则 filename 用于异常消息。
当检测到 YAML 语法错误时,会引发 Psych::SyntaxError。
示例
Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00> begin Psych.parse("--- `", filename: "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。
Source
# File ext/psych/lib/psych.rb, line 412 def self.parse_file filename, fallback: false result = File.open filename, 'r:bom|utf-8' do |f| parse f, filename: filename end result || fallback end
解析 filename 处的文件。返回 Psych::Nodes::Document。
当检测到 YAML 语法错误时,会引发 Psych::SyntaxError。
Source
# File ext/psych/lib/psych.rb, line 454 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
解析 yaml 中的 YAML 字符串。返回 Psych::Nodes::Stream。此方法可以处理 yaml 中包含的多个 YAML 文档。如果引发 Psych::SyntaxError,则 filename 用于异常消息。
如果提供了块,则在解析 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("--- `", filename: "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。
Source
# File ext/psych/lib/psych.rb, line 421 def self.parser Psych::Parser.new(TreeBuilder.new) end
返回默认解析器
Source
# File ext/psych/lib/psych.rb, line 596 def self.safe_dump o, io = nil, options = {} if Hash === io options = io io = nil end visitor = Psych::Visitors::RestrictedYAMLTree.create options visitor << o visitor.tree.yaml io, options end
安全地将 Ruby 对象 o 转储到 YAML 字符串。可选的 options 可能被传递以控制输出格式。如果传入 IO 对象,YAML 将被转储到该 IO 对象。默认情况下,只允许序列化以下类
可以通过将这些类添加到 permitted_classes 关键字参数来允许任意类。它们是可加的。例如,要允许 Date 序列化
Psych.safe_dump(yaml, permitted_classes: [Date])
现在,除了上面列出的类之外,还可以转储 Date 类。
如果对象包含不在 permitted_classes 列表中的类,则会引发 Psych::DisallowedClass 异常。
当前支持的选项是
:indentation-
用于缩进的空格数。可接受的值应在
0..9范围内,否则选项将被忽略。默认值:
2。 :line_width-
换行前的最大字符数。无限制行宽请使用
-1。默认值:
0(表示“在 81 处换行”)。 :canonical-
写入“规范”
YAML格式(非常冗长,但严格正式)。默认值:
false。 :header-
在文档开头写入
%YAML [version]。默认值:
false。 :stringify_names-
将
Hash对象中的符号键转储为字符串。默认值:
false。
示例
# Dump an array, get back a YAML string Psych.safe_dump(['a', 'b']) # => "---\n- a\n- b\n" # Dump an array to an IO object Psych.safe_dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> # Dump an array with indentation set Psych.safe_dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n" # Dump an array to an IO with indentation set Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3) # Dump hash with symbol keys as string Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
Source
# File ext/psych/lib/psych.rb, line 323 def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true result = parse(yaml, filename: filename) return fallback unless result class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s), permitted_symbols.map(&:to_s)) scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols visitor = if aliases Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze else Visitors::NoAliasRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze end result = visitor.accept result result end
安全地加载 yaml 中的 yaml 字符串。默认情况下,只允许反序列化以下类
默认不允许递归数据结构。可以通过将这些类添加到 permitted_classes 关键字参数来允许任意类。它们是可加的。例如,要允许 Date 反序列化
Psych.safe_load(yaml, permitted_classes: [Date])
现在,除了上面列出的类之外,还可以加载 Date 类。
可以通过更改 aliases 关键字参数来显式允许别名。例如
x = [] x << x yaml = Psych.dump x Psych.safe_load yaml # => raises an exception Psych.safe_load yaml, aliases: true # => loads the aliases
如果 yaml 包含不在 permitted_classes 列表中的类,则会引发 Psych::DisallowedClass 异常。
如果 yaml 包含别名但 aliases 关键字参数设置为 false,则会引发 Psych::AliasesNotEnabled 异常。
如果解析过程中出现任何异常,filename 将用于异常消息。
当可选的 symbolize_names 关键字参数设置为 true 时,返回 Hash 对象中的键的符号(默认:字符串)。
Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"} Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
Source
# File ext/psych/lib/psych.rb, line 705 def self.safe_load_file filename, **kwargs File.open(filename, 'r:bom|utf-8') { |f| self.safe_load f, filename: filename, **kwargs } end
安全地加载 filename 中包含的文档。返回 filename 中包含的 yaml 作为 Ruby 对象,或者如果文件为空,则返回指定的 fallback 返回值,默认为 nil。有关选项,请参阅 safe_load。
Source
# File ext/psych/lib/psych.rb, line 671 def self.safe_load_stream yaml, filename: nil, permitted_classes: [], aliases: false documents = parse_stream(yaml, filename: filename).children.map do |child| stream = Psych::Nodes::Stream.new stream.children << child safe_load(stream.to_yaml, permitted_classes: permitted_classes, aliases: aliases) end if block_given? documents.each { |doc| yield doc } nil else documents end end
加载 yaml 中提供的多个文档。将解析后的文档作为列表返回。
示例
Psych.safe_load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] list = [] Psych.safe_load_stream("--- foo\n...\n--- bar\n...") do |ruby| list << ruby end list # => ['foo', 'bar']
Source
# File ext/psych/lib/psych.rb, line 623 def self.to_json object visitor = Psych::Visitors::JSONTree.create visitor << object visitor.tree.yaml end
将 Ruby object 转储到 JSON 字符串。
Source
# File ext/psych/lib/psych.rb, line 272 def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true result = parse(yaml, filename: filename) return fallback unless result result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols) end
将 yaml 加载到 Ruby 数据结构中。如果提供了多个文档,则返回第一个文档中包含的对象。如果解析过程中出现任何异常,filename 将用于异常消息。如果 yaml 为空,则返回指定的 fallback 返回值,默认为 false。
当检测到 YAML 语法错误时,会引发 Psych::SyntaxError。
示例
Psych.unsafe_load("--- a") # => 'a' Psych.unsafe_load("---\n - a\n - b") # => ['a', 'b'] begin Psych.unsafe_load("--- `", filename: "file.txt") rescue Psych::SyntaxError => ex ex.file # => 'file.txt' ex.message # => "(file.txt): found character that cannot start any token" end
当可选的 symbolize_names 关键字参数设置为 true 时,返回 Hash 对象中的键的符号(默认:字符串)。
Psych.unsafe_load("---\n foo: bar") # => {"foo"=>"bar"} Psych.unsafe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
当 `yaml` 参数是 NilClass 时,引发 TypeError
注意:此方法*不应*用于解析不受信任的文档,例如通过用户输入提供的 YAML 文档。相反,请使用 load 方法或 safe_load 方法。
Source
# File ext/psych/lib/psych.rb, line 694 def self.unsafe_load_file filename, **kwargs File.open(filename, 'r:bom|utf-8') { |f| self.unsafe_load f, filename: filename, **kwargs } end
加载 filename 中包含的文档。返回 filename 中包含的 yaml 作为 Ruby 对象,或者如果文件为空,则返回指定的 fallback 返回值,默认为 false。
注意:此方法*不应*用于解析不受信任的文档,例如通过用户输入提供的 YAML 文档。相反,请使用 safe_load_file 方法。