diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 64e9c2950..aa22b2bd0 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -1243,6 +1243,45 @@ mrb_str_lines(mrb_state *mrb, mrb_value self) return result; } +/* + * call-seq: + * +string -> new_string or self + * + * Returns +self+ if +self+ is not frozen. + * + * Otherwise returns self.dup, which is not frozen. + */ +static mrb_value +mrb_str_uplus(mrb_state *mrb, mrb_value str) +{ + if (mrb_frozen_p(mrb_obj_ptr(str))) { + return mrb_str_dup(mrb, str); + } + else { + return str; + } +} + +/* + * call-seq: + * -string -> frozen_string + * + * Returns a frozen, possibly pre-existing copy of the string. + * + * The returned \String will be deduplicated as long as it does not have + * any instance variables set on it and is not a String subclass. + * + * String#dedup is an alias for String#-@. + */ +static mrb_value +mrb_str_uminus(mrb_state *mrb, mrb_value str) +{ + if (mrb_frozen_p(mrb_obj_ptr(str))) { + return str; + } + return mrb_obj_freeze(mrb, mrb_str_dup(mrb, str)); +} + void mrb_mruby_string_ext_gem_init(mrb_state* mrb) { @@ -1278,6 +1317,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) mrb_define_method(mrb, s, "delete_suffix", mrb_str_del_suffix, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "casecmp", mrb_str_casecmp, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "casecmp?", mrb_str_casecmp_p, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "+@", mrb_str_uplus, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "-@", mrb_str_uminus, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "__lines", mrb_str_lines, MRB_ARGS_NONE()); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index eb731c503..9de02c59f 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -1,3 +1,4 @@ +# coding: utf-8 ## # String(Ext) Test @@ -712,3 +713,17 @@ assert('String#delete_suffix') do assert_equal "he", "hello".delete_suffix!("llo") assert_nil "hello".delete_suffix!("he") end + +assert('String#+@') do + a = +"abc" + assert_false(a.frozen?) + a = +(a.freeze) + assert_false(a.frozen?) +end + +assert('String#-@') do + a = -"abc" + assert_true(a.frozen?) + a = -(a.freeze) + assert_true(a.frozen?) +end