class Psych::Parser
YAML 事件解析器类。此类解析 YAML 文档,并在传递给构造函数的处理程序上调用事件。这些事件可以用于诸如构建 YAML AST 或反序列化 YAML 文档之类的操作。它甚至可以反馈给 Psych::Emitter,以发出解析的同一文档。
有关 Psych::Parser 发出的事件的文档,请参阅 Psych::Handler。
这是一个示例,打印出在 YAML 文档中找到的每个标量
# Handler for detecting scalar values class ScalarHandler < Psych::Handler def scalar value, anchor, tag, plain, quoted, style puts value end end parser = Psych::Parser.new(ScalarHandler.new) parser.parse(yaml_document)
这是一个示例,将解析器反馈到 Psych::Emitter 中。YAML 文档从 STDIN 读取,并写回 STDERR
parser = Psych::Parser.new(Psych::Emitter.new($stderr)) parser.parse($stdin)
Psych 使用 Psych::Parser 与 Psych::TreeBuilder 结合使用来构建解析的 YAML 文档的 AST。
常量
- ANY
让解析器选择编码
- UTF16BE
带 BOM 的 UTF-16-BE 编码
- UTF16LE
带 BOM 的 UTF-16-LE 编码
- UTF8
UTF-8 编码
属性
external_encoding[W]
将此解析器的编码 Set 为 encoding
handler[RW]
将在其上调用事件的处理程序
公共类方法
new(handler = Handler.new) 点击切换源
使用 handler 创建一个新的 Psych::Parser 实例。YAML 事件将在 handler 上调用。有关更多详细信息,请参阅 Psych::Parser。
# File psych/lib/psych/parser.rb, line 47 def initialize handler = Handler.new @handler = handler @external_encoding = ANY end
公共实例方法
mark # → #<Psych::Parser::Mark> 点击切换源
返回一个包含行、列和索引信息的 Psych::Parser::Mark 对象。
static VALUE mark(VALUE self)
{
VALUE mark_klass;
VALUE args[3];
yaml_parser_t * parser;
TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser);
mark_klass = rb_const_get_at(cPsychParser, rb_intern("Mark"));
args[0] = SIZET2NUM(parser->mark.index);
args[1] = SIZET2NUM(parser->mark.line);
args[2] = SIZET2NUM(parser->mark.column);
return rb_class_new_instance(3, args, mark_klass);
}
parse(yaml) 点击切换源
解析包含在 yaml 中的 YAML 文档。事件将在解析器实例上设置的处理程序上调用。
请参阅 Psych::Parser 和 Psych::Parser#handler
# File psych/lib/psych/parser.rb, line 61 def parse yaml, path = yaml.respond_to?(:path) ? yaml.path : "<unknown>" _native_parse @handler, yaml, path end
私有实例方法
_native_parse(p1, p2, p3) 点击切换源
static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
{
yaml_parser_t * parser;
yaml_event_t event;
int done = 0;
int state = 0;
int parser_encoding = YAML_ANY_ENCODING;
int encoding = rb_utf8_encindex();
rb_encoding * internal_enc = rb_default_internal_encoding();
TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser);
yaml_parser_delete(parser);
yaml_parser_initialize(parser);
if (rb_respond_to(yaml, id_read)) {
yaml = transcode_io(yaml, &parser_encoding);
yaml_parser_set_encoding(parser, parser_encoding);
yaml_parser_set_input(parser, io_reader, (void *)yaml);
} else {
StringValue(yaml);
yaml = transcode_string(yaml, &parser_encoding);
yaml_parser_set_encoding(parser, parser_encoding);
yaml_parser_set_input_string(
parser,
(const unsigned char *)RSTRING_PTR(yaml),
(size_t)RSTRING_LEN(yaml)
);
}
while(!done) {
VALUE event_args[5];
VALUE start_line, start_column, end_line, end_column;
if(parser->error || !yaml_parser_parse(parser, &event)) {
VALUE exception;
exception = make_exception(parser, path);
yaml_parser_delete(parser);
yaml_parser_initialize(parser);
rb_exc_raise(exception);
}
start_line = SIZET2NUM(event.start_mark.line);
start_column = SIZET2NUM(event.start_mark.column);
end_line = SIZET2NUM(event.end_mark.line);
end_column = SIZET2NUM(event.end_mark.column);
event_args[0] = handler;
event_args[1] = start_line;
event_args[2] = start_column;
event_args[3] = end_line;
event_args[4] = end_column;
rb_protect(protected_event_location, (VALUE)event_args, &state);
switch(event.type) {
case YAML_STREAM_START_EVENT:
{
VALUE args[2];
args[0] = handler;
args[1] = INT2NUM(event.data.stream_start.encoding);
rb_protect(protected_start_stream, (VALUE)args, &state);
}
break;
case YAML_DOCUMENT_START_EVENT:
{
VALUE args[4];
/* Get a list of tag directives (if any) */
VALUE tag_directives = rb_ary_new();
/* Grab the document version */
VALUE version = event.data.document_start.version_directive ?
rb_ary_new3(
(long)2,
INT2NUM(event.data.document_start.version_directive->major),
INT2NUM(event.data.document_start.version_directive->minor)
) : rb_ary_new();
if(event.data.document_start.tag_directives.start) {
yaml_tag_directive_t *start =
event.data.document_start.tag_directives.start;
yaml_tag_directive_t *end =
event.data.document_start.tag_directives.end;
for(; start != end; start++) {
VALUE handle = Qnil;
VALUE prefix = Qnil;
if(start->handle) {
handle = rb_str_new2((const char *)start->handle);
PSYCH_TRANSCODE(handle, encoding, internal_enc);
}
if(start->prefix) {
prefix = rb_str_new2((const char *)start->prefix);
PSYCH_TRANSCODE(prefix, encoding, internal_enc);
}
rb_ary_push(tag_directives, rb_ary_new3((long)2, handle, prefix));
}
}
args[0] = handler;
args[1] = version;
args[2] = tag_directives;
args[3] = event.data.document_start.implicit == 1 ? Qtrue : Qfalse;
rb_protect(protected_start_document, (VALUE)args, &state);
}
break;
case YAML_DOCUMENT_END_EVENT:
{
VALUE args[2];
args[0] = handler;
args[1] = event.data.document_end.implicit == 1 ? Qtrue : Qfalse;
rb_protect(protected_end_document, (VALUE)args, &state);
}
break;
case YAML_ALIAS_EVENT:
{
VALUE args[2];
VALUE alias = Qnil;
if(event.data.alias.anchor) {
alias = rb_str_new2((const char *)event.data.alias.anchor);
PSYCH_TRANSCODE(alias, encoding, internal_enc);
}
args[0] = handler;
args[1] = alias;
rb_protect(protected_alias, (VALUE)args, &state);
}
break;
case YAML_SCALAR_EVENT:
{
VALUE args[7];
VALUE anchor = Qnil;
VALUE tag = Qnil;
VALUE plain_implicit, quoted_implicit, style;
VALUE val = rb_str_new(
(const char *)event.data.scalar.value,
(long)event.data.scalar.length
);
PSYCH_TRANSCODE(val, encoding, internal_enc);
if(event.data.scalar.anchor) {
anchor = rb_str_new2((const char *)event.data.scalar.anchor);
PSYCH_TRANSCODE(anchor, encoding, internal_enc);
}
if(event.data.scalar.tag) {
tag = rb_str_new2((const char *)event.data.scalar.tag);
PSYCH_TRANSCODE(tag, encoding, internal_enc);
}
plain_implicit =
event.data.scalar.plain_implicit == 0 ? Qfalse : Qtrue;
quoted_implicit =
event.data.scalar.quoted_implicit == 0 ? Qfalse : Qtrue;
style = INT2NUM(event.data.scalar.style);
args[0] = handler;
args[1] = val;
args[2] = anchor;
args[3] = tag;
args[4] = plain_implicit;
args[5] = quoted_implicit;
args[6] = style;
rb_protect(protected_scalar, (VALUE)args, &state);
}
break;
case YAML_SEQUENCE_START_EVENT:
{
VALUE args[5];
VALUE anchor = Qnil;
VALUE tag = Qnil;
VALUE implicit, style;
if(event.data.sequence_start.anchor) {
anchor = rb_str_new2((const char *)event.data.sequence_start.anchor);
PSYCH_TRANSCODE(anchor, encoding, internal_enc);
}
tag = Qnil;
if(event.data.sequence_start.tag) {
tag = rb_str_new2((const char *)event.data.sequence_start.tag);
PSYCH_TRANSCODE(tag, encoding, internal_enc);
}
implicit =
event.data.sequence_start.implicit == 0 ? Qfalse : Qtrue;
style = INT2NUM(event.data.sequence_start.style);
args[0] = handler;
args[1] = anchor;
args[2] = tag;
args[3] = implicit;
args[4] = style;
rb_protect(protected_start_sequence, (VALUE)args, &state);
}
break;
case YAML_SEQUENCE_END_EVENT:
rb_protect(protected_end_sequence, handler, &state);
break;
case YAML_MAPPING_START_EVENT:
{
VALUE args[5];
VALUE anchor = Qnil;
VALUE tag = Qnil;
VALUE implicit, style;
if(event.data.mapping_start.anchor) {
anchor = rb_str_new2((const char *)event.data.mapping_start.anchor);
PSYCH_TRANSCODE(anchor, encoding, internal_enc);
}
if(event.data.mapping_start.tag) {
tag = rb_str_new2((const char *)event.data.mapping_start.tag);
PSYCH_TRANSCODE(tag, encoding, internal_enc);
}
implicit =
event.data.mapping_start.implicit == 0 ? Qfalse : Qtrue;
style = INT2NUM(event.data.mapping_start.style);
args[0] = handler;
args[1] = anchor;
args[2] = tag;
args[3] = implicit;
args[4] = style;
rb_protect(protected_start_mapping, (VALUE)args, &state);
}
break;
case YAML_MAPPING_END_EVENT:
rb_protect(protected_end_mapping, handler, &state);
break;
case YAML_NO_EVENT:
rb_protect(protected_empty, handler, &state);
break;
case YAML_STREAM_END_EVENT:
rb_protect(protected_end_stream, handler, &state);
done = 1;
break;
}
yaml_event_delete(&event);
if (state) rb_jump_tag(state);
}
return self;
}