Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (リビジョン 27929) +++ include/ruby/intern.h (作業コピー) @@ -664,6 +664,7 @@ void rb_str_update(VALUE, long, long, VALUE); VALUE rb_str_replace(VALUE, VALUE); VALUE rb_str_inspect(VALUE); +VALUE rb_str_inspect_encode(VALUE); VALUE rb_str_dump(VALUE); VALUE rb_str_split(VALUE, const char*); void rb_str_associate(VALUE, VALUE); Index: object.c =================================================================== --- object.c (リビジョン 27929) +++ object.c (作業コピー) @@ -350,7 +350,7 @@ VALUE rb_inspect(VALUE obj) { - return rb_obj_as_string(rb_funcall(obj, id_inspect, 0, 0)); + return rb_str_inspect_encode(rb_obj_as_string(rb_funcall(obj, id_inspect, 0, 0))); } static int Index: string.c =================================================================== --- string.c (リビジョン 27929) +++ string.c (作業コピー) @@ -4078,8 +4078,101 @@ } #endif + + +static rb_encoding * +inspect_encoding(void) +{ + rb_encoding *resenc = rb_default_internal_encoding(); + if (resenc == NULL) resenc = rb_default_external_encoding(); + if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding(); + return resenc; +} + + /* * call-seq: + * str.inspect_encode -> string + * + * Returns a inspect encoding version of _str_. + * if original encoding is diffrent from the result, transcode to 7bit clean. + * + * Encoding.default_internal = "utf-8" + * class A ; def inspect ; "\u3042".encode("euc-jp") end ; end + * A.new #=> "\xA4\xA2" + * A.new.inspect #=> "\"\\x{A4A2}\"" + * A.new.inspect.inspect_encode #=> "\"\\\\x{A4A2}\"" + * + */ + +VALUE +rb_str_inspect_encode(VALUE str) +{ + rb_encoding *enc = STR_ENC_GET(str); + rb_encoding *resenc = inspect_encoding(); + int unicode_p = rb_enc_unicode_p(enc); + VALUE result = rb_str_buf_new(0); +#define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ + char buf[CHAR_ESC_LEN + 1]; + const char *p, *pend, *prev; + + if(resenc == enc) + return str; + + rb_enc_associate(result, resenc); + p = RSTRING_PTR(str); pend = RSTRING_END(str); + prev = p; + while (p < pend) { + unsigned int c; + int n; + 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; + if ( !rb_enc_isascii(c, enc)) { + if (p - n > prev) str_buf_cat(result, prev, p - n - prev); + if (unicode_p) { + if (c < 0x10000) { + snprintf(buf, CHAR_ESC_LEN, "\\u%04X", c); + } + else { + snprintf(buf, CHAR_ESC_LEN, "\\u{%X}", c); + } + str_buf_cat(result, buf, strlen(buf)); + } + else { + if (c < 0x100) { + snprintf(buf, CHAR_ESC_LEN, "\\x%02X", c); + } + else { + snprintf(buf, CHAR_ESC_LEN, "\\x{%X}", c); + } + str_buf_cat(result, buf, strlen(buf)); + } + prev = p; + } + } + if (p > prev) str_buf_cat(result, prev, p - prev); + OBJ_INFECT(result, str); + return result; +} +#undef CHAR_ESC_LEN + +/* + * call-seq: * str.inspect -> string * * Returns a printable version of _str_, surrounded by quote marks, @@ -4098,11 +4191,8 @@ #define CHAR_ESC_LEN 13 /* sizeof(\x{ hex of 32bit unsigned int } \0) */ char buf[CHAR_ESC_LEN + 1]; VALUE result = rb_str_buf_new(0); - rb_encoding *resenc = rb_default_internal_encoding(); + rb_encoding *resenc = inspect_encoding(); int unicode_p = rb_enc_unicode_p(enc); - - if (resenc == NULL) resenc = rb_default_external_encoding(); - if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding(); rb_enc_associate(result, resenc); str_buf_cat2(result, "\""); @@ -7417,6 +7507,7 @@ rb_define_method(rb_cString, "to_s", rb_str_to_s, 0); rb_define_method(rb_cString, "to_str", rb_str_to_s, 0); rb_define_method(rb_cString, "inspect", rb_str_inspect, 0); + rb_define_method(rb_cString, "inspect_encode", rb_str_inspect_encode, 0); rb_define_method(rb_cString, "dump", rb_str_dump, 0); rb_define_method(rb_cString, "upcase", rb_str_upcase, 0);