-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add String#enclosed_with?
#5950
Conversation
I don't think this adds a visible value to what we currently have with |
@sdogruyol Agree - I've added custom methods for |
Sorry, I hardly see the value. |
For example in my code I've strings that can be simple/double quoted, or not. Before this, it was a lot more verbose. if str.starts_with?('"') && str.ends_with?("'")
something
elsif str.starts_with?('\'') && str.ends_with?('\'')
other_thing
end Now I just: case str
when .enclosed_with? '"' then something
when .enclosed_with? '\'' then other_thing
end |
There is something to it when start and end are the same... |
Use &&. Define a helper method. Let's not clutter the std. |
I've now deleted the two arguments overload, that is not really needed I admit. The class String
def enclosed_with?(char : Char)
starts_with?(char) && ends_with?(char)
end
def enclosed_with?(str : String)
return false if str.bytesize > bytesize
(to_unsafe + bytesize - str.bytesize).memcmp(str.to_unsafe, str.bytesize) == to_unsafe.memcmp(str.to_unsafe, str.bytesize) == 0
end
def enclosed_with?(re : Regex)
!!($~ = /^#{re}.*#{re}\z/.match(self))
end
def starts_with?(re : Regex)
!!($~ = re.match_at_byte_index(self, 0, Regex::Options::ANCHORED))
end
def ends_with?(re : Regex)
!!($~ = /#{re}\z/.match(self))
end
end
require "benchmark"
CHAR = '_'
BAD_CHAR = '#'
STR_DELMIMITER = "_TEST_"
STRING = STR_DELMIMITER * 9999
REGEX = /_TEST_/
puts "Char: "
Benchmark.ips do |x|
x.report " enclosed_with?" do
999.times do
STRING.enclosed_with? CHAR
STRING.enclosed_with? BAD_CHAR
end
end
x.report "starts_with? and ends_with?" do
999.times do
STRING.starts_with?(CHAR) && STRING.ends_with?(CHAR)
STRING.starts_with?(BAD_CHAR) && STRING.ends_with?(CHAR)
end
end
end
puts "String: "
Benchmark.ips do |x|
x.report "enclosed_with?" do
999.times do
STRING.enclosed_with? STR_DELMIMITER
end
end
x.report "String: starts_with? and ends_with?" do
999.times do
STRING.starts_with?(STR_DELMIMITER) && STRING.ends_with?(STR_DELMIMITER)
end
end
end
puts "Regex: "
Benchmark.ips do |x|
x.report "enclosed_with?" do
999.times do
STRING.enclosed_with? REGEX
end
end
x.report "starts_with? and ends_with?" do
999.times do
STRING.starts_with?(REGEX) && STRING.ends_with?(REGEX)
end
end
end Results: Char:
enclosed_with? 159.81k ( 6.26µs) (± 3.10%) fastest
starts_with? and ends_with? 145.35k ( 6.88µs) (± 1.93%) 1.10× slower
String:
enclosed_with? 2.07M (483.75ns) (± 3.47%) fastest
starts_with? and ends_with? 591.67k ( 1.69µs) (± 8.69%) 3.49× slower
Regex:
enclosed_with? 5.98 (167.29ms) (±10.53%) fastest
starts_with? and ends_with? 0.84 ( 1.2s ) (± 3.51%) 7.15× slower |
@asterite can you consider reopening this? I've done some cleanups. I guess the commits doesn't appear here because the PR is closed... |
Sorry @j8r, but enough people have raised that adding I hope to see you in other issue & PR around 🙇 |
A method that combine
starts_with?
andends_with?
.This is of course not an essential feature, but I find it quite elegant - specially when used with
when
insidecase
expressions.Be free to not merge.