Boris Blaadh <nejnejnej / gmail.com> writes:

> Brian Adkins wrote:
>> Boris Blaadh <nejnejnej / gmail.com> writes:
>> 
>>> wordlist = string.split(' ')
>>> # get rid of the last space
>>> shorttext.chop!
>>>
>>> puts "#{shorttext}..."
>> 
>> It is nicer to break at word boundaries in some contexts. But if it's
>> a single word (such as a long email address), then you'd still want to
>> show something more than "...". Maybe you can add a check for that.
>> 
>> e.g. for string = 'john.smith / hisdomain.com', lead = 15
>
> Hehe, ok:
>
> if shorttext.empty?
>   puts wordlist[0]
> else
>   puts "#{shorttext}..."
> end

That fixes the problem of showing only '...', but now 'puts
wordlist[0]' may display more than the limit.

Refining your idea a bit gave the following:

  def elide_words total_length
    return self unless self.length > total_length
    raise 'total_length must be at least 3' if total_length < 3
    words = self.split(' ')
    result = ''
    words.each do |word|
      len = total_length - (result.empty? ? 3 : 4)
      break if result.length + word.length > len
      result << ' ' unless result.empty?
      result << word
    end
    if result.empty?
      return self.elide(total_length)
    else
      return result + '...'
    end
  end

But we really don't need to find *all* the space boundaries via
split(), so the following version is about 10 times faster:

  def elide_words total_length
    return self unless self.length > total_length
    raise 'total_length must be at least 3' if total_length < 3
    len = total_length - 3 # room for '...'

    # Case 1: natural word break
    return self[0, len] + '...' if self[len,1] == ' '

    # Case 2: search backward for a char preceding a delimiter
    delim_found = false
    idx = len.downto(0) {|i|
      if delim_found
        break (i + 1) if self[i,1] != ' '
      else
        delim_found = true if self[i,1] == ' '
      end
    }

    return self[0, idx] + '...'
  end


-- 
Brian Adkins
http://www.lojic.com/
http://lojic.com/blog/