[前][次][番号順一覧][スレッド一覧]

ruby-changes:40948

From: naruse <ko1@a...>
Date: Fri, 11 Dec 2015 03:57:34 +0900 (JST)
Subject: [ruby-changes:40948] naruse:r53027 (trunk): * object.c (rb_inspect): dump inspected result with rb_str_escape()

naruse	2015-12-11 03:57:08 +0900 (Fri, 11 Dec 2015)

  New Revision: 53027

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=53027

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/object.c
    trunk/string.c
    trunk/test/ruby/test_m17n.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 53026)
+++ ChangeLog	(revision 53027)
@@ -1,3 +1,12 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Fri Dec 11 03:44:43 2015  NARUSE, Yui  <naruse@r...>
+
+	* 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@a...>
 
 	* test/ruby/test_gc.rb (test_expand_heap): relax condition (1->2).
Index: object.c
===================================================================
--- object.c	(revision 53026)
+++ object.c	(revision 53027)
@@ -465,6 +465,7 @@ rb_any_to_s(VALUE obj) https://github.com/ruby/ruby/blob/trunk/object.c#L465
     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) https://github.com/ruby/ruby/blob/trunk/object.c#L479
     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;
 }
 
Index: string.c
===================================================================
--- string.c	(revision 53026)
+++ string.c	(revision 53027)
@@ -5265,6 +5265,70 @@ rb_str_buf_cat_escaped_char(VALUE result https://github.com/ruby/ruby/blob/trunk/string.c#L5265
     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
Index: NEWS
===================================================================
--- NEWS	(revision 53026)
+++ NEWS	(revision 53027)
@@ -152,6 +152,10 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L152
   * 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 https://github.com/ruby/ruby/blob/trunk/NEWS#L165
   * 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
Index: test/ruby/test_m17n.rb
===================================================================
--- test/ruby/test_m17n.rb	(revision 53026)
+++ test/ruby/test_m17n.rb	(revision 53027)
@@ -278,7 +278,7 @@ class TestM17N < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_m17n.rb#L278
         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 https://github.com/ruby/ruby/blob/trunk/test/ruby/test_m17n.rb#L302
     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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]