aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--compile.c8
-rw-r--r--insns.def22
-rw-r--r--string.c8
-rw-r--r--test/ruby/test_refinement.rb13
5 files changed, 51 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index f289bd776a..d4ada857fa 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,8 @@ with all sufficient information, see the ChangeLog file or Redmine
* rescue/else/ensure are allowed inside do/end blocks. [Feature #12906]
+* refinements take place in string interpolations. [Feature #13812]
+
=== Core classes updates (outstanding ones only)
* Array
diff --git a/compile.c b/compile.c
index 5cf7f750fc..0e3abd71f7 100644
--- a/compile.c
+++ b/compile.c
@@ -6180,7 +6180,15 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popp
ADD_INSN(ret, line, pop);
}
else {
+ const unsigned int flag = VM_CALL_FCALL;
+ LABEL *isstr = NEW_LABEL(line);
+ ADD_INSN(ret, line, dup);
+ ADD_INSN2(ret, line, branchiftype, INT2FIX(T_STRING), isstr);
+ LABEL_REF(isstr);
+ ADD_INSN(ret, line, dup);
+ ADD_SEND_R(ret, line, idTo_s, INT2FIX(0), NULL, INT2FIX(flag), NULL);
ADD_INSN(ret, line, tostring);
+ ADD_LABEL(ret, isstr);
}
break;
}
diff --git a/insns.def b/insns.def
index 70062c983c..1b069ce37d 100644
--- a/insns.def
+++ b/insns.def
@@ -356,10 +356,11 @@ concatstrings
DEFINE_INSN
tostring
()
-(VALUE val)
+(VALUE val, VALUE str)
(VALUE val)
{
- val = rb_obj_as_string(val);
+ VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
+ val = rb_obj_as_string_result(str, val);
}
/**
@@ -1038,6 +1039,23 @@ branchnil
}
}
+/**
+ @c jump
+ @e if val is type, set PC to (PC + dst).
+ @j もし val が type ならば、PC を (PC + dst) にする。
+ */
+DEFINE_INSN
+branchiftype
+(rb_num_t type, OFFSET dst)
+(VALUE val)
+()
+{
+ if (TYPE(val) == (int)type) {
+ RUBY_VM_CHECK_INTS(th);
+ JUMP(dst);
+ }
+}
+
/**********************************************************/
/* for optimize */
diff --git a/string.c b/string.c
index c32b363324..bbd23669e6 100644
--- a/string.c
+++ b/string.c
@@ -1404,6 +1404,8 @@ str_shared_replace(VALUE str, VALUE str2)
}
}
+VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
+
VALUE
rb_obj_as_string(VALUE obj)
{
@@ -1413,6 +1415,12 @@ rb_obj_as_string(VALUE obj)
return obj;
}
str = rb_funcall(obj, idTo_s, 0);
+ return rb_obj_as_string_result(str, obj);
+}
+
+VALUE
+rb_obj_as_string_result(VALUE str, VALUE obj)
+{
if (!RB_TYPE_P(str, T_STRING))
return rb_any_to_s(obj);
if (!FL_TEST_RAW(str, RSTRING_FSTR) && FL_ABLE(obj))
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index d79eb2b187..31925f3933 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -1961,6 +1961,19 @@ class TestRefinement < Test::Unit::TestCase
end
end
+ class ToString
+ c = self
+ using Module.new {refine(c) {def to_s; "ok"; end}}
+ def string
+ "#{self}"
+ end
+ end
+
+ def test_tostring
+ assert_equal("ok", ToString.new.string)
+ assert_predicate(ToString.new.taint.string, :tainted?)
+ end
+
private
def eval_using(mod, s)