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文档yaml
。filename
在引发一个 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