Skip to content

Commit c00096f

Browse files
authored
Merge pull request rails#54293 from byroot/mb-chars-deprecation
Improve deprecation of String#mb_chars
2 parents b2b0b13 + 9bf81e4 commit c00096f

File tree

9 files changed

+82
-36
lines changed

9 files changed

+82
-36
lines changed

activerecord/lib/active_record/connection_adapters/abstract/quoting.rb

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def quote_table_name(table_name)
7171
# {SQL injection attacks}[https://en.wikipedia.org/wiki/SQL_injection].
7272
def quote(value)
7373
case value
74-
when String, Symbol
74+
when String, Symbol, ActiveSupport::Multibyte::Chars
7575
"'#{quote_string(value.to_s)}'"
7676
when true then quoted_true
7777
when false then quoted_false
@@ -84,11 +84,7 @@ def quote(value)
8484
when Date, Time then "'#{quoted_date(value)}'"
8585
when Class then "'#{value}'"
8686
else
87-
if value.class.name == "ActiveSupport::Multibyte::Chars"
88-
"'#{quote_string(value.to_s)}'"
89-
else
90-
raise TypeError, "can't quote #{value.class.name}"
91-
end
87+
raise TypeError, "can't quote #{value.class.name}"
9288
end
9389
end
9490

@@ -97,7 +93,7 @@ def quote(value)
9793
# to a String.
9894
def type_cast(value)
9995
case value
100-
when Symbol, Type::Binary::Data
96+
when Symbol, Type::Binary::Data, ActiveSupport::Multibyte::Chars
10197
value.to_s
10298
when true then unquoted_true
10399
when false then unquoted_false
@@ -107,11 +103,7 @@ def type_cast(value)
107103
when Type::Time::Value then quoted_time(value)
108104
when Date, Time then quoted_date(value)
109105
else
110-
if value.class.name == "ActiveSupport::Multibyte::Chars"
111-
value.to_s
112-
else
113-
raise TypeError, "can't cast #{value.class.name}"
114-
end
106+
raise TypeError, "can't cast #{value.class.name}"
115107
end
116108
end
117109

activerecord/test/cases/sanitize_test.rb

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,29 @@ def setup
1313
def test_sanitize_sql_array_handles_string_interpolation
1414
quoted_bambi = ActiveRecord::Base.lease_connection.quote_string("Bambi")
1515
assert_equal "name='#{quoted_bambi}'", Binary.sanitize_sql_array(["name='%s'", "Bambi"])
16-
assert_equal "name='#{quoted_bambi}'", Binary.sanitize_sql_array(["name='%s'", "Bambi".mb_chars])
16+
assert_deprecated ActiveSupport.deprecator do
17+
assert_equal "name='#{quoted_bambi}'", Binary.sanitize_sql_array(["name='%s'", "Bambi".mb_chars])
18+
end
19+
1720
quoted_bambi_and_thumper = ActiveRecord::Base.lease_connection.quote_string("Bambi\nand\nThumper")
1821
assert_equal "name='#{quoted_bambi_and_thumper}'", Binary.sanitize_sql_array(["name='%s'", "Bambi\nand\nThumper"])
19-
assert_equal "name='#{quoted_bambi_and_thumper}'", Binary.sanitize_sql_array(["name='%s'", "Bambi\nand\nThumper".mb_chars])
22+
23+
assert_deprecated ActiveSupport.deprecator do
24+
assert_equal "name='#{quoted_bambi_and_thumper}'", Binary.sanitize_sql_array(["name='%s'", "Bambi\nand\nThumper".mb_chars])
25+
end
2026
end
2127

