diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2015-01-08 14:21:34 -0800 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2015-01-08 14:21:34 -0800 |
commit | e3b2c1c9f5c3a6144a4b02d46a3677df9826a1ab (patch) | |
tree | 8976c31dc44648187f2bcceec3c69297df658d67 | |
parent | 010d0c37bde30c5f347ebfd69087a487ff8b8bbb (diff) | |
parent | af308f8307899cb9e1c0fffea4bce3110a1c3926 (diff) | |
download | psych-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.yml | 5 | ||||
-rw-r--r-- | CHANGELOG.rdoc | 49 | ||||
-rw-r--r-- | Manifest.txt | 1 | ||||
-rw-r--r-- | Rakefile | 4 | ||||
-rw-r--r-- | ext/psych/psych.c | 2 | ||||
-rw-r--r-- | ext/psych/psych_emitter.c | 56 | ||||
-rw-r--r-- | ext/psych/psych_emitter.h | 2 | ||||
-rw-r--r-- | ext/psych/psych_parser.c | 26 | ||||
-rw-r--r-- | ext/psych/psych_parser.h | 2 | ||||
-rw-r--r-- | lib/psych.rb | 2 | ||||
-rw-r--r-- | lib/psych/scalar_scanner.rb | 2 | ||||
-rw-r--r-- | lib/psych/visitors/to_ruby.rb | 35 | ||||
-rw-r--r-- | lib/psych/visitors/yaml_tree.rb | 83 | ||||
-rw-r--r-- | test/psych/json/test_stream.rb | 2 | ||||
-rw-r--r-- | test/psych/test_emitter.rb | 3 | ||||
-rw-r--r-- | test/psych/test_exception.rb | 6 | ||||
-rw-r--r-- | test/psych/test_hash.rb | 44 | ||||
-rw-r--r-- | test/psych/test_json_tree.rb | 2 | ||||
-rw-r--r-- | test/psych/test_marshalable.rb | 54 | ||||
-rw-r--r-- | test/psych/test_merge_keys.rb | 30 | ||||
-rw-r--r-- | test/psych/test_string.rb | 4 |
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 @@ -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 |