class ReeString::TruncateBytes
def call(str, truncate_at, **opts)
def call(str, truncate_at, **opts) str = str.dup omission = opts[:omission] || DEFAULT_OMISSION case when str.bytesize <= truncate_at str when omission.bytesize > truncate_at raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{truncate_at} bytes" when omission.bytesize == truncate_at omission.dup else String.new.tap do |cut| cut_at = truncate_at - omission.bytesize str.each_grapheme_cluster do |grapheme| if cut.bytesize + grapheme.bytesize <= cut_at cut << grapheme else break end end cut << omission end end end