module ActionView::Helpers::TextHelper

def excerpt(text, phrase, options = {})

# => ...a very beautiful...
excerpt('This is a very beautiful morning', 'very', separator: ' ', radius: 1)

# => is also an example
excerpt('This is also an example', 'an', radius: 8, omission: ' ')

# => ...next...
excerpt('This next thing is an example', 'ex', radius: 2)

# => This is an example
excerpt('This is an example', 'is')

# => This is a...
excerpt('This is an example', 'is', radius: 5)

# => ...s is an exam...
excerpt('This is an example', 'an', radius: 5)

isn't found, +nil+ is returned.
:separator option to choose the delimitation. The resulting string will be stripped in any case. If the +phrase+
then the :omission option (which defaults to "...") will be prepended/appended accordingly. Use the
defined in :radius (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
The :radius option expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
Extracts an excerpt from +text+ that matches the first instance of +phrase+.
def excerpt(text, phrase, options = {})
  return unless text && phrase
  separator = options.fetch(:separator, nil) || ""
  case phrase
  when Regexp
    regex = phrase
  else
    regex = /#{Regexp.escape(phrase)}/i
  end
  return unless matches = text.match(regex)
  phrase = matches[0]
  unless separator.empty?
    text.split(separator).each do |value|
      if value.match?(regex)
        phrase = value
        break
      end
    end
  end
  first_part, second_part = text.split(phrase, 2)
  prefix, first_part   = cut_excerpt_part(:first, first_part, separator, options)
  postfix, second_part = cut_excerpt_part(:second, second_part, separator, options)
  affix = [first_part, separator, phrase, separator, second_part].join.strip
  [prefix, affix, postfix].join
end