summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2011-02-06 17:13:27 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2011-02-06 17:13:27 -0800
commit8c60e9fa2a5e4932d8762469000b232d57c696b5 (patch)
tree29ba5ec4de61ecb966f68e11146de6cb6ca266f3
parente008a513f5e33031c5e9341cb4da09a225693840 (diff)
downloadpsych-8c60e9fa2a5e4932d8762469000b232d57c696b5.tar.gz
merging from ruby
-rw-r--r--ext/psych/parser.c14
-rw-r--r--lib/psych/nodes/node.rb9
-rw-r--r--lib/psych/visitors/depth_first.rb18
-rw-r--r--lib/psych/visitors/to_ruby.rb20
-rw-r--r--test/psych/nodes/test_enumerable.rb43
-rw-r--r--test/psych/test_json_tree.rb5
-rw-r--r--test/psych/test_merge_keys.rb72
-rw-r--r--test/psych/test_parser.rb27
-rw-r--r--test/psych/test_yaml.rb5
-rw-r--r--test/psych/visitors/test_depth_first.rb48
10 files changed, 238 insertions, 23 deletions
diff --git a/ext/psych/parser.c b/ext/psych/parser.c
index 071b8c0..7bfdf4a 100644
--- a/ext/psych/parser.c
+++ b/ext/psych/parser.c
@@ -4,6 +4,7 @@ VALUE cPsychParser;
VALUE ePsychSyntaxError;
static ID id_read;
+static ID id_path;
static ID id_empty;
static ID id_start_stream;
static ID id_end_stream;
@@ -93,10 +94,20 @@ static VALUE parse(VALUE self, VALUE yaml)
while(!done) {
if(!yaml_parser_parse(parser, &event)) {
+ VALUE path;
size_t line = parser->mark.line;
size_t column = parser->mark.column;
- rb_raise(ePsychSyntaxError, "couldn't parse YAML at line %d column %d",
+ if(rb_respond_to(yaml, id_path))
+ path = rb_funcall(yaml, id_path, 0);
+ else
+ path = rb_str_new2("<unknown>");
+
+ 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);
}
@@ -357,6 +368,7 @@ void Init_psych_parser()
rb_define_method(cPsychParser, "external_encoding=", set_external_encoding, 1);
id_read = rb_intern("read");
+ id_path = rb_intern("path");
id_empty = rb_intern("empty");
id_start_stream = rb_intern("start_stream");
id_end_stream = rb_intern("end_stream");
diff --git a/lib/psych/nodes/node.rb b/lib/psych/nodes/node.rb
index 35de224..7c040ec 100644
--- a/lib/psych/nodes/node.rb
+++ b/lib/psych/nodes/node.rb
@@ -6,6 +6,8 @@ module Psych
# The base class for any Node in a YAML parse tree. This class should
# never be instantiated.
class Node
+ include Enumerable
+
# The children of this node
attr_reader :children
@@ -17,7 +19,12 @@ module Psych
@children = []
end
- def each
+ ###
+ # Iterate over each node in the tree. Yields each node to +block+ depth
+ # first.
+ def each &block
+ return enum_for :each unless block_given?
+ Visitors::DepthFirst.new(block).accept self
end
###
diff --git a/lib/psych/visitors/depth_first.rb b/lib/psych/visitors/depth_first.rb
index f202d4d..c6eb814 100644
--- a/lib/psych/visitors/depth_first.rb
+++ b/lib/psych/visitors/depth_first.rb
@@ -1,8 +1,26 @@
module Psych
module Visitors
class DepthFirst < Psych::Visitors::Visitor
+ def initialize block
+ @block = block
+ end
+
private
+ def nary o
+ o.children.each { |x| visit x }
+ @block.call o
+ end
+ alias :visit_Psych_Nodes_Stream :nary
+ alias :visit_Psych_Nodes_Document :nary
+ alias :visit_Psych_Nodes_Sequence :nary
+ alias :visit_Psych_Nodes_Mapping :nary
+
+ def terminal o
+ @block.call o
+ end
+ alias :visit_Psych_Nodes_Scalar :terminal
+ alias :visit_Psych_Nodes_Alias :terminal
end
end
end
diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb
index 745338a..f8b1585 100644
--- a/lib/psych/visitors/to_ruby.rb
+++ b/lib/psych/visitors/to_ruby.rb
@@ -60,7 +60,7 @@ module Psych
when "tag:yaml.org,2002:float", "!float"
Float(@ss.tokenize(o.value))
when "!ruby/regexp"
- o.value =~ /^\/(.*)\/([mix]*)$/
+ o.value =~ /^\/(.*)\/([mixn]*)$/
source = $1
options = 0
lang = nil
@@ -69,6 +69,7 @@ module Psych
when 'x' then options |= Regexp::EXTENDED
when 'i' then options |= Regexp::IGNORECASE
when 'm' then options |= Regexp::MULTILINE
+ when 'n' then options |= Regexp::NOENCODING
else lang = option
end
end
@@ -187,14 +188,17 @@ module Psych
o.children.each_slice(2) { |k,v|
key = accept(k)
- if key == '<<' && Nodes::Alias === v
- # FIXME: remove this when "<<" syntax is deprecated
- if $VERBOSE
- where = caller.find { |x| x !~ /psych/ }
- warn where
- warn "\"<<: *#{v.anchor}\" is no longer supported, please switch to \"*#{v.anchor}\""
+ if key == '<<'
+ case v
+ when Nodes::Alias
+ hash.merge! accept(v)
+ when Nodes::Sequence
+ accept(v).reverse_each do |value|
+ hash.merge! value
+ end
+ else
+ hash[key] = accept(v)
end
- return accept(v)
else
hash[key] = accept(v)
end
diff --git a/test/psych/nodes/test_enumerable.rb b/test/psych/nodes/test_enumerable.rb
new file mode 100644
index 0000000..57d4e89
--- /dev/null
+++ b/test/psych/nodes/test_enumerable.rb
@@ -0,0 +1,43 @@
+require_relative '../helper'
+
+module Psych
+ module Nodes
+ class TestEnumerable < TestCase
+ def test_includes_enumerable
+ yaml = '--- hello'
+ assert_equal 3, Psych.parse_stream(yaml).to_a.length
+ end
+
+ def test_returns_enumerator
+ yaml = '--- hello'
+ assert_equal 3, Psych.parse_stream(yaml).each.map { |x| x }.length
+ end
+
+ def test_scalar
+ assert_equal 3, calls('--- hello').length
+ end
+
+ def test_sequence
+ assert_equal 4, calls("---\n- hello").length
+ end
+
+ def test_mapping
+ assert_equal 5, calls("---\nhello: world").length
+ end
+
+ def test_alias
+ assert_equal 5, calls("--- &yay\n- foo\n- *yay\n").length
+ end
+
+ private
+
+ def calls yaml
+ calls = []
+ Psych.parse_stream(yaml).each do |node|
+ calls << node
+ end
+ calls
+ end
+ end
+ end
+end
diff --git a/test/psych/test_json_tree.rb b/test/psych/test_json_tree.rb
index 5fcb0d6..423a528 100644
--- a/test/psych/test_json_tree.rb
+++ b/test/psych/test_json_tree.rb
@@ -41,8 +41,9 @@ module Psych
end
def test_time
- time = Time.new(2010, 10, 10).utc
- assert_equal "{\"a\": \"2010-10-10 07:00:00.000000000Z\"}\n", Psych.to_json({'a' => time })
+ time = Time.utc(2010, 10, 10)
+ assert_equal "{\"a\": \"2010-10-10 00:00:00.000000000Z\"}\n",
+Psych.to_json({'a' => time })
end
def test_datetime
diff --git a/test/psych/test_merge_keys.rb b/test/psych/test_merge_keys.rb
new file mode 100644
index 0000000..fef8892
--- /dev/null
+++ b/test/psych/test_merge_keys.rb
@@ -0,0 +1,72 @@
+require_relative 'helper'
+
+module Psych
+ class TestMergeKeys < TestCase
+ # [ruby-core:34679]
+ def test_merge_key
+ yaml = <<-eoyml
+foo: &foo
+ hello: world
+bar:
+ << : *foo
+ baz: boo
+ eoyml
+
+ hash = {
+ "foo" => { "hello" => "world"},
+ "bar" => { "hello" => "world", "baz" => "boo" } }
+ assert_equal hash, Psych.load(yaml)
+ end
+
+ def test_multiple_maps
+ yaml = <<-eoyaml
+---
+- &CENTER { x: 1, y: 2 }
+- &LEFT { x: 0, y: 2 }
+- &BIG { r: 10 }
+- &SMALL { r: 1 }
+
+# All the following maps are equal:
+
+- # Merge multiple maps
+ << : [ *CENTER, *BIG ]
+ label: center/big
+ eoyaml
+
+ hash = {
+ 'x' => 1,
+ 'y' => 2,
+ 'r' => 10,
+ 'label' => 'center/big'
+ }
+
+ assert_equal hash, Psych.load(yaml)[4]
+ end
+
+ def test_override
+ yaml = <<-eoyaml
+---
+- &CENTER { x: 1, y: 2 }
+- &LEFT { x: 0, y: 2 }
+- &BIG { r: 10 }
+- &SMALL { r: 1 }
+
+# All the following maps are equal:
+
+- # Override
+ << : [ *BIG, *LEFT, *SMALL ]
+ x: 1
+ label: center/big
+ eoyaml
+
+ hash = {
+ 'x' => 1,
+ 'y' => 2,
+ 'r' => 10,
+ 'label' => 'center/big'
+ }
+
+ assert_equal hash, Psych.load(yaml)[4]
+ end
+ end
+end
diff --git a/test/psych/test_parser.rb b/test/psych/test_parser.rb
index cd22914..a60a0c6 100644
--- a/test/psych/test_parser.rb
+++ b/test/psych/test_parser.rb
@@ -128,6 +128,33 @@ module Psych
end
end
+ def test_syntax_error_twice
+ assert_raises(Psych::SyntaxError) do
+ @parser.parse("---\n\"foo\"\n\"bar\"\n")
+ end
+
+ assert_raises(Psych::SyntaxError) do
+ @parser.parse("---\n\"foo\"\n\"bar\"\n")
+ end
+ end
+
+ def test_syntax_error_has_path_for_string
+ e = assert_raises(Psych::SyntaxError) do
+ @parser.parse("---\n\"foo\"\n\"bar\"\n")
+ end
+ assert_match '(<unknown>):', e.message
+ end
+
+ def test_syntax_error_has_path_for_io
+ io = StringIO.new "---\n\"foo\"\n\"bar\"\n"
+ def io.path; "hello!"; end
+
+ e = assert_raises(Psych::SyntaxError) do
+ @parser.parse(io)
+ end
+ assert_match "(#{io.path}):", e.message
+ end
+
def test_mapping_end
@parser.parse("---\n!!map { key: value }")
assert_called :end_mapping
diff --git a/test/psych/test_yaml.rb b/test/psych/test_yaml.rb
index 45cd39d..20bf26e 100644
--- a/test/psych/test_yaml.rb
+++ b/test/psych/test_yaml.rb
@@ -13,6 +13,11 @@ class Psych_Unit_Tests < Psych::TestCase
def teardown
Psych.domain_types.clear
end
+
+ # [ruby-core:34969]
+ def test_regexp_with_n
+ assert_cycle(Regexp.new('',0,'n'))
+ end
#
# Tests modified from 00basic.t in Psych.pm
#
diff --git a/test/psych/visitors/test_depth_first.rb b/test/psych/visitors/test_depth_first.rb
index a783960..a84f5b6 100644
--- a/test/psych/visitors/test_depth_first.rb
+++ b/test/psych/visitors/test_depth_first.rb
@@ -3,21 +3,47 @@ require_relative '../helper'
module Psych
module Visitors
class TestDepthFirst < TestCase
+ class Collector < Struct.new(:calls)
+ def initialize(calls = [])
+ super
+ end
+
+ def call obj
+ calls << obj
+ end
+ end
+
def test_scalar
- collector = Class.new(Struct.new(:calls)) {
- def initialize(calls = [])
- super
- end
-
- def call obj
- calls << obj
- end
- }.new
- visitor = Visitors::DepthFirst.new collector
- visitor.accept Psych.parse '--- hello'
+ collector = Collector.new
+ visitor = Visitors::DepthFirst.new collector
+ visitor.accept Psych.parse_stream '--- hello'
assert_equal 3, collector.calls.length
end
+
+ def test_sequence
+ collector = Collector.new
+ visitor = Visitors::DepthFirst.new collector
+ visitor.accept Psych.parse_stream "---\n- hello"
+
+ assert_equal 4, collector.calls.length
+ end
+
+ def test_mapping
+ collector = Collector.new
+ visitor = Visitors::DepthFirst.new collector
+ visitor.accept Psych.parse_stream "---\nhello: world"
+
+ assert_equal 5, collector.calls.length
+ end
+
+ def test_alias
+ collector = Collector.new
+ visitor = Visitors::DepthFirst.new collector
+ visitor.accept Psych.parse_stream "--- &yay\n- foo\n- *yay\n"
+
+ assert_equal 5, collector.calls.length
+ end
end
end
end