модуль 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 высокого уровня
Парсинг
Парсер YAML высокого уровня, предоставляемый Psych, просто принимает 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. См. Psych.dump для получения дополнительной информации о выводе структуры данных 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)
Запись в файл
В настоящее время нет прямого API для вывода структуры Ruby в файл:
File.open('database.yml', 'w') do |file|
file.write(Psych.dump(['a', 'b']))
end
API среднего уровня
Парсинг
Psych предоставляет доступ к AST, созданной в результате парсинга документа YAML. Это дерево построено с использованием 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 идентична AST, используемой при парсинге документа YAML. Пользователи могут вручную построить 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 для получения дополнительной информации об использовании событийного парсера.
Чтение в структуру
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"
Константы
Методы открытого класса
# 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 Выводит объект 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 595
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"
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
# 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 Загружает документ, содержащийся в filename. Возвращает yaml, содержащийся в filename, как объект Ruby, или, если файл пустой, возвращает указанное значение fallback возврата, которое по умолчанию равно false. См. load для параметров.
# 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. Возвращает список проанализированных документов. Если задан блок, каждый документ будет преобразован в 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 398
def self.parse yaml, filename: nil
parse_stream(yaml, filename: filename) do |node|
return node
end
false
end Парсинг строки YAML в yaml. Возвращает Psych::Nodes::Document. filename используется в сообщении об ошибке, если возникает Psych::SyntaxError.
Вызывает 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 для получения дополнительной информации об AST 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 Парсинг файла по адресу filename. Возвращает Psych::Nodes::Document.
Вызывает Psych::SyntaxError при обнаружении синтаксической ошибки YAML.
# 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 Парсинг строки YAML в yaml. Возвращает Psych::Nodes::Stream. Данный метод может обрабатывать несколько документов YAML, содержащихся в yaml. filename используется в сообщении об ошибке, если возникает Psych::SyntaxError.
Если задан блок, узел 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 для получения дополнительной информации об AST YAML.
# File ext/psych/lib/psych.rb, line 419 def self.parser Psych::Parser.new(TreeBuilder.new) end
Возвращает парсер по умолчанию
# 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 Безопасно выводит объект Ruby o в строку YAML. Дополнительные options могут быть переданы для управления форматом вывода. Если передается объект IO, то YAML будет выведен в этот объект IO. По умолчанию разрешены только следующие классы:
Произвольные классы могут быть разрешены путем добавления этих классов в аргумент permitted_classes. Они добавляются. Например, для разрешения сериализации Date:
Psych.safe_dump(yaml, permitted_classes: [Date])
Теперь класс Date может быть выведен, в дополнение к классам, перечисленным выше.
Исключение Psych::DisallowedClass будет вызвано, если объект содержит класс, который не входит в список permitted_classes.
В настоящее время поддерживаются следующие параметры:
-
: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 323
def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: 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
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
Будет выброшено исключение Psych::DisallowedClass, если yaml содержит класс, который не входит в список permitted_classes.
Будет выброшено исключение Psych::BadAlias, если yaml содержит псевдонимы, но аргумент aliases установлен в значение false.
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 658
def self.safe_load_file filename, **kwargs
File.open(filename, 'r:bom|utf-8') { |f|
self.safe_load f, filename: filename, **kwargs
}
end Безопасно загружает документ, содержащийся в filename. Возвращает yaml, содержащийся в filename, как объект Ruby, или, если файл пуст, возвращает указанное значение возврата fallback, по умолчанию false. См. safe_load для параметров.
# File ext/psych/lib/psych.rb, line 605 def self.to_json object visitor = Psych::Visitors::JSONTree.create visitor << object visitor.tree.yaml end
Выгрузить объект Ruby object в строку JSON.
# File ext/psych/lib/psych.rb, line 271 def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false result = parse(yaml, filename: filename) return fallback unless result result.to_ruby(symbolize_names: symbolize_names, freeze: freeze) 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"}
Выбрасывает исключение TypeError, когда параметр ‘yaml` — NilClass.
ПРИМЕЧАНИЕ: Этот метод *не следует* использовать для парсинга недоверенных документов, таких как YAML документы, предоставленные пользователем. Вместо этого используйте метод load или метод safe_load.
# 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 Загрузить документ, содержащийся в filename. Возвращает yaml, содержащийся в filename, как объект Ruby, или, если файл пуст, возвращает указанное значение возврата fallback, по умолчанию false.
ПРИМЕЧАНИЕ: Этот метод *не следует* использовать для парсинга недоверенных документов, таких как YAML документы, предоставленные пользователем. Вместо этого используйте метод safe_load_file.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.