diff options
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r-- | actionpack/lib/action_view/helpers/text_helper.rb | 60 |
1 files changed, 49 insertions, 11 deletions
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 0f599d5f41..069969a710 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -126,8 +126,9 @@ module ActionView # Extracts an excerpt from +text+ that matches the first instance of +phrase+. # The <tt>:radius</tt> option expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters # defined in <tt>:radius</tt> (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+, - # then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. The resulting string - # will be stripped in any case. If the +phrase+ isn't found, nil is returned. + # then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. The + # <tt>:separator</tt> enable to choose the delimation. The resulting string will be stripped in any case. If the +phrase+ + # isn't found, nil is returned. # # excerpt('This is an example', 'an', :radius => 5) # # => ...s is an exam... @@ -143,21 +144,37 @@ module ActionView # # excerpt('This is also an example', 'an', :radius => 8, :omission => '<chop> ') # # => <chop> is also an example + # + # excerpt('This is a very beautiful morning', 'very', :separator => ' ', :radius => 1) + # # => ...a very beautiful... def excerpt(text, phrase, options = {}) return unless text && phrase - radius = options.fetch(:radius, 100) - omission = options.fetch(:omission, "...") + radius = options.fetch(:radius, 100) + omission = options.fetch(:omission, "...") + separator = options.fetch(:separator, "") + + phrase = Regexp.escape(phrase) + regex = /#{phrase}/i + + return unless matches = text.match(regex) + phrase = matches[0] + + text.split(separator).each do |value| + if value.match(regex) + regex = phrase = value + break + end + end - phrase = Regexp.escape(phrase) - return unless found_pos = text =~ /(#{phrase})/i + first_part, second_part = text.split(regex, 2) - start_pos = [ found_pos - radius, 0 ].max - end_pos = [ [ found_pos + phrase.length + radius - 1, 0].max, text.length ].min + options = options.merge(:part_position => :first) + prefix, first_part = cut_part(first_part, options) - prefix = start_pos > 0 ? omission : "" - postfix = end_pos < text.length - 1 ? omission : "" + options = options.merge(:part_position => :second) + postfix, second_part = cut_part(second_part, options) - prefix + text[start_pos..end_pos].strip + postfix + prefix + (first_part + separator + phrase + separator + second_part).strip + postfix end # Attempts to pluralize the +singular+ word unless +count+ is 1. If @@ -402,6 +419,27 @@ module ActionView t.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') || t end end + + def cut_part(part, options) + radius = options.fetch(:radius, 100) + omission = options.fetch(:omission, "...") + separator = options.fetch(:separator, "") + part_position = options.fetch(:part_position) + + return "", "" unless part + + part = part.split(separator) + part.delete("") + affix = part.size > radius ? omission : "" + part = if part_position == :first + drop_index = [part.length - radius, 0].max + part.drop(drop_index).join(separator) + else + part.first(radius).join(separator) + end + + return affix, part + end end end end |