Feature #16348
closedProposal: Symbol#start_with?, Symbol#end_with?, and Symbol#include?
Description
When replacing #match? to #start_with?, #end_with?, and #include? for some reason (address to https://bugs.ruby-lang.org/issues/13083 etc), we frequently hit missing Symbol#start_with?, Symbol#end_with?, and Symbol#include? in spite of Symbol#match? exists.
https://github.com/rails/rails/commit/63256bc5d7dd77b2cce82df46c53249dab2dc2a8
https://github.com/rails/rails/commit/a8e812964d711fa03843e76ae50f5ff81cdc9e00
Is this inconsistency intentional?
If not so, Symbol#start_with?, Symbol#end_with?, and Symbol#include? prevents such like an issue.
Updated by shevegen (Robert A. Heiler) about 5 years ago
I have no particular pro/con opinion. When it comes to class Symbol
, though, I believe
that this is is a design decision for matz. I understand that some of the comments
in the other threads are related to rails, but the suggestion here would mean to also
add three methods to class Symbol
, so the impact of such a change should be considered,
if there is one (including the semantics and design decisions; remember strange
things such as HashWithIndirectAccess
).
Updated by naruse (Yui NARUSE) about 5 years ago
diff --git a/string.c b/string.c
index 554aabad4b..d53fdc89fd 100644
--- a/string.c
+++ b/string.c
@@ -11166,6 +11166,64 @@ sym_swapcase(int argc, VALUE *argv, VALUE sym)
return rb_str_intern(rb_str_swapcase(argc, argv, rb_sym2str(sym)));
}
+/*
+ * call-seq:
+ * sym.include? other_str -> true or false
+ *
+ * Returns <code>true</code> if <i>str</i> contains the given string or
+ * character.
+ *
+ * :hello.include? "lo" #=> true
+ * :hello.include? "ol" #=> false
+ * :hello.include? ?h #=> true
+ */
+
+static VALUE
+sym_include(VALUE sym, VALUE arg)
+{
+ return rb_str_include(rb_sym2str(sym), arg);
+}
+
+/*
+ * call-seq:
+ * sym.start_with?([prefixes]+) -> true or false
+ *
+ * Returns true if +sym+ starts with one of the +prefixes+ given.
+ * Each of the +prefixes+ should be a String or a Regexp.
+ *
+ * :hello.start_with?("hell") #=> true
+ * :hello.start_with?(/H/i) #=> true
+ *
+ * # returns true if one of the prefixes matches.
+ * :hello.start_with?("heaven", "hell") #=> true
+ * :hello.start_with?("heaven", "paradise") #=> false
+ */
+
+static VALUE
+sym_start_with(int argc, VALUE *argv, VALUE sym)
+{
+ return rb_str_start_with(argc, argv, rb_sym2str(sym));
+}
+
+/*
+ * call-seq:
+ * sym.end_with?([suffixes]+) -> true or false
+ *
+ * Returns true if +sym+ ends with one of the +suffixes+ given.
+ *
+ * :hello.end_with?("ello") #=> true
+ *
+ * # returns true if one of the +suffixes+ matches.
+ * :hello.end_with?("heaven", "ello") #=> true
+ * :hello.end_with?("heaven", "paradise") #=> false
+ */
+
+static VALUE
+sym_end_with(int argc, VALUE *argv, VALUE sym)
+{
+ return rb_str_end_with(argc, argv, rb_sym2str(sym));
+}
+
/*
* call-seq:
* sym.encoding -> encoding
@@ -11452,5 +11510,9 @@ Init_String(void)
rb_define_method(rb_cSymbol, "capitalize", sym_capitalize, -1);
rb_define_method(rb_cSymbol, "swapcase", sym_swapcase, -1);
+ rb_define_method(rb_cSymbol, "include?", sym_include, 1);
+ rb_define_method(rb_cSymbol, "start_with?", sym_start_with, -1);
+ rb_define_method(rb_cSymbol, "end_with?", sym_end_with, -1);
+
rb_define_method(rb_cSymbol, "encoding", sym_encoding, 0);
}
diff --git a/test/ruby/test_symbol.rb b/test/ruby/test_symbol.rb
index d657f1aae6..d3a3af508f 100644
--- a/test/ruby/test_symbol.rb
+++ b/test/ruby/test_symbol.rb
@@ -568,4 +568,34 @@ def ==(obj)
puts :a == :a
RUBY
end
+
+ def test_start_with?
+ assert_equal(true, :hello.start_with?("hel"))
+ assert_equal(false, :hello.start_with?("el"))
+ assert_equal(true, :hello.start_with?("el", "he"))
+
+ bug5536 = '[ruby-core:40623]'
+ assert_raise(TypeError, bug5536) {:str.start_with? :not_convertible_to_string}
+
+ assert_equal(true, :hello.start_with?(/hel/))
+ assert_equal("hel", $&)
+ assert_equal(false, :hello.start_with?(/el/))
+ assert_nil($&)
+ end
+
+ def test_end_with?
+ assert_equal(true, :hello.end_with?("llo"))
+ assert_equal(false, :hello.end_with?("ll"))
+ assert_equal(true, :hello.end_with?("el", "lo"))
+
+ bug5536 = '[ruby-core:40623]'
+ assert_raise(TypeError, bug5536) {:str.end_with? :not_convertible_to_string}
+ end
+
+ def test_include?
+ assert_include(:foobar, ?f)
+ assert_include(:foobar, "foo")
+ assert_not_include(:foobar, "baz")
+ assert_not_include(:foobar, ?z)
+ end
end
Updated by nobu (Nobuyoshi Nakada) about 5 years ago
naruse (Yui NARUSE) wrote:
+ * sym.include? other_str -> true or false + * + * Returns <code>true</code> if <i>str</i> contains the given string or
str
should be sym
.
Updated by duerst (Martin Dürst) about 5 years ago
I personally think that we should be restrictive in adding new methods to Symbol
. Otherwise, this very quickly becomes a slippery slope, and the distinction between Symbol
and String
becomes less and less clear.
I was personally surprised when I implemented feature #10085 that Symbol
had #upcase
and friends, I wouldn't have guessed that.
Updated by matz (Yukihiro Matsumoto) about 5 years ago
I am OK with adding start_with?
and end_with?
.
I am a bit reluctant with adding include?
since Symbol does not include any character. Persuade me further if you really need Symbol#include?
.
Matz.
Updated by Hanmac (Hans Mackowiak) about 5 years ago
there is also symbol[string]
which can be used as replace for Symbol#include?
Updated by naruse (Yui NARUSE) about 5 years ago
- Status changed from Open to Closed
Applied in changeset git|b5fbefbf2c14742f6d46ecdf3ce712062dfb1d0a.
Added Symbol#start_with? and Symbol#end_with? method. [Feature #16348]
Updated by naruse (Yui NARUSE) about 5 years ago
duerst (Martin Dürst) wrote:
I personally think that we should be restrictive in adding new methods to
Symbol
. Otherwise, this very quickly becomes a slippery slope, and the distinction betweenSymbol
andString
becomes less and less clear.I was personally surprised when I implemented feature #10085 that
Symbol
had#upcase
and friends, I wouldn't have guessed that.
As far as I remember, once Matz tried and gave up to unify String and Symbol, he said Symbol should have similar set of methods while people needed.
After a decade some but small number of methods are added even if including this.
I think there's no worry.