summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--ext/psych/lib/psych/syntax_error.rb18
-rw-r--r--ext/psych/parser.c27
-rw-r--r--test/psych/test_exception.rb15
4 files changed, 62 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index e52628adce..87cd76a7f2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Wed Oct 5 02:50:27 2011 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/syntax_error.rb: Add file, line, offset, and
+ message attributes during parse failure.
+ * ext/psych/parser.c: Update parser to raise exception with correct
+ values.
+ * test/psych/test_exception.rb: corresponding tests.
+
Wed Oct 5 01:52:16 2011 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/parser.c (parse): Use context_mark for indicating error
diff --git a/ext/psych/lib/psych/syntax_error.rb b/ext/psych/lib/psych/syntax_error.rb
new file mode 100644
index 0000000000..9fe3e0da30
--- /dev/null
+++ b/ext/psych/lib/psych/syntax_error.rb
@@ -0,0 +1,18 @@
+module Psych
+ class SyntaxError < ::SyntaxError
+ attr_reader :file, :line, :column, :offset, :problem, :context
+
+ def initialize file, line, col, offset, problem, context
+ err = [problem, context].compact.join ' '
+ message = "(%s): %s at line %d column %d" % [file, err, line, col]
+
+ @file = file
+ @line = line
+ @column = col
+ @offset = offset
+ @problem = problem
+ @context = context
+ super(message)
+ end
+ end
+end
diff --git a/ext/psych/parser.c b/ext/psych/parser.c
index f3928a9510..1a6e281f43 100644
--- a/ext/psych/parser.c
+++ b/ext/psych/parser.c
@@ -59,6 +59,23 @@ static VALUE allocate(VALUE klass)
return Data_Wrap_Struct(klass, 0, dealloc, parser);
}
+static VALUE make_exception(yaml_parser_t * parser, VALUE path)
+{
+ VALUE exception;
+ size_t line, column;
+
+ line = parser->context_mark.line + 1;
+ column = parser->context_mark.column + 1;
+
+ return rb_funcall(ePsychSyntaxError, rb_intern("new"), 6,
+ path,
+ INT2NUM(line),
+ INT2NUM(column),
+ INT2NUM(parser->problem_offset),
+ parser->problem ? rb_usascii_str_new2(parser->problem) : Qnil,
+ parser->context ? rb_usascii_str_new2(parser->context) : Qnil);
+}
+
/*
* call-seq:
* parser.parse(yaml)
@@ -98,21 +115,18 @@ static VALUE parse(VALUE self, VALUE yaml)
while(!done) {
if(!yaml_parser_parse(parser, &event)) {
- VALUE path;
- size_t line = parser->context_mark.line + 1;
- size_t column = parser->context_mark.column + 1;
+ VALUE path, exception;
if(rb_respond_to(yaml, id_path))
path = rb_funcall(yaml, id_path, 0);
else
path = rb_str_new2("<unknown>");
+ exception = make_exception(parser, path);
yaml_parser_delete(parser);
yaml_parser_initialize(parser);
- rb_raise(ePsychSyntaxError, "(%s): couldn't parse YAML at line %d column %d",
- StringValuePtr(path),
- (int)line, (int)column);
+ rb_exc_raise(exception);
}
switch(event.type) {
@@ -376,6 +390,7 @@ void Init_psych_parser()
/* UTF-16-BE Encoding with BOM */
rb_define_const(cPsychParser, "UTF16BE", INT2NUM(YAML_UTF16BE_ENCODING));
+ rb_require("psych/syntax_error");
ePsychSyntaxError = rb_define_class_under(mPsych, "SyntaxError", rb_eSyntaxError);
rb_define_method(cPsychParser, "parse", parse, 1);
diff --git a/test/psych/test_exception.rb b/test/psych/test_exception.rb
index 806c5e2641..5530a69626 100644
--- a/test/psych/test_exception.rb
+++ b/test/psych/test_exception.rb
@@ -16,6 +16,21 @@ module Psych
@wups = Wups.new
end
+ def test_attributes
+ e = assert_raises(Psych::SyntaxError) {
+ Psych.load '--- `foo'
+ }
+
+ assert_equal '<unknown>', e.file
+ assert_equal 1, e.line
+ assert_equal 5, e.column
+ # FIXME: offset isn't being set correctly by libyaml
+ # assert_equal 5, e.offset
+
+ assert e.problem
+ assert e.context
+ end
+
def test_convert
w = Psych.load(Psych.dump(@wups))
assert_equal @wups, w