diff options
-rw-r--r-- | internal/string.h | 1 | ||||
-rw-r--r-- | io.c | 25 | ||||
-rw-r--r-- | ruby.c | 4 | ||||
-rwxr-xr-x | spec/ruby/command_line/dash_0_spec.rb | 13 | ||||
-rw-r--r-- | spec/ruby/language/predefined_spec.rb | 71 | ||||
-rw-r--r-- | string.c | 8 |
6 files changed, 110 insertions, 12 deletions
diff --git a/internal/string.h b/internal/string.h index 87cefa13d5..0ff92c3b84 100644 --- a/internal/string.h +++ b/internal/string.h @@ -61,6 +61,7 @@ size_t rb_str_size_as_embedded(VALUE); bool rb_str_reembeddable_p(VALUE); VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE); VALUE rb_str_with_debug_created_info(VALUE, VALUE, int); +VALUE rb_str_frozen_bare_string(VALUE); /* error.c */ void rb_warn_unchilled_literal(VALUE str); @@ -8673,6 +8673,25 @@ deprecated_str_setter(VALUE val, ID id, VALUE *var) *var = val; } +static void +deprecated_rs_setter(VALUE val, ID id, VALUE *var) +{ + if (!NIL_P(val)) { + if (!RB_TYPE_P(val, T_STRING)) { + rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id)); + } + if (rb_str_equal(val, rb_default_rs)) { + val = rb_default_rs; + } + else { + val = rb_str_frozen_bare_string(val); + } + rb_enc_str_coderange(val); + rb_warn_deprecated("'%s'", NULL, rb_id2name(id)); + } + *var = val; +} + /* * call-seq: * print(*objects) -> nil @@ -15713,8 +15732,10 @@ Init_IO(void) rb_vm_register_global_object(rb_default_rs); rb_rs = rb_default_rs; rb_output_rs = Qnil; - rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter); - rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_str_setter); + rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter); + rb_gvar_ractor_local("$/"); // not local but ractor safe + rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter); + rb_gvar_ractor_local("$-0"); // not local but ractor safe rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter); rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE); @@ -1325,11 +1325,11 @@ proc_0_option(ruby_cmdline_options_t *opt, const char *s) if (v > 0377) rb_rs = Qnil; else if (v == 0 && numlen >= 2) { - rb_rs = rb_str_new2(""); + rb_rs = rb_fstring_lit(""); } else { c = v & 0xff; - rb_rs = rb_str_new(&c, 1); + rb_rs = rb_str_freeze(rb_str_new(&c, 1)); } return s; } diff --git a/spec/ruby/command_line/dash_0_spec.rb b/spec/ruby/command_line/dash_0_spec.rb new file mode 100755 index 0000000000..73c5e29004 --- /dev/null +++ b/spec/ruby/command_line/dash_0_spec.rb @@ -0,0 +1,13 @@ +require_relative '../spec_helper' + +describe "The -0 command line option" do + it "sets $/ and $-0" do + ruby_exe("puts $/, $-0", options: "-072").should == ":\n:\n" + end + + ruby_version_is "3.5" do + it "sets $/ and $-0 as a frozen string" do + ruby_exe("puts $/.frozen?, $-0.frozen?", options: "-072").should == "true\ntrue\n" + end + end +end diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb index 9338a04715..f8645493b8 100644 --- a/spec/ruby/language/predefined_spec.rb +++ b/spec/ruby/language/predefined_spec.rb @@ -559,12 +559,39 @@ describe "Predefined global $/" do $VERBOSE = @verbose end - it "can be assigned a String" do - str = "abc" - $/ = str - $/.should equal(str) + ruby_version_is ""..."3.5" do + it "can be assigned a String" do + str = +"abc" + $/ = str + $/.should equal(str) + end end + ruby_version_is "3.5" do + it "makes a new frozen String from the assigned String" do + string_subclass = Class.new(String) + str = string_subclass.new("abc") + str.instance_variable_set(:@ivar, 1) + $/ = str + $/.should.frozen? + $/.should be_an_instance_of(String) + $/.should_not.instance_variable_defined?(:@ivar) + $/.should == str + end + + it "makes a new frozen String if it's not frozen" do + str = +"abc" + $/ = str + $/.should.frozen? + $/.should == str + end + + it "assigns the given String if it's frozen and has no instance variables" do + str = "abc".freeze + $/ = str + $/.should equal(str) + end + end it "can be assigned nil" do $/ = nil $/.should be_nil @@ -608,10 +635,38 @@ describe "Predefined global $-0" do $VERBOSE = @verbose end - it "can be assigned a String" do - str = "abc" - $-0 = str - $-0.should equal(str) + ruby_version_is ""..."3.5" do + it "can be assigned a String" do + str = +"abc" + $-0 = str + $-0.should equal(str) + end + end + + ruby_version_is "3.5" do + it "makes a new frozen String from the assigned String" do + string_subclass = Class.new(String) + str = string_subclass.new("abc") + str.instance_variable_set(:@ivar, 1) + $-0 = str + $-0.should.frozen? + $-0.should be_an_instance_of(String) + $-0.should_not.instance_variable_defined?(:@ivar) + $-0.should == str + end + + it "makes a new frozen String if it's not frozen" do + str = +"abc" + $-0 = str + $-0.should.frozen? + $-0.should == str + end + + it "assigns the given String if it's frozen and has no instance variables" do + str = "abc".freeze + $-0 = str + $-0.should equal(str) + end end it "can be assigned nil" do @@ -1480,6 +1480,14 @@ rb_str_new_frozen_String(VALUE orig) return str_new_frozen(rb_cString, orig); } + +VALUE +rb_str_frozen_bare_string(VALUE orig) +{ + if (RB_LIKELY(BARE_STRING_P(orig) && OBJ_FROZEN_RAW(orig))) return orig; + return str_new_frozen(rb_cString, orig); +} + VALUE rb_str_tmp_frozen_acquire(VALUE orig) { |