2228
def test_sanitize_sql_array_handles_bind_variables
2329
quoted_bambi = ActiveRecord::Base.lease_connection.quote("Bambi")
2430
assert_equal "name=#{quoted_bambi}", Binary.sanitize_sql_array(["name=?", "Bambi"])
25-
assert_equal "name=#{quoted_bambi}", Binary.sanitize_sql_array(["name=?", "Bambi".mb_chars])
31+
assert_deprecated ActiveSupport.deprecator do
32+
assert_equal "name=#{quoted_bambi}", Binary.sanitize_sql_array(["name=?", "Bambi".mb_chars])
33+
end
2634
quoted_bambi_and_thumper = ActiveRecord::Base.lease_connection.quote("Bambi\nand\nThumper")
2735
assert_equal "name=#{quoted_bambi_and_thumper}", Binary.sanitize_sql_array(["name=?", "Bambi\nand\nThumper"])
28-
assert_equal "name=#{quoted_bambi_and_thumper}", Binary.sanitize_sql_array(["name=?", "Bambi\nand\nThumper".mb_chars])
36+
assert_deprecated ActiveSupport.deprecator do
37+
assert_equal "name=#{quoted_bambi_and_thumper}", Binary.sanitize_sql_array(["name=?", "Bambi\nand\nThumper".mb_chars])
38+
end
2939
end
3040

3141
def test_sanitize_sql_array_handles_named_bind_variables
@@ -224,8 +234,13 @@ def test_bind_chars
224234
quoted_bambi_and_thumper = ActiveRecord::Base.lease_connection.quote("Bambi\nand\nThumper")
225235
assert_equal "name=#{quoted_bambi}", bind("name=?", "Bambi")
226236
assert_equal "name=#{quoted_bambi_and_thumper}", bind("name=?", "Bambi\nand\nThumper")
227-
assert_equal "name=#{quoted_bambi}", bind("name=?", "Bambi".mb_chars)
228-
assert_equal "name=#{quoted_bambi_and_thumper}", bind("name=?", "Bambi\nand\nThumper".mb_chars)
237+
assert_deprecated ActiveSupport.deprecator do
238+
assert_equal "name=#{quoted_bambi}", bind("name=?", "Bambi".mb_chars)
239+
end
240+
241+
assert_deprecated ActiveSupport.deprecator do
242+
assert_equal "name=#{quoted_bambi_and_thumper}", bind("name=?", "Bambi\nand\nThumper".mb_chars)
243+
end
229244
end
230245

231246
def test_named_bind_with_postgresql_type_casts

activesupport/lib/active_support/core_ext/string/multibyte.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,16 @@ class String
3535
# For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
3636
# information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
3737
def mb_chars
38-
ActiveSupport::Multibyte.proxy_class.new(self)
38+
ActiveSupport.deprecator.warn(
39+
"String#mb_chars is deprecated and will be removed in Rails 8.2. " \
40+
"Use normal string methods instead."
41+
)
42+
43+
if ActiveSupport::Multibyte.proxy_class == ActiveSupport::Multibyte::Chars
44+
ActiveSupport::Multibyte::Chars.new(self, deprecation: false)
45+
else
46+
ActiveSupport::Multibyte.proxy_class.new(self)
47+
end
3948
end
4049

4150
# Returns +true+ if string has utf_8 encoding.

activesupport/lib/active_support/multibyte/chars.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
require "active_support/core_ext/string/behavior"
66
require "active_support/core_ext/module/delegation"
77

8-
ActiveSupport.deprecator.warn(
9-
"ActiveSupport::Multibyte::Chars and String#mb_chars are deprecated and will be removed in Rails 8.2. " \
10-
"Use normal string methods instead."
11-
)
12-
138
module ActiveSupport # :nodoc:
149
module Multibyte # :nodoc:
1510
# = Active Support \Multibyte \Chars
@@ -58,7 +53,14 @@ class Chars
5853
delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
5954

6055
# Creates a new Chars instance by wrapping _string_.
61-
def initialize(string)
56+
def initialize(string, deprecation: true)
57+
if deprecation
58+
ActiveSupport.deprecator.warn(
59+
"ActiveSupport::Multibyte::Chars is deprecated and will be removed in Rails 8.2. " \
60+
"Use normal string methods instead."
61+
)
62+
end
63+
6264
@wrapped_string = string
6365
if string.encoding != Encoding::UTF_8
6466
@wrapped_string = @wrapped_string.dup

activesupport/test/abstract_unit.rb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
Thread.abort_on_exception = true
2323

2424
# Show backtraces for deprecated behavior for quicker cleanup.
25-
ActiveSupport.deprecator.debug = true
25+
ActiveSupport.deprecator.behavior = :raise
2626

