summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2014-12-01 13:22:26 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2014-12-01 13:22:26 -0800
commit002cc29fcb92b72a02a0ca03b0873ca4d2ace67b (patch)
treeb31a5f26799736306385d03edd6cdd390541908c
parentfc31992c397e936e6e5c2f45ec8984a7bc035b47 (diff)
parentdbbd9e189d39de48432b89260236250ad10d2a14 (diff)
downloadpsych-002cc29fcb92b72a02a0ca03b0873ca4d2ace67b.tar.gz
Merge branch 'master' of github.com:tenderlove/psych
* 'master' of github.com:tenderlove/psych: backport r48512 from ruby/ruby trunk. Add changelog for 2a4d9568f7d5d19c00231cf48eb855cc45ec3394 backport r48214 from ruby/ruby trunk. Allow dumping any BasicObject that defines #marshal_dump or #marshal_load
-rw-r--r--CHANGELOG.rdoc7
-rw-r--r--lib/psych/visitors/to_ruby.rb15
-rw-r--r--lib/psych/visitors/yaml_tree.rb14
-rw-r--r--test/psych/json/test_stream.rb2
-rw-r--r--test/psych/test_emitter.rb3
-rw-r--r--test/psych/test_json_tree.rb2
-rw-r--r--test/psych/test_marshalable.rb54
7 files changed, 93 insertions, 4 deletions
diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc
index 5df3bcb..c6f13c2 100644
--- a/CHANGELOG.rdoc
+++ b/CHANGELOG.rdoc
@@ -1,3 +1,10 @@
+Sun Nov 23 13:11:24 2014 Sean Griffin <sean@thoughtbot.com>
+
+ * lib/psych/visitors/to_ruby.rb: Allow loading any BasicObject that
+ defines #marshal_load, fixes #100
+ * lib/psych/visitors/yaml_tree.rb: Allow dumping any BasicObject that
+ defines #marshal_dump
+
Sat Aug 30 06:39:48 2014 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/lib/psych/visitors/yaml_tree.rb: fix NameError dumping and
diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb
index e74d5d4..e696ebd 100644
--- a/lib/psych/visitors/to_ruby.rb
+++ b/lib/psych/visitors/to_ruby.rb
@@ -271,6 +271,21 @@ module Psych
end
map
+ when /^!ruby\/marshalable:(.*)$/
+ name = $1
+ klass = resolve_class(name)
+ obj = register(o, klass.allocate)
+
+ if obj.respond_to?(:init_with)
+ init_with(obj, revive_hash({}, o), o)
+ elsif obj.respond_to?(:marshal_load)
+ marshal_data = o.children.map(&method(:accept))
+ obj.marshal_load(marshal_data)
+ obj
+ else
+ raise ArgumentError, "Cannot deserialize #{name}"
+ end
+
else
revive_hash(register(o, {}), o)
end
diff --git a/lib/psych/visitors/yaml_tree.rb b/lib/psych/visitors/yaml_tree.rb
index 3f2427b..989e1f0 100644
--- a/lib/psych/visitors/yaml_tree.rb
+++ b/lib/psych/visitors/yaml_tree.rb
@@ -27,6 +27,8 @@ module Psych
def key? target
@obj_to_node.key? target.object_id
+ rescue NoMethodError
+ false
end
def id_for target
@@ -411,6 +413,18 @@ module Psych
end
end
+ def visit_BasicObject o
+ tag = Psych.dump_tags[o.class]
+ tag ||= "!ruby/marshalable:#{o.class.name}"
+
+ map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
+ register(o, map)
+
+ o.marshal_dump.each(&method(:accept))
+
+ @emitter.end_mapping
+ end
+
private
# FIXME: Remove the index and count checks in Psych 3.0
NULL = "\x00"
diff --git a/test/psych/json/test_stream.rb b/test/psych/json/test_stream.rb
index 4690ad2..b0c33e6 100644
--- a/test/psych/json/test_stream.rb
+++ b/test/psych/json/test_stream.rb
@@ -65,7 +65,7 @@ module Psych
@stream.push list
json = @io.string
- assert_match(/]$/, json)
+ assert_match(/\]$/, json)
assert_match(/^--- \[/, json)
assert_match(/["]one["]/, json)
assert_match(/["]two["]/, json)
diff --git a/test/psych/test_emitter.rb b/test/psych/test_emitter.rb
index 0554ae5..1c96c12 100644
--- a/test/psych/test_emitter.rb
+++ b/test/psych/test_emitter.rb
@@ -11,8 +11,7 @@ module Psych
end
def test_line_width
- assert_equal 0, @emitter.line_width
- assert_equal 10, @emitter.line_width = 10
+ @emitter.line_width = 10
assert_equal 10, @emitter.line_width
end
diff --git a/test/psych/test_json_tree.rb b/test/psych/test_json_tree.rb
index 60f8321..a23fc1a 100644
--- a/test/psych/test_json_tree.rb
+++ b/test/psych/test_json_tree.rb
@@ -45,7 +45,7 @@ module Psych
def test_list_to_json
list = %w{ one two }
json = Psych.to_json(list)
- assert_match(/]$/, json)
+ assert_match(/\]$/, json)
assert_match(/^\[/, json)
assert_match(/"one"/, json)
assert_match(/"two"/, json)
diff --git a/test/psych/test_marshalable.rb b/test/psych/test_marshalable.rb
new file mode 100644
index 0000000..7df74ee
--- /dev/null
+++ b/test/psych/test_marshalable.rb
@@ -0,0 +1,54 @@
+require_relative 'helper'
+require 'delegate'
+
+module Psych
+ class TestMarshalable < TestCase
+ def test_objects_defining_marshal_dump_and_marshal_load_can_be_dumped
+ sd = SimpleDelegator.new(1)
+ loaded = Psych.load(Psych.dump(sd))
+
+ assert_instance_of(SimpleDelegator, loaded)
+ assert_equal(sd, loaded)
+ end
+
+ class PsychCustomMarshalable < BasicObject
+ attr_reader :foo
+
+ def initialize(foo)
+ @foo = foo
+ end
+
+ def marshal_dump
+ [foo]
+ end
+
+ def mashal_load(data)
+ @foo = data[0]
+ end
+
+ def init_with(coder)
+ @foo = coder['foo']
+ end
+
+ def encode_with(coder)
+ coder['foo'] = 2
+ end
+
+ def respond_to?(method)
+ [:marshal_dump, :marshal_load, :init_with, :encode_with].include?(method)
+ end
+
+ def class
+ PsychCustomMarshalable
+ end
+ end
+
+ def test_init_with_takes_priority_over_marshal_methods
+ obj = PsychCustomMarshalable.new(1)
+ loaded = Psych.load(Psych.dump(obj))
+
+ assert(PsychCustomMarshalable === loaded)
+ assert_equal(2, loaded.foo)
+ end
+ end
+end