aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md2
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb60
-rw-r--r--actionpack/test/template/text_helper_test.rb13
3 files changed, 64 insertions, 11 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 1232370439..4cf653722f 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Add `separation` option for `ActionView::Helpers::TextHelper.excerpt`. *Guirec Corbel*
+
* Added controller-level etag additions that will be part of the action etag computation *Jeremy Kemper/DHH*
class InvoicesController < ApplicationController
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
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index c0f694b2bf..4525efe73c 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -303,6 +303,19 @@ class TextHelperTest < ActionView::TestCase
assert_equal options, passed_options
end
+ def test_excerpt_with_separator
+ options = { :separator => ' ', :radius => 1 }
+ assert_equal('...a very beautiful...', excerpt('This is a very beautiful morning', 'very', options))
+ assert_equal('This is...', excerpt('This is a very beautiful morning', 'this', options))
+ assert_equal('...beautiful morning', excerpt('This is a very beautiful morning', 'morning', options))
+
+ options = { :separator => "\n", :radius => 0 }
+ assert_equal("...very long...", excerpt("my very\nvery\nvery long\nstring", 'long', options))
+
+ options = { :separator => "\n", :radius => 1 }
+ assert_equal("...very\nvery long\nstring", excerpt("my very\nvery\nvery long\nstring", 'long', options))
+ end
+
def test_word_wrap
assert_equal("my very very\nvery long\nstring", word_wrap("my very very very long string", :line_width => 15))
end