summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rdoc9
-rw-r--r--lib/psych/tree_builder.rb4
-rw-r--r--lib/psych/visitors/to_ruby.rb29
-rw-r--r--lib/psych/visitors/yaml_tree.rb14
-rw-r--r--test/psych/test_object_references.rb67
5 files changed, 103 insertions, 20 deletions
diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc
index 06ace09..baa7a72 100644
--- a/CHANGELOG.rdoc
+++ b/CHANGELOG.rdoc
@@ -1,3 +1,12 @@
+Wed Nov 9 04:52:16 2011 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/tree_builder.rb: dump complex numbers,
+ rationals, etc with reference ids.
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
+ * ext/psych/lib/psych/visitors/to_ruby.rb: loading complex numbers,
+ rationals, etc with reference ids.
+ * test/psych/test_object_references.rb: corresponding tests
+
Mon Nov 7 20:31:52 2011 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/lib/psych/scalar_scanner.rb: make sure strings that look
diff --git a/lib/psych/tree_builder.rb b/lib/psych/tree_builder.rb
index 8b4e972..c8f3447 100644
--- a/lib/psych/tree_builder.rb
+++ b/lib/psych/tree_builder.rb
@@ -72,7 +72,9 @@ module Psych
end
def scalar value, anchor, tag, plain, quoted, style
- @last.children << Nodes::Scalar.new(value,anchor,tag,plain,quoted,style)
+ s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style)
+ @last.children << s
+ s
end
def alias anchor
diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb
index 5cef198..4267f4d 100644
--- a/lib/psych/visitors/to_ruby.rb
+++ b/lib/psych/visitors/to_ruby.rb
@@ -31,9 +31,7 @@ module Psych
result
end
- def visit_Psych_Nodes_Scalar o
- @st[o.anchor] = o.value if o.anchor
-
+ def deserialize o
if klass = Psych.load_tags[o.tag]
instance = klass.allocate
@@ -92,6 +90,11 @@ module Psych
@ss.tokenize o.value
end
end
+ private :deserialize
+
+ def visit_Psych_Nodes_Scalar o
+ register o, deserialize(o)
+ end
def visit_Psych_Nodes_Sequence o
if klass = Psych.load_tags[o.tag]
@@ -108,15 +111,13 @@ module Psych
case o.tag
when '!omap', 'tag:yaml.org,2002:omap'
- map = Psych::Omap.new
- @st[o.anchor] = map if o.anchor
+ map = register(o, Psych::Omap.new)
o.children.each { |a|
map[accept(a.children.first)] = accept a.children.last
}
map
else
- list = []
- @st[o.anchor] = list if o.anchor
+ list = register(o, [])
o.children.each { |c| list.push accept c }
list
end
@@ -135,8 +136,7 @@ module Psych
klass = resolve_class($1)
if klass
- s = klass.allocate
- @st[o.anchor] = s if o.anchor
+ s = register(o, klass.allocate)
members = {}
struct_members = s.members.map { |x| x.to_sym }
@@ -158,7 +158,7 @@ module Psych
when '!ruby/range'
h = Hash[*o.children.map { |c| accept c }]
- Range.new(h['begin'], h['end'], h['excl'])
+ register o, Range.new(h['begin'], h['end'], h['excl'])
when /^!ruby\/exception:?(.*)?$/
h = Hash[*o.children.map { |c| accept c }]
@@ -177,11 +177,11 @@ module Psych
when '!ruby/object:Complex'
h = Hash[*o.children.map { |c| accept c }]
- Complex(h['real'], h['image'])
+ register o, Complex(h['real'], h['image'])
when '!ruby/object:Rational'
h = Hash[*o.children.map { |c| accept c }]
- Rational(h['numerator'], h['denominator'])
+ register o, Rational(h['numerator'], h['denominator'])
when /^!ruby\/object:?(.*)?$/
name = $1 || 'Object'
@@ -209,6 +209,11 @@ module Psych
end
private
+ def register node, object
+ @st[node.anchor] = object if node.anchor
+ object
+ end
+
def revive_hash hash, o
@st[o.anchor] = hash if o.anchor
diff --git a/lib/psych/visitors/yaml_tree.rb b/lib/psych/visitors/yaml_tree.rb
index 5a09285..523ad77 100644
--- a/lib/psych/visitors/yaml_tree.rb
+++ b/lib/psych/visitors/yaml_tree.rb
@@ -159,13 +159,13 @@ module Psych
end
def visit_Regexp o
- @emitter.scalar o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY
+ register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
end
def visit_DateTime o
formatted = format_time o.to_time
tag = '!ruby/object:DateTime'
- @emitter.scalar formatted, nil, tag, false, false, Nodes::Scalar::ANY
+ register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY)
end
def visit_Time o
@@ -174,7 +174,7 @@ module Psych
end
def visit_Rational o
- @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK)
+ register o, @emitter.start_mapping(nil, '!ruby/object:Rational', false, Nodes::Mapping::BLOCK)
[
'denominator', o.denominator.to_s,
@@ -187,7 +187,7 @@ module Psych
end
def visit_Complex o
- @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK)
+ register o, @emitter.start_mapping(nil, '!ruby/object:Complex', false, Nodes::Mapping::BLOCK)
['real', o.real.to_s, 'image', o.imag.to_s].each do |m|
@emitter.scalar m, nil, nil, true, false, Nodes::Scalar::ANY
@@ -255,16 +255,16 @@ module Psych
def visit_Module o
raise TypeError, "can't dump anonymous module: #{o}" unless o.name
- @emitter.scalar o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED
+ register o, @emitter.scalar(o.name, nil, '!ruby/module', false, false, Nodes::Scalar::SINGLE_QUOTED)
end
def visit_Class o
raise TypeError, "can't dump anonymous class: #{o}" unless o.name
- @emitter.scalar o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED
+ register o, @emitter.scalar(o.name, nil, '!ruby/class', false, false, Nodes::Scalar::SINGLE_QUOTED)
end
def visit_Range o
- @emitter.start_mapping nil, '!ruby/range', false, Nodes::Mapping::BLOCK
+ register o, @emitter.start_mapping(nil, '!ruby/range', false, Nodes::Mapping::BLOCK)
['begin', o.begin, 'end', o.end, 'excl', o.exclude_end?].each do |m|
accept m
end
diff --git a/test/psych/test_object_references.rb b/test/psych/test_object_references.rb
new file mode 100644
index 0000000..77cc96e
--- /dev/null
+++ b/test/psych/test_object_references.rb
@@ -0,0 +1,67 @@
+require 'psych/helper'
+
+module Psych
+ class TestObjectReferences < TestCase
+ def test_range_has_references
+ assert_reference_trip 1..2
+ end
+
+ def test_module_has_references
+ assert_reference_trip Psych
+ end
+
+ def test_class_has_references
+ assert_reference_trip TestObjectReferences
+ end
+
+ def test_rational_has_references
+ assert_reference_trip Rational('1.2')
+ end
+
+ def test_complex_has_references
+ assert_reference_trip Complex(1, 2)
+ end
+
+ def test_datetime_has_references
+ assert_reference_trip DateTime.now
+ end
+
+ def assert_reference_trip obj
+ yml = Psych.dump([obj, obj])
+ assert_match(/\*\d+/, yml)
+ data = Psych.load yml
+ assert_equal data.first.object_id, data.last.object_id
+ end
+
+ def test_float_references
+ data = Psych.load <<-eoyml
+---
+- &name 1.2
+- *name
+ eoyml
+ assert_equal data.first, data.last
+ assert_equal data.first.object_id, data.last.object_id
+ end
+
+ def test_binary_references
+ data = Psych.load <<-eoyml
+---
+- &name !binary |-
+ aGVsbG8gd29ybGQh
+- *name
+ eoyml
+ assert_equal data.first, data.last
+ assert_equal data.first.object_id, data.last.object_id
+ end
+
+ def test_regexp_references
+ data = Psych.load <<-eoyml
+---
+- &name !ruby/regexp /pattern/i
+- *name
+ eoyml
+ assert_equal data.first, data.last
+ assert_equal data.first.object_id, data.last.object_id
+ end
+ end
+end