模块 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")
Exception
处理¶ ↑
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)
写入文件¶ ↑
目前没有直接的 API 用于将 Ruby 结构转储到文件
File.open('database.yml', 'w') do |file| file.write(Psych.dump(['a', 'b'])) end
中级 API¶ ↑
解析¶ ↑
Psych
提供对从解析 YAML 文档生成的 AST 的访问。此树是使用 Psych::Parser
和 Psych::TreeBuilder
构建的。可以自由地检查和操作 AST。有关处理 YAML 语法树的更多信息,请参阅 Psych::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')
Exception
处理¶ ↑
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 文档发射。有关构建 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
。
读取到 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"
常量
公共类方法
将 Ruby 对象 o
转换为 YAML 字符串。可以传入可选的 options
来控制输出格式。如果传入 IO 对象,则 YAML 将被转储到该 IO 对象。
当前支持的选项是
:indentation
-
用于缩进的空格字符数。可接受的值应在
0..9
范围内,否则选项将被忽略。默认值:
2
。 :line_width
-
换行时的最大字符数。
默认值:
0
(表示“在 81 个字符处换行”)。 :canonical
-
写入“规范”YAML 格式(非常冗长,但严格正式)。
默认值:
false
。 :header
-
在文档开头写入
%YAML [version]
。默认值:
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)
# File psych/lib/psych.rb, line 505 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
将对象列表作为单独的文档转储到文档流中。
示例
Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n"
# File psych/lib/psych.rb, line 595 def self.dump_stream *objects visitor = Psych::Visitors::YAMLTree.create({}) objects.each do |o| visitor << o end visitor.tree.yaml end
返回正在使用的 libyaml 版本
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); }
将 yaml
加载到 Ruby 数据结构中。如果提供了多个文档,则将返回第一个文档中包含的对象。如果在解析过程中引发任何异常,则 filename
将用于异常消息。如果 yaml
为空,则返回指定的 fallback
返回值,默认值为 false
。
当检测到 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
关键字参数设置为真值时,将返回 Hash 对象中键的符号(默认:字符串)。
Psych.load("---\n foo: bar") # => {"foo"=>"bar"} Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
当 ‘yaml` 参数为 NilClass 时,会引发 TypeError。此方法类似于 `safe_load`,只是默认情况下允许 `Symbol` 对象。
# File psych/lib/psych.rb, line 368 def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false 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 end
加载 filename
中包含的文档。将 filename
中包含的 yaml 作为 Ruby 对象返回,或者如果文件为空,则返回指定的 fallback
返回值,默认值为 false
。有关选项,请参见 load。
# File psych/lib/psych.rb, line 669 def self.load_file filename, **kwargs File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename: filename, **kwargs } 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']
# File psych/lib/psych.rb, line 626 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
中的 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
。
# File psych/lib/psych.rb, line 398 def self.parse yaml, filename: nil parse_stream(yaml, filename: filename) do |node| return node end false end
解析 filename
处的文件。返回 Psych::Nodes::Document
。
当检测到 YAML 语法错误时,会引发 Psych::SyntaxError
。
# File psych/lib/psych.rb, line 410 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
解析 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
当传递 NilClass 时,会引发 TypeError。
有关 YAML AST 的更多信息,请参见 Psych::Nodes
。
# File psych/lib/psych.rb, line 452 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
返回默认解析器
# File psych/lib/psych.rb, line 419 def self.parser Psych::Parser.new(TreeBuilder.new) end
安全地将 Ruby 对象 o
转换为 YAML 字符串。可选的 options
可以传递进来以控制输出格式。如果传入了一个 IO 对象,YAML 将被转储到该 IO 对象。默认情况下,只有以下类允许被序列化
-
TrueClass
-
FalseClass
-
NilClass
-
Integer
-
Float
-
String
-
Array
-
Hash
可以通过将这些类添加到 permitted_classes
关键字参数中来允许任意类。它们是累加的。例如,要允许 Date 序列化
Psych.safe_dump(yaml, permitted_classes: [Date])
现在,除了上面列出的类之外,Date 类也可以被转储。
如果对象包含不在 permitted_classes
列表中的类,则会引发 Psych::DisallowedClass
异常。
当前支持的选项是
:indentation
-
用于缩进的空格字符数。可接受的值应在
0..9
范围内,否则选项将被忽略。默认值:
2
。 :line_width
-
换行时的最大字符数。
默认值:
0
(表示“在 81 个字符处换行”)。 :canonical
-
写入“规范”YAML 格式(非常冗长,但严格正式)。
默认值:
false
。 :header
-
在文档开头写入
%YAML [version]
。默认值:
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)
# File psych/lib/psych.rb, line 578 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
安全地加载 yaml
中的 yaml 字符串。默认情况下,只有以下类允许被反序列化
-
TrueClass
-
FalseClass
-
NilClass
-
Integer
-
Float
-
String
-
Array
-
Hash
默认情况下不允许递归数据结构。可以通过将这些类添加到 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
关键字参数设置为真值时,将返回 Hash 对象中键的符号(默认:字符串)。
Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"} Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
# File psych/lib/psych.rb, line 322 def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false 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 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
安全地加载 filename
中包含的文档。将 filename
中包含的 yaml 作为 Ruby 对象返回,如果文件为空,则返回指定的 fallback
返回值,默认值为 false
。有关选项,请参见 safe_load
。
# File psych/lib/psych.rb, line 658 def self.safe_load_file filename, **kwargs File.open(filename, 'r:bom|utf-8') { |f| self.safe_load f, filename: filename, **kwargs } end
将 Ruby object
转换为 JSON
字符串。
# File psych/lib/psych.rb, line 605 def self.to_json object visitor = Psych::Visitors::JSONTree.create visitor << object visitor.tree.yaml 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
关键字参数设置为真值时,将返回 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
方法。
# File psych/lib/psych.rb, line 271 def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false result = parse(yaml, filename: filename) return fallback unless result result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer) end
加载 filename
中包含的文档。将 filename
中包含的 yaml 作为 Ruby 对象返回,如果文件为空,则返回指定的 fallback
返回值,默认值为 false
。
注意:此方法 *不应* 用于解析不受信任的文档,例如通过用户输入提供的 YAML 文档。相反,请使用 safe_load_file
方法。
# File psych/lib/psych.rb, line 647 def self.unsafe_load_file filename, **kwargs File.open(filename, 'r:bom|utf-8') { |f| self.unsafe_load f, filename: filename, **kwargs } end