diff --git a/string.c b/string.c index 6faeb5d00e..fbc44086dc 100644 --- a/string.c +++ b/string.c @@ -11307,6 +11307,26 @@ rb_str_delete_suffix(VALUE str, VALUE suffix) return rb_str_subseq(str, 0, RSTRING_LEN(str) - suffixlen); } +/* + * call-seq: + * ensure_suffix(suffix) -> new_string + * + * Returns a new string with the given suffix appended if not present, + * or a duplicate of self if it already ends with suffix. + * + * "script".ensure_suffix(".rb") # => "script.rb" + * "script.rb".ensure_suffix(".rb") # => "script.rb" + * "script.r".ensure_suffix(".rb") # => "script.r.rb" + * + */ +static VALUE +rb_str_ensure_suffix(VALUE str, VALUE suffix) +{ + if (rb_str_end_with(1, &suffix, str)) return str_duplicate(rb_cString, str); + + return rb_str_plus(str, suffix); +} + void rb_str_setter(VALUE val, ID id, VALUE *var) { @@ -12678,6 +12698,7 @@ Init_String(void) rb_define_method(rb_cString, "rstrip", rb_str_rstrip, 0); rb_define_method(rb_cString, "delete_prefix", rb_str_delete_prefix, 1); rb_define_method(rb_cString, "delete_suffix", rb_str_delete_suffix, 1); + rb_define_method(rb_cString, "ensure_suffix", rb_str_ensure_suffix, 1); rb_define_method(rb_cString, "sub!", rb_str_sub_bang, -1); rb_define_method(rb_cString, "gsub!", rb_str_gsub_bang, -1); diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index d2099607fd..4974d0b27c 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -3737,6 +3737,18 @@ CODE Warning[:deprecated] = deprecated end + def test_string_ensure_suffix + s = S("foobar") + + assert_equal("foobarbaz", s.ensure_suffix("baz")) + assert_equal("foobar", s.ensure_suffix("bar")) + assert_equal("foobarrb", s.ensure_suffix("rb")) + assert_equal(false, s.ensure_suffix("bar").equal?(s)) + assert_equal("foobarBAR", s.ensure_suffix("BAR")) + assert_equal("foobar", s.ensure_suffix("")) + assert_equal(false, s.ensure_suffix("").equal?(s)) + end + private def assert_bytesplice_result(expected, s, *args)