summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2015-01-08 14:21:34 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2015-01-08 14:21:34 -0800
commite3b2c1c9f5c3a6144a4b02d46a3677df9826a1ab (patch)
tree8976c31dc44648187f2bcceec3c69297df658d67
parent010d0c37bde30c5f347ebfd69087a487ff8b8bbb (diff)
parentaf308f8307899cb9e1c0fffea4bce3110a1c3926 (diff)
downloadpsych-e3b2c1c9f5c3a6144a4b02d46a3677df9826a1ab.zip
Merge branch 'master' into jirutka-patch-1
* master: (21 commits) * ext/psych/lib/psych/visitors/to_ruby.rb: call `allocate` on hash subclasses. Fixes github.com/tenderlove/psych/issues/196 * ext/psych/lib/psych/visitors/to_ruby.rb: revive hashes with ivars removed isolate task removed isolate plugin added minitest dependency into gemspec added install task into travis added ruby-head env bumping version to 2.0.8 fixed build error caused by trunk changes bumping version to 2.0.7 merging from ruby trunk 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 bumping version * ext/psych/lib/psych/visitors/yaml_tree.rb: fix NameError dumping and loading. Fixes GH #85. Thanks @brentdax for the patch! * test/psych/test_exception.rb: test for fix * ext/psych/lib/psych/scalar_scanner.rb: fix loading strings that look like integers but have a newline. Fixes GH #189 * test/psych/test_string.rb: test for fix * ext/psych/lib/psych/visitors/to_ruby.rb: merge keys with a hash should merge the hash in to the parent. * test/psych/test_merge_keys.rb: test for change. Fixes GH #202 * ext/psych/lib/psych/visitors/to_ruby.rb: quoted "<<" strings should not be treated as merge keys. * ext/psych/lib/psych/visitors/yaml_tree.rb: hashes with keys containing "<<" should roundtrip. * test/psych/test_merge_keys.rb: test for change. Fixes GH #203 ... Conflicts: lib/psych/visitors/yaml_tree.rb
-rw-r--r--.travis.yml5
-rw-r--r--CHANGELOG.rdoc49
-rw-r--r--Manifest.txt1
-rw-r--r--Rakefile4
-rw-r--r--ext/psych/psych.c2
-rw-r--r--ext/psych/psych_emitter.c56
-rw-r--r--ext/psych/psych_emitter.h2
-rw-r--r--ext/psych/psych_parser.c26
-rw-r--r--ext/psych/psych_parser.h2
-rw-r--r--lib/psych.rb2
-rw-r--r--lib/psych/scalar_scanner.rb2
-rw-r--r--lib/psych/visitors/to_ruby.rb35
-rw-r--r--lib/psych/visitors/yaml_tree.rb83
-rw-r--r--test/psych/json/test_stream.rb2
-rw-r--r--test/psych/test_emitter.rb3
-rw-r--r--test/psych/test_exception.rb6
-rw-r--r--test/psych/test_hash.rb44
-rw-r--r--test/psych/test_json_tree.rb2
-rw-r--r--test/psych/test_marshalable.rb54
-rw-r--r--test/psych/test_merge_keys.rb30
-rw-r--r--test/psych/test_string.rb4
21 files changed, 367 insertions, 47 deletions
diff --git a/.travis.yml b/.travis.yml
index d995250..2c45195 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,8 +3,9 @@ rvm:
- 1.9.3
- 2.0.0
- 2.1.0
+ - ruby-head
before_script:
- - gem install isolate
- gem install hoe
- gem install rake-compiler
-script: rake isolate test
+ - gem install minitest -v '~> 4.0'
+script: rake test
diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc
index cd87b92..4c04f1a 100644
--- a/CHANGELOG.rdoc
+++ b/CHANGELOG.rdoc
@@ -1,3 +1,52 @@
+Fri Jan 9 07:13:55 2015 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: call `allocate` on hash
+ subclasses. Fixes github.com/tenderlove/psych/issues/196
+
+ * test/psych/test_hash.rb: test for change
+
+Fri Jan 9 06:58:43 2015 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: revive hashes with ivars
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: dump hashes with ivars.
+ Fixes github.com/psych/issues/43
+
+ * test/psych/test_hash.rb: test for change
+
+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
+ loading. Fixes GH #85. Thanks @brentdax for the patch!
+ * test/psych/test_exception.rb: test for fix
+
+Sat Aug 30 06:23:40 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/scalar_scanner.rb: fix loading strings that
+ look like integers but have a newline. Fixes GH #189
+ * test/psych/test_string.rb: test for fix
+
+Sat Aug 30 06:10:39 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: merge keys with a hash
+ should merge the hash in to the parent.
+ * test/psych/test_merge_keys.rb: test for change. Fixes GH #202
+
+Sat Aug 30 06:00:26 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: quoted "<<" strings
+ should not be treated as merge keys.
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: hashes with keys
+ containing "<<" should roundtrip.
+ * test/psych/test_merge_keys.rb: test for change. Fixes GH #203
+
Wed Aug 6 03:41:21 2014 Aaron Patterson <aaron@tenderlovemaking.com>
* ext/psych/lib/psych/visitors/to_ruby.rb: backwards compatibility for
diff --git a/Manifest.txt b/Manifest.txt
index b1ed1d6..264b848 100644
--- a/Manifest.txt
+++ b/Manifest.txt
@@ -79,7 +79,6 @@ test/psych/test_deprecated.rb
test/psych/test_document.rb
test/psych/test_emitter.rb
test/psych/test_encoding.rb
-test/psych/test_engine_manager.rb
test/psych/test_exception.rb
test/psych/test_hash.rb
test/psych/test_json_tree.rb
diff --git a/Rakefile b/Rakefile
index fd20115..7c15d95 100644
--- a/Rakefile
+++ b/Rakefile
@@ -9,9 +9,10 @@ class Hoe
end
gem 'rake-compiler', '>= 0.4.1'
+gem 'minitest', '~> 4.0'
require "rake/extensiontask"
-Hoe.plugin :doofus, :git, :gemspec, :isolate
+Hoe.plugin :doofus, :git, :gemspec
$hoe = Hoe.spec 'psych' do
license 'MIT'
@@ -23,6 +24,7 @@ $hoe = Hoe.spec 'psych' do
self.testlib = :minitest
extra_dev_deps << ['rake-compiler', '>= 0.4.1']
+ extra_dev_deps << ['minitest', '~> 4.0']
self.spec_extras = {
:extensions => ["ext/psych/extconf.rb"],
diff --git a/ext/psych/psych.c b/ext/psych/psych.c
index 69ff1d8..3bb59bf 100644
--- a/ext/psych/psych.c
+++ b/ext/psych/psych.c
@@ -20,7 +20,7 @@ static VALUE libyaml_version(VALUE module)
VALUE mPsych;
-void Init_psych()
+void Init_psych(void)
{
mPsych = rb_define_module("Psych");
diff --git a/ext/psych/psych_emitter.c b/ext/psych/psych_emitter.c
index f0d0326..4ba2381 100644
--- a/ext/psych/psych_emitter.c
+++ b/ext/psych/psych_emitter.c
@@ -29,6 +29,24 @@ static void dealloc(void * ptr)
xfree(emitter);
}
+#if 0
+static size_t memsize(const void *ptr)
+{
+ const yaml_emitter_t *emitter = ptr;
+ /* TODO: calculate emitter's size */
+ return 0;
+}
+#endif
+
+static const rb_data_type_t psych_emitter_type = {
+ "Psych/emitter",
+ {0, dealloc, 0,},
+ 0, 0,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ RUBY_TYPED_FREE_IMMEDIATELY,
+#endif
+};
+
static VALUE allocate(VALUE klass)
{
yaml_emitter_t * emitter;
@@ -39,7 +57,7 @@ static VALUE allocate(VALUE klass)
yaml_emitter_set_unicode(emitter, 1);
yaml_emitter_set_indent(emitter, 2);
- return Data_Wrap_Struct(klass, 0, dealloc, emitter);
+ return TypedData_Wrap_Struct(klass, &psych_emitter_type, emitter);
}
/* call-seq: Psych::Emitter.new(io, options = Psych::Emitter::OPTIONS)
@@ -54,7 +72,7 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self)
VALUE indent;
VALUE canonical;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
if (rb_scan_args(argc, argv, "11", &io, &options) == 2) {
line_width = rb_funcall(options, id_line_width, 0);
@@ -81,7 +99,7 @@ static VALUE start_stream(VALUE self, VALUE encoding)
{
yaml_emitter_t * emitter;
yaml_event_t event;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
Check_Type(encoding, T_FIXNUM);
yaml_stream_start_event_initialize(&event, (yaml_encoding_t)NUM2INT(encoding));
@@ -101,7 +119,7 @@ static VALUE end_stream(VALUE self)
{
yaml_emitter_t * emitter;
yaml_event_t event;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_stream_end_event_initialize(&event);
@@ -124,7 +142,7 @@ static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp)
yaml_tag_directive_t * tail = NULL;
yaml_event_t event;
yaml_version_directive_t version_directive;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
Check_Type(version, T_ARRAY);
@@ -198,7 +216,7 @@ static VALUE end_document(VALUE self, VALUE imp)
{
yaml_emitter_t * emitter;
yaml_event_t event;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_document_end_event_initialize(&event, imp ? 1 : 0);
@@ -228,7 +246,7 @@ static VALUE scalar(
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *encoding;
#endif
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
Check_Type(value, T_STRING);
@@ -295,7 +313,7 @@ static VALUE start_sequence(
}
#endif
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_sequence_start_event_initialize(
&event,
@@ -320,7 +338,7 @@ static VALUE end_sequence(VALUE self)
{
yaml_emitter_t * emitter;
yaml_event_t event;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_sequence_end_event_initialize(&event);
@@ -348,7 +366,7 @@ static VALUE start_mapping(
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *encoding;
#endif
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
#ifdef HAVE_RUBY_ENCODING_H
encoding = rb_utf8_encoding();
@@ -387,7 +405,7 @@ static VALUE end_mapping(VALUE self)
{
yaml_emitter_t * emitter;
yaml_event_t event;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_mapping_end_event_initialize(&event);
@@ -406,7 +424,7 @@ static VALUE alias(VALUE self, VALUE anchor)
{
yaml_emitter_t * emitter;
yaml_event_t event;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
#ifdef HAVE_RUBY_ENCODING_H
if(!NIL_P(anchor)) {
@@ -432,7 +450,7 @@ static VALUE alias(VALUE self, VALUE anchor)
static VALUE set_canonical(VALUE self, VALUE style)
{
yaml_emitter_t * emitter;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_emitter_set_canonical(emitter, Qtrue == style ? 1 : 0);
@@ -446,7 +464,7 @@ static VALUE set_canonical(VALUE self, VALUE style)
static VALUE canonical(VALUE self)
{
yaml_emitter_t * emitter;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
return (emitter->canonical == 0) ? Qfalse : Qtrue;
}
@@ -459,7 +477,7 @@ static VALUE canonical(VALUE self)
static VALUE set_indentation(VALUE self, VALUE level)
{
yaml_emitter_t * emitter;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_emitter_set_indent(emitter, NUM2INT(level));
@@ -473,7 +491,7 @@ static VALUE set_indentation(VALUE self, VALUE level)
static VALUE indentation(VALUE self)
{
yaml_emitter_t * emitter;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
return INT2NUM(emitter->best_indent);
}
@@ -485,7 +503,7 @@ static VALUE indentation(VALUE self)
static VALUE line_width(VALUE self)
{
yaml_emitter_t * emitter;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
return INT2NUM(emitter->best_width);
}
@@ -497,14 +515,14 @@ static VALUE line_width(VALUE self)
static VALUE set_line_width(VALUE self, VALUE width)
{
yaml_emitter_t * emitter;
- Data_Get_Struct(self, yaml_emitter_t, emitter);
+ TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_emitter_set_width(emitter, NUM2INT(width));
return width;
}
-void Init_psych_emitter()
+void Init_psych_emitter(void)
{
VALUE psych = rb_define_module("Psych");
VALUE handler = rb_define_class_under(psych, "Handler", rb_cObject);
diff --git a/ext/psych/psych_emitter.h b/ext/psych/psych_emitter.h
index 560451e..4c1482a 100644
--- a/ext/psych/psych_emitter.h
+++ b/ext/psych/psych_emitter.h
@@ -3,6 +3,6 @@
#include <psych.h>
-void Init_psych_emitter();
+void Init_psych_emitter(void);
#endif
diff --git a/ext/psych/psych_parser.c b/ext/psych/psych_parser.c
index 8c65ce1..faae460 100644
--- a/ext/psych/psych_parser.c
+++ b/ext/psych/psych_parser.c
@@ -49,6 +49,24 @@ static void dealloc(void * ptr)
xfree(parser);
}
+#if 0
+static size_t memsize(const void *ptr)
+{
+ const yaml_parser_t *parser = ptr;
+ /* TODO: calculate parser's size */
+ return 0;
+}
+#endif
+
+static const rb_data_type_t psych_parser_type = {
+ "Psych/parser",
+ {0, dealloc, 0,},
+ 0, 0,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ RUBY_TYPED_FREE_IMMEDIATELY,
+#endif
+};
+
static VALUE allocate(VALUE klass)
{
yaml_parser_t * parser;
@@ -56,7 +74,7 @@ static VALUE allocate(VALUE klass)
parser = xmalloc(sizeof(yaml_parser_t));
yaml_parser_initialize(parser);
- return Data_Wrap_Struct(klass, 0, dealloc, parser);
+ return TypedData_Wrap_Struct(klass, &psych_parser_type, parser);
}
static VALUE make_exception(yaml_parser_t * parser, VALUE path)
@@ -248,7 +266,7 @@ static VALUE parse(int argc, VALUE *argv, VALUE self)
path = rb_str_new2("<unknown>");
}
- Data_Get_Struct(self, yaml_parser_t, parser);
+ TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser);
yaml_parser_delete(parser);
yaml_parser_initialize(parser);
@@ -526,7 +544,7 @@ static VALUE mark(VALUE self)
VALUE args[3];
yaml_parser_t * parser;
- Data_Get_Struct(self, 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] = INT2NUM(parser->mark.index);
args[1] = INT2NUM(parser->mark.line);
@@ -535,7 +553,7 @@ static VALUE mark(VALUE self)
return rb_class_new_instance(3, args, mark_klass);
}
-void Init_psych_parser()
+void Init_psych_parser(void)
{
#if 0
mPsych = rb_define_module("Psych");
diff --git a/ext/psych/psych_parser.h b/ext/psych/psych_parser.h
index 25e896f..beb3dd0 100644
--- a/ext/psych/psych_parser.h
+++ b/ext/psych/psych_parser.h
@@ -1,6 +1,6 @@
#ifndef PSYCH_PARSER_H
#define PSYCH_PARSER_H
-void Init_psych_parser();
+void Init_psych_parser(void);
#endif
diff --git a/lib/psych.rb b/lib/psych.rb
index 41d40a5..1933437 100644
--- a/lib/psych.rb
+++ b/lib/psych.rb
@@ -217,7 +217,7 @@ require 'psych/class_loader'
module Psych
# The version is Psych you're using
- VERSION = '2.0.5'
+ VERSION = '2.0.8'
# The version of libyaml Psych is using
LIBYAML_VERSION = Psych.libyaml_version.join '.'
diff --git a/lib/psych/scalar_scanner.rb b/lib/psych/scalar_scanner.rb
index 3fc9edd..9300790 100644
--- a/lib/psych/scalar_scanner.rb
+++ b/lib/psych/scalar_scanner.rb
@@ -37,7 +37,7 @@ module Psych
case string
# Check for a String type, being careful not to get caught by hash keys, hex values, and
# special floats (e.g., -.inf).
- when /^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/
+ when /^[^\d\.:-]?[A-Za-z_\s!@#\$%\^&\*\(\)\{\}\<\>\|\/\\~;=]+/, /\n/
if string.length > 5
@string_cache[string] = true
return string
diff --git a/lib/psych/visitors/to_ruby.rb b/lib/psych/visitors/to_ruby.rb
index 234cabc..f353e9c 100644
--- a/lib/psych/visitors/to_ruby.rb
+++ b/lib/psych/visitors/to_ruby.rb
@@ -261,8 +261,22 @@ module Psych
end
set
+ when /^!ruby\/hash-with-ivars(?::(.*))?$/
+ hash = $1 ? resolve_class($1).allocate : {}
+ o.children.each_slice(2) do |key, value|
+ case key.value
+ when 'elements'
+ revive_hash hash, value
+ when 'ivars'
+ value.children.each_slice(2) do |k,v|
+ hash.instance_variable_set accept(k), accept(v)
+ end
+ end
+ end
+ hash
+
when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/
- revive_hash register(o, resolve_class($1).new), o
+ revive_hash register(o, resolve_class($1).allocate), o
when '!omap', 'tag:yaml.org,2002:omap'
map = register(o, class_loader.psych_omap.new)
@@ -271,6 +285,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
@@ -305,9 +334,9 @@ module Psych
key = accept(k)
val = accept(v)
- if key == '<<'
+ if key == '<<' && k.tag != "tag:yaml.org,2002:str"
case v
- when Nodes::Alias
+ when Nodes::Alias, Nodes::Mapping
begin
hash.merge! val
rescue TypeError
diff --git a/lib/psych/visitors/yaml_tree.rb b/lib/psych/visitors/yaml_tree.rb
index f40538a..3a6bd1d 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
@@ -211,6 +213,25 @@ module Psych
@emitter.end_mapping
end
+ def visit_NameError o
+ tag = ['!ruby/exception', o.class.name].join ':'
+
+ @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK
+
+ {
+ 'message' => o.message.to_s,
+ 'backtrace' => private_iv_get(o, 'backtrace'),
+ }.each do |k,v|
+ next unless v
+ @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY
+ accept v
+ end
+
+ dump_ivars o
+
+ @emitter.end_mapping
+ end
+
def visit_Regexp o
register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY)
end
@@ -291,6 +312,11 @@ module Psych
quote = false
elsif o =~ /\n/
style = Nodes::Scalar::LITERAL
+ elsif o == '<<'
+ style = Nodes::Scalar::SINGLE_QUOTED
+ tag = 'tag:yaml.org,2002:str'
+ plain = false
+ quote = false
elsif o =~ /^[^[:word:]][^"]*$/
style = Nodes::Scalar::DOUBLE_QUOTED
else
@@ -341,17 +367,46 @@ module Psych
end
def visit_Hash o
- tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}"
- implicit = !tag
+ ivars = o.instance_variables
- register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK))
+ if ivars.any?
+ tag = "!ruby/hash-with-ivars"
+ tag << ":#{o.class}" unless o.class == ::Hash
- o.each do |k,v|
- accept k
- accept v
- end
+ register(o, @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK))
- @emitter.end_mapping
+ @emitter.scalar 'elements', nil, nil, true, false, Nodes::Scalar::ANY
+
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ o.each do |k,v|
+ accept k
+ accept v
+ end
+ @emitter.end_mapping
+
+ @emitter.scalar 'ivars', nil, nil, true, false, Nodes::Scalar::ANY
+
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ o.instance_variables.each do |ivar|
+ accept ivar
+ accept o.instance_variable_get ivar
+ end
+ @emitter.end_mapping
+
+ @emitter.end_mapping
+ else
+ tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}"
+ implicit = !tag
+
+ register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK))
+
+ o.each do |k,v|
+ accept k
+ accept v
+ end
+
+ @emitter.end_mapping
+ end
end
def visit_Psych_Set o
@@ -387,6 +442,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_exception.rb b/test/psych/test_exception.rb
index a9fe5c4..30dfb24 100644
--- a/test/psych/test_exception.rb
+++ b/test/psych/test_exception.rb
@@ -16,6 +16,12 @@ module Psych
@wups = Wups.new
end
+ def test_naming_exception
+ err = String.xxx rescue $!
+ new_err = Psych.load(Psych.dump(err))
+ assert_equal err.message, new_err.message
+ end
+
def test_load_takes_file
ex = assert_raises(Psych::SyntaxError) do
Psych.load '--- `'
diff --git a/test/psych/test_hash.rb b/test/psych/test_hash.rb
index 264a471..066df66 100644
--- a/test/psych/test_hash.rb
+++ b/test/psych/test_hash.rb
@@ -5,11 +5,55 @@ module Psych
class X < Hash
end
+ class HashWithCustomInit < Hash
+ attr_reader :obj
+ def initialize(obj)
+ @obj = obj
+ end
+ end
+
+ class HashWithCustomInitNoIvar < Hash
+ def initialize(obj)
+ # *shrug*
+ end
+ end
+
def setup
super
@hash = { :a => 'b' }
end
+ def test_custom_initialized
+ a = [1,2,3,4,5]
+ t1 = HashWithCustomInit.new(a)
+ t2 = Psych.load(Psych.dump(t1))
+ assert_equal t1, t2
+ assert_cycle t1
+ end
+
+ def test_custom_initialize_no_ivar
+ t1 = HashWithCustomInitNoIvar.new(nil)
+ t2 = Psych.load(Psych.dump(t1))
+ assert_equal t1, t2
+ assert_cycle t1
+ end
+
+ def test_hash_with_ivars
+ @hash.instance_variable_set :@foo, 'bar'
+ dup = Psych.load Psych.dump @hash
+ assert_equal 'bar', dup.instance_variable_get(:@foo)
+ end
+
+ def test_hash_subclass_with_ivars
+ x = X.new
+ x[:a] = 'b'
+ x.instance_variable_set :@foo, 'bar'
+ dup = Psych.load Psych.dump x
+ assert_cycle x
+ assert_equal 'bar', dup.instance_variable_get(:@foo)
+ assert_equal X, dup.class
+ end
+
def test_load_with_class_syck_compatibility
hash = Psych.load "--- !ruby/object:Hash\n:user_id: 7\n:username: Lucas\n"
assert_equal({ user_id: 7, username: 'Lucas'}, hash)
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
diff --git a/test/psych/test_merge_keys.rb b/test/psych/test_merge_keys.rb
index ba8d2e7..1620a6a 100644
--- a/test/psych/test_merge_keys.rb
+++ b/test/psych/test_merge_keys.rb
@@ -6,6 +6,36 @@ module Psych
attr_reader :bar
end
+ def test_merge_key_with_bare_hash
+ doc = Psych.load <<-eodoc
+map:
+ <<:
+ hello: world
+ eodoc
+ hash = { "map" => { "hello" => "world" } }
+ assert_equal hash, doc
+ end
+
+ def test_roundtrip_with_chevron_key
+ h = {}
+ v = { 'a' => h, '<<' => h }
+ assert_cycle v
+ end
+
+ def test_explicit_string
+ doc = Psych.load <<-eoyml
+a: &me { hello: world }
+b: { !!str '<<': *me }
+eoyml
+ expected = {
+ "a" => { "hello" => "world" },
+ "b" => {
+ "<<" => { "hello" => "world" }
+ }
+ }
+ assert_equal expected, doc
+ end
+
def test_mergekey_with_object
s = <<-eoyml
foo: &foo
diff --git a/test/psych/test_string.rb b/test/psych/test_string.rb
index 68917c8..26a4e20 100644
--- a/test/psych/test_string.rb
+++ b/test/psych/test_string.rb
@@ -16,6 +16,10 @@ module Psych
end
end
+ def test_string_with_newline
+ assert_equal "1\n2", Psych.load("--- ! '1\n\n 2'\n")
+ end
+
def test_no_doublequotes_with_special_characters
assert_equal 2, Psych.dump(%Q{<%= ENV["PATH"] %>}).count('"')
end