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

ruby-changes:72983

From: Nobuyoshi <ko1@a...>
Date: Sat, 20 Aug 2022 03:57:36 +0900 (JST)
Subject: [ruby-changes:72983] 1ef49de834 (master): [Bug #18955] format single character for `%c`

https://git.ruby-lang.org/ruby.git/commit/?id=1ef49de834

From 1ef49de83483e6f78bfe9c795a473ccfb29db150 Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Sat, 20 Aug 2022 01:04:02 +0900
Subject: [Bug #18955] format single character for `%c`

---
 spec/ruby/core/kernel/shared/sprintf.rb | 28 ++++++++++++++++++++--------
 spec/ruby/core/string/modulo_spec.rb    | 12 ++++++++++--
 sprintf.c                               | 11 +++++------
 test/ruby/test_m17n.rb                  |  2 +-
 test/ruby/test_sprintf.rb               |  3 ++-
 5 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 84d472b0d1..59f5ab0036 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -289,16 +289,28 @@ describe :kernel_sprintf, shared: true do https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/kernel/shared/sprintf.rb#L289
         @method.call("%c", "a").should == "a"
       end
 
-      it "raises ArgumentError if argument is a string of several characters" do
-        -> {
-          @method.call("%c", "abc")
-        }.should raise_error(ArgumentError)
+      ruby_version_is ""..."3.2" do
+        it "raises ArgumentError if argument is a string of several characters" do
+          -> {
+            @method.call("%c", "abc")
+          }.should raise_error(ArgumentError)
+        end
+
+        it "raises ArgumentError if argument is an empty string" do
+          -> {
+            @method.call("%c", "")
+          }.should raise_error(ArgumentError)
+        end
       end
 
-      it "raises ArgumentError if argument is an empty string" do
-        -> {
-          @method.call("%c", "")
-        }.should raise_error(ArgumentError)
+      ruby_version_is "3.2" do
+        it "displays only the first character if argument is a string of several characters" do
+          @method.call("%c", "abc").should == "a"
+        end
+
+        it "displays no characters if argument is an empty string" do
+          @method.call("%c", "").should == ""
+        end
       end
 
       it "supports Unicode characters" do
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index 99c1694417..bf96a82874 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -368,8 +368,16 @@ describe "String#%" do https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/string/modulo_spec.rb#L368
     ("%c" % 'A').should == "A"
   end
 
-  it "raises an exception for multiple character strings as argument for %c" do
-    -> { "%c" % 'AA' }.should raise_error(ArgumentError)
+  ruby_version_is ""..."3.2" do
+    it "raises an exception for multiple character strings as argument for %c" do
+      -> { "%c" % 'AA' }.should raise_error(ArgumentError)
+    end
+  end
+
+  ruby_version_is "3.2" do
+    it "supports only the first character as argument for %c" do
+      ("%c" % 'AA').should == "A"
+    end
   end
 
   it "calls to_str on argument for %c formats" do
diff --git a/sprintf.c b/sprintf.c
index 5f7227e619..22edf398fe 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -441,12 +441,10 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) https://github.com/ruby/ruby/blob/trunk/sprintf.c#L441
 
                 tmp = rb_check_string_type(val);
                 if (!NIL_P(tmp)) {
-                    rb_encoding *valenc = rb_enc_get(tmp);
-                    if (rb_enc_strlen(RSTRING_PTR(tmp), RSTRING_END(tmp), valenc) != 1) {
-                        rb_raise(rb_eArgError, "%%c requires a character");
-                    }
-                    c = rb_enc_codepoint_len(RSTRING_PTR(tmp), RSTRING_END(tmp), &n, valenc);
-                    RB_GC_GUARD(tmp);
+                    flags |= FPREC;
+                    prec = 1;
+                    str = tmp;
+                    goto format_s1;
                 }
                 else {
                     c = NUM2INT(val);
@@ -488,6 +486,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) https://github.com/ruby/ruby/blob/trunk/sprintf.c#L486
                 else {
                     str = rb_obj_as_string(arg);
                 }
+              format_s1:
                 len = RSTRING_LEN(str);
                 rb_str_set_len(result, blen);
                 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) {
diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb
index 2c6fcee004..a50507a528 100644
--- a/test/ruby/test_m17n.rb
+++ b/test/ruby/test_m17n.rb
@@ -893,7 +893,7 @@ class TestM17N < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_m17n.rb#L893
       "%s%s" % [s("\xc2\xa1"), e("\xc2\xa1")]
     }
 
-    "%c" % "\u3042".encode('Windows-31J')
+    assert_equal("\u3042".encode('Windows-31J'), "%c" % "\u3042\u3044".encode('Windows-31J'))
   end
 
   def test_sprintf_p
diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb
index b05f4f3e44..618e67264a 100644
--- a/test/ruby/test_sprintf.rb
+++ b/test/ruby/test_sprintf.rb
@@ -362,7 +362,8 @@ class TestSprintf < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_sprintf.rb#L362
   def test_char
     assert_equal("a", sprintf("%c", 97))
     assert_equal("a", sprintf("%c", ?a))
-    assert_raise(ArgumentError) { sprintf("%c", sprintf("%c%c", ?a, ?a)) }
+    assert_equal("a", sprintf("%c", "a"))
+    assert_equal("a", sprintf("%c", sprintf("%c%c", ?a, ?a)))
     assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%c", ?a))
     assert_equal(" " * (BSIZ - 1) + "a", sprintf(" " * (BSIZ - 1) + "%-1c", ?a))
     assert_equal(" " * BSIZ + "a", sprintf("%#{ BSIZ + 1 }c", ?a))
-- 
cgit v1.2.1


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

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