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 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
將物件清單作為個別文件轉儲至文件串流。
範例
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 版本
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
。
當偵測到 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
載入包含在 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
載入在 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
剖析 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
剖析 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
剖析 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
請參閱 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
傳回預設剖析器
# File ext/psych/lib/psych.rb, line 419 def self.parser Psych::Parser.new(TreeBuilder.new) 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
-
換行的最大字元數。
預設值:
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
安全地載入 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
安全載入 `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
將 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
將 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
載入 `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