2727
# Default to Ruby 2.4+ to_time behavior but allow running tests with old behavior
2828
ActiveSupport.deprecator.silence do
@@ -34,10 +34,6 @@
3434
# Disable available locale checks to avoid warnings running the test suite.
3535
I18n.enforce_available_locales = false
3636

37-
ActiveSupport.deprecator.silence do
38-
ActiveSupport::Multibyte.const_get(:Chars)
39-
end
40-
4137
class ActiveSupport::TestCase
4238
if Process.respond_to?(:fork) && !Gem.win_platform?
4339
parallelize

activesupport/test/core_ext/string_ext_test.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,9 @@ def test_string_should_recognize_utf8_strings
801801
end
802802

803803
def test_mb_chars_returns_instance_of_proxy_class
804-
assert_kind_of ActiveSupport::Multibyte.proxy_class, UTF8_STRING.mb_chars
804+
assert_deprecated ActiveSupport.deprecator do
805+
assert_kind_of ActiveSupport::Multibyte.proxy_class, UTF8_STRING.mb_chars
806+
end
805807
end
806808
end
807809

activesupport/test/multibyte_chars_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
class MultibyteCharsTest < ActiveSupport::TestCase
88
include MultibyteTestHelpers
99

10+
def run(...)
11+
result = nil
12+
assert_deprecated ActiveSupport.deprecator do
13+
result = super
14+
end
15+
result
16+
end
17+
1018
def setup
1119
@proxy_class = ActiveSupport::Multibyte::Chars
1220
@chars = @proxy_class.new UNICODE_STRING.dup
@@ -96,6 +104,14 @@ def test_should_return_string_as_json
96104
class MultibyteCharsUTF8BehaviorTest < ActiveSupport::TestCase
97105
include MultibyteTestHelpers
98106

107+
def run(...)
108+
result = nil
109+
assert_deprecated ActiveSupport.deprecator do
110+
result = super
111+
end
112+
result
113+
end
114+
99115
def setup
100116
@chars = UNICODE_STRING.dup.mb_chars
101117
# Ruby 1.9 only supports basic whitespace
@@ -491,6 +507,14 @@ def test_acts_like_string
491507
class MultibyteCharsExtrasTest < ActiveSupport::TestCase
492508
include MultibyteTestHelpers
493509

510+
def run(...)
511+
result = nil
512+
assert_deprecated ActiveSupport.deprecator do
513+
result = super
514+
end
515+
result
516+
end
517+
494518
def test_upcase_should_be_unicode_aware
495519
assert_equal "АБВГД\0F", chars("аБвгд\0f").upcase
496520
assert_equal "こにちわ", chars("こにちわ").upcase
@@ -569,6 +593,8 @@ def test_normalization_shouldnt_strip_null_bytes
569593
end
570594

571595
def test_should_compute_grapheme_length
596+
"foo".mb_chars # appease assert_deprecated
597+
572598
[
573599
["", 0],
574600
["abc", 3],

activesupport/test/multibyte_proxy_test.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ def with_custom_encoder(encoder)
2525
end
2626

2727
test "custom multibyte encoder" do
28-
with_custom_encoder(AsciiOnlyEncoder) do
29-
assert_equal "s?me string 123", "søme string 123".mb_chars.to_s
30-
end
28+
assert_deprecated ActiveSupport.deprecator do
29+
with_custom_encoder(AsciiOnlyEncoder) do
30+
assert_equal "s?me string 123", "søme string 123".mb_chars.to_s
31+
end
3132

32-
assert_equal "søme string 123", "søme string 123".mb_chars.to_s
33+
assert_equal "søme string 123", "søme string 123".mb_chars.to_s
34+
end
3335
end
3436
end

activesupport/test/multibyte_test_helpers.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ module MultibyteTestHelpers
77
BYTE_STRING = "\270\236\010\210\245".b.freeze
88

99
def chars(str)
10-
ActiveSupport::Multibyte::Chars.new(str)
10+
assert_deprecated ActiveSupport.deprecator do
11+
ActiveSupport::Multibyte::Chars.new(str)
12+
end
1113
end
1214

1315
def inspect_codepoints(str)

0 commit comments

Comments
 (0)