* object.c (rb_inspect): dump inspected result with rb_str_escape()

instead of raising Encoding::CompatibilityError. [Feature #11801]

* string.c (rb_str_escape): added to dump given string like
  rb_str_inspect without quotes and always dump in US-ASCII
  like rb_str_dump.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53027 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
naruse 2015-12-10 18:57:08 +00:00
parent 9e0d92a4e4
commit e3ab670a71
5 changed files with 93 additions and 5 deletions

View File

@ -1,3 +1,12 @@
Fri Dec 11 03:44:43 2015 NARUSE, Yui <naruse@ruby-lang.org>
* object.c (rb_inspect): dump inspected result with rb_str_escape()
instead of raising Encoding::CompatibilityError. [Feature #11801]
* string.c (rb_str_escape): added to dump given string like
rb_str_inspect without quotes and always dump in US-ASCII
like rb_str_dump.
Thu Dec 10 14:59:59 2015 Koichi Sasada <ko1@atdot.net>
* test/ruby/test_gc.rb (test_expand_heap): relax condition (1->2).

9
NEWS
View File

@ -152,6 +152,10 @@ with all sufficient information, see the ChangeLog file.
* Array#flatten and Array#flatten! no longer try to call #to_ary
method on elements beyond the given level. [Bug #10748]
* Array#inspect doesn't raise error even if its content returns
a string which is not compatible with Encoding.default_external
as inspected result. [Feature #11801]
* Enumerable
* Enumerable#chunk and Enumerable#slice_before no longer takes the
initial_state argument. [Feature #10958]
@ -161,6 +165,11 @@ with all sufficient information, see the ChangeLog file.
* On Windows File::Stat#ino always returned 0, but now returns
BY_HANDLE_FILE_INFORMATION.nFileIndexHigh/Low. [Feature #11216]
* Hash
* Hash#inspect doesn't raise error even if its content returns
a string which is not compatible with Encoding.default_external
as inspected result. [Feature #11801]
* IO
* IO#close doesn't raise when the IO object is closed. [Feature #10718]
* IO#each_codepoint raises an exception at incomplete character

View File

@ -465,6 +465,7 @@ rb_any_to_s(VALUE obj)
return str;
}
VALUE rb_str_escape(VALUE str);
/*
* If the default external encoding is ASCII compatible, the encoding of
* the inspected result must be compatible with it.
@ -478,11 +479,11 @@ rb_inspect(VALUE obj)
rb_encoding *ext = rb_default_external_encoding();
if (!rb_enc_asciicompat(ext)) {
if (!rb_enc_str_asciionly_p(str))
rb_raise(rb_eEncCompatError, "inspected result must be ASCII only if default external encoding is ASCII incompatible");
return rb_str_escape(str);
return str;
}
if (rb_enc_get(str) != ext && !rb_enc_str_asciionly_p(str))
rb_raise(rb_eEncCompatError, "inspected result must be ASCII only or use the default external encoding");
return rb_str_escape(str);
return str;
}

View File

@ -5265,6 +5265,70 @@ rb_str_buf_cat_escaped_char(VALUE result, unsigned int c, int unicode_p)
return l;
}
VALUE
rb_str_escape(VALUE str)
{
int encidx = ENCODING_GET(str);
rb_encoding *enc = rb_enc_from_index(encidx);
const char *p = RSTRING_PTR(str);
const char *pend = RSTRING_END(str);
const char *prev = p;
char buf[CHAR_ESC_LEN + 1];
VALUE result = rb_str_buf_new(0);
int unicode_p = rb_enc_unicode_p(enc);
int asciicompat = rb_enc_asciicompat(enc);
while (p < pend) {
unsigned int c, cc;
int n = rb_enc_precise_mbclen(p, pend, enc);
if (!MBCLEN_CHARFOUND_P(n)) {
if (p > prev) str_buf_cat(result, prev, p - prev);
n = rb_enc_mbminlen(enc);
if (pend < p + n)
n = (int)(pend - p);
while (n--) {
snprintf(buf, CHAR_ESC_LEN, "\\x%02X", *p & 0377);
str_buf_cat(result, buf, strlen(buf));
prev = ++p;
}
continue;
}
n = MBCLEN_CHARFOUND_LEN(n);
c = rb_enc_mbc_to_codepoint(p, pend, enc);
p += n;
switch (c) {
case '\n': cc = 'n'; break;
case '\r': cc = 'r'; break;
case '\t': cc = 't'; break;
case '\f': cc = 'f'; break;
case '\013': cc = 'v'; break;
case '\010': cc = 'b'; break;
case '\007': cc = 'a'; break;
case 033: cc = 'e'; break;
default: cc = 0; break;
}
if (cc) {
if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
buf[0] = '\\';
buf[1] = (char)cc;
str_buf_cat(result, buf, 2);
prev = p;
}
else if (asciicompat && rb_enc_isascii(c, enc) && ISPRINT(c)) {
}
else {
if (p - n > prev) str_buf_cat(result, prev, p - n - prev);
rb_str_buf_cat_escaped_char(result, c, unicode_p);
prev = p;
}
}
if (p > prev) str_buf_cat(result, prev, p - prev);
ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
OBJ_INFECT_RAW(result, str);
return result;
}
/*
* call-seq:
* str.inspect -> string

View File

@ -278,7 +278,7 @@ class TestM17N < Test::Unit::TestCase
o = Object.new
[Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE].each do |e|
o.instance_eval "undef inspect;def inspect;'abc'.encode('#{e}');end"
assert_raise(Encoding::CompatibilityError) { [o].inspect }
assert_equal '[abc]', [o].inspect
end
ensure
Encoding.default_internal = orig_int
@ -302,13 +302,18 @@ class TestM17N < Test::Unit::TestCase
def o.inspect
"abc".encode(Encoding.default_external)
end
assert_raise(Encoding::CompatibilityError) { [o].inspect }
assert_equal '[abc]', [o].inspect
Encoding.default_external = Encoding::US_ASCII
def o.inspect
"\u3042"
end
assert_raise(Encoding::CompatibilityError) { [o].inspect }
assert_equal '[\u3042]', [o].inspect
def o.inspect
"\x82\xa0".force_encoding(Encoding::Windows_31J)
end
assert_equal '[\x{82A0}]', [o].inspect
ensure
Encoding.default_internal = orig_int
Encoding.default_external = orig_ext