Psych 模組

概觀

PsychYAML 剖析器和發出器。 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::ParserPsych::TreeBuilder 建立。AST 可以自由地檢查和操作。有關處理 YAML 語法樹狀結構的更多資訊,請參閱 Psych::parse_streamPsych::NodesPsych::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::NodesPsych::Nodes::NodePsych::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"

常數

DEFAULT_SNAKEYAML_VERSION
LIBYAML_VERSION

libyaml 的版本 Psych 正在使用

VERSION

您正在使用的 Psych 版本

公開類別方法

dump(o) → yaml 字串 按一下以切換來源
dump(o, options) → yaml 字串
dump(o, io) → 傳入的 io 物件
dump(o, io, options) → 傳入的 io 物件

將 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 ext/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
dump_stream(*objects) 按一下以切換來源

將物件清單作為個別文件轉儲至文件串流。

範例

Psych.dump_stream("foo\n  ", {}) # => "--- ! \"foo\\n  \"\n--- {}\n"
# File ext/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_version 按一下以切換來源

傳回正在使用的 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);
}
load(yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false) 按一下以切換來源

yaml 載入 Ruby 資料結構。如果提供多個文件,將傳回第一個文件包含的物件。如果在剖析時引發任何例外狀況,將在例外狀況訊息中使用 filename。如果 yaml 為空,它會傳回指定的 fallback 傳回值,預設為 false

當偵測到 Psych::SyntaxError 語法錯誤時,會引發 YAML

範例

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` 物件。

# File ext/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
load_file(filename, **kwargs) 按一下以切換來源

載入包含在 filename 中的文件。傳回 filename 中包含的 yaml 作為 Ruby 物件,或者如果檔案為空,則傳回指定的 fallback 傳回值,預設為 false。請參閱 load 以取得選項。

# File ext/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
load_stream(yaml, filename: nil, fallback: [], **kwargs) { |to_ruby(**kwargs)| ... } 按一下以切換來源

載入在 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 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
parse(yaml, filename: nil) 按一下以切換來源

剖析 yaml 中的 YAML 字串。傳回 Psych::Nodes::Document。如果引發 Psych::SyntaxError,則會在例外訊息中使用 filename

當偵測到 Psych::SyntaxError 語法錯誤時,會引發 YAML

範例

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

請參閱 Psych::Nodes 以取得有關 YAML AST 的更多資訊。

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

  false
end
parse_file(filename, fallback: false) 按一下以切換來源

剖析 filename 中的檔案。傳回 Psych::Nodes::Document

當偵測到 Psych::SyntaxError 語法錯誤時,會引發 YAML

# File ext/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
parse_stream(yaml, filename: nil, &block) 按一下以切換來源

剖析 yaml 中的 YAML 字串。傳回 Psych::Nodes::Stream。此方法可以處理包含在 yaml 中的許多 YAML 文件。如果引發 Psych::SyntaxError,則會在例外訊息中使用 filename

如果提供區塊,則會在剖析 Psych::Nodes::Document 節點時,將其傳遞給區塊。

當偵測到 Psych::SyntaxError 語法錯誤時,會引發 YAML

範例

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

當傳遞 TypeError 時,會引發 NilClass

請參閱 Psych::Nodes 以取得有關 YAML AST 的更多資訊。

# File ext/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
parser() 按一下以切換來源

傳回預設剖析器

# File ext/psych/lib/psych.rb, line 419
def self.parser
  Psych::Parser.new(TreeBuilder.new)
end
safe_dump(o) → yaml 字串 按一下以切換來源
safe_dump(o, options) → yaml 字串
safe_dump(o, io) → 傳入的 io 物件
safe_dump(o, io, options) → 傳入的 io 物件

安全地將 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

換行的最大字元數。

預設值: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 ext/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
safe_load(yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false) 按一下以切換來源

安全地載入 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"}
# File ext/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
safe_load_file(filename, **kwargs) 按一下以切換來源

安全載入 `filename` 中的文件。將 `filename` 中的 yaml 以 Ruby 物件回傳,或者如果檔案為空,則回傳指定的 `fallback` 回傳值,預設為 `false`。有關選項,請參閱 safe_load

# File ext/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
to_json(object) 按一下以切換來源

將 Ruby `object` 轉儲為 JSON 字串。

# File ext/psych/lib/psych.rb, line 605
def self.to_json object
  visitor = Psych::Visitors::JSONTree.create
  visitor << object
  visitor.tree.yaml
end
unsafe_load(yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false) 按一下以切換來源

yaml 載入 Ruby 資料結構。如果提供多個文件,將傳回第一個文件包含的物件。如果在剖析時引發任何例外狀況,將在例外狀況訊息中使用 filename。如果 yaml 為空,它會傳回指定的 fallback 傳回值,預設為 false

當偵測到 Psych::SyntaxError 語法錯誤時,會引發 YAML

範例

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 方法。

# File ext/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
unsafe_load_file(filename, **kwargs) 按一下以切換來源

載入 `filename` 中的文件。將 `filename` 中的 yaml 以 Ruby 物件回傳,或者如果檔案為空,則回傳指定的 `fallback` 回傳值,預設為 `false`。

注意:此方法 *不應* 用於解析不受信任的文件,例如透過使用者輸入提供的 YAML 文件。請改用 safe_load_file 方法。

# File ext/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