Module: ActionView::Helpers::TextHelper

Defined in:
lib/action_view/helpers/text_helper.rb

Overview

Provides a set of methods for working with text strings that can help unburden the level of inline Ruby code in the templates. In the example below we iterate over a collection of posts provided to the template and print each title after making sure it doesn't run longer than 20 characters:

<% for post in @posts %>
  Title: <%= truncate(post.title, 20) %>
<% end %>

Defined Under Namespace

Classes: Cycle

Constant Summary collapse

VERBOTEN_TAGS =
%w(form script)
VERBOTEN_ATTRS =
/^on/i
/
 (                       # leading text
   <\w+.*?>|             #   leading HTML tag, or
   [^=!:'"\/]|           #   leading punctuation, or 
   ^                     #   beginning of line
 )
 (
   (?:http[s]?:\/\/)|    # protocol spec, or
   (?:www\.)             # www.*
 ) 
 (
   ([\w]+:?[=?&\/.-]?)*    # url segment
   \w+[\/]?              # url tail
   (?:\#\w*)?            # trailing anchor
 )
 ([[:punct:]]|\s|<|$)    # trailing text
/x

Instance Method Summary collapse

Instance Method Details

Turns all urls and email addresses into clickable links. The link parameter can limit what should be linked. Options are :all (default), :email_addresses, and :urls.

Example:

auto_link("Go to http://www.rubyonrails.com and say hello to [email protected]") =>
  Go to <a href="http://www.rubyonrails.com">http://www.rubyonrails.com</a> and
  say hello to <a href="mailto:[email protected]">[email protected]</a>

If a block is given, each url and email address is yielded and the result is used as the link text. Example:

auto_link(post.body, :all, :target => '_blank') do |text|
  truncate(text, 15)
end

144
145
146
147
148
149
150
151
# File 'lib/action_view/helpers/text_helper.rb', line 144

def auto_link(text, link = :all, href_options = {}, &block)
  return '' if text.blank?
  case link
    when :all             then auto_link_urls(auto_link_email_addresses(text, &block), href_options, &block)
    when :email_addresses then auto_link_email_addresses(text, &block)
    when :urls            then auto_link_urls(text, href_options, &block)
  end
end

#concat(string, binding) ⇒ Object

The regular puts and print are outlawed in eRuby. It's recommended to use the <%= “hello” %> form instead of print “hello”. If you absolutely must use a method-based output, you can use concat. It's used like this: <% concat “hello”, binding %>. Notice that it doesn't have an equal sign in front. Using <%= concat “hello” %> would result in a double hello.


15
16
17
# File 'lib/action_view/helpers/text_helper.rb', line 15

def concat(string, binding)
  eval("_erbout", binding).concat(string)
end

#cycle(first_value, *values) ⇒ Object

Returns a Cycle object whose to_s value cycles through items of an array every time it is called. This can be used to alternate classes for table rows:

<%- for item in @items do -%>

<tr class="<%= cycle("even", "odd") %>">
  ... use item ...
</tr>

<%- end -%>

You can use named cycles to prevent clashes in nested loops. You'll have to reset the inner cycle, manually:

<%- for item in @items do -%>

<tr class="<%= cycle("even", "odd", :name => "row_class")
  <td>
    <%- for value in item.values do -%>
      <span style="color:'<%= cycle("red", "green", "blue"
                                    :name => "colors") %>'">
        item
      </span>
    <%- end -%>
    <%- reset_cycle("colors") -%>
  </td>
</tr>

<%- end -%>


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/action_view/helpers/text_helper.rb', line 260

def cycle(first_value, *values)
  if (values.last.instance_of? Hash)
    params = values.pop
    name = params[:name]
  else
    name = "default"
  end
  values.unshift(first_value)

  cycle = get_cycle(name)
  if (cycle.nil? || cycle.values != values)
    cycle = set_cycle(name, Cycle.new(*values))
  end
  return cycle.to_s
end

#excerpt(text, phrase, radius = 100, excerpt_string = "...") ⇒ Object

Extracts an excerpt from the text surrounding the phrase with a number of characters on each side determined by radius. If the phrase isn't found, nil is returned. Ex:

excerpt("hello my world", "my", 3) => "...lo my wo..."

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/action_view/helpers/text_helper.rb', line 44

def excerpt(text, phrase, radius = 100, excerpt_string = "...")
  if text.nil? || phrase.nil? then return end
  phrase = Regexp.escape(phrase)

  if found_pos = text =~ /(#{phrase})/i
    start_pos = [ found_pos - radius, 0 ].max
    end_pos   = [ found_pos + phrase.length + radius, text.length ].min

    prefix  = start_pos > 0 ? excerpt_string : ""
    postfix = end_pos < text.length ? excerpt_string : ""

    prefix + text[start_pos..end_pos].strip + postfix
  else
    nil
  end
end

#highlight(text, phrase, highlighter = '<strong class="highlight">\1</strong>') ⇒ Object

Highlights the phrase where it is found in the text by surrounding it like <strong class=“highlight”>I'm a highlight phrase</strong>. The highlighter can be specialized by passing highlighter as single-quoted string with 1 where the phrase is supposed to be inserted. N.B.: The phrase is sanitized to include only letters, digits, and spaces before use.


36
37
38
39
# File 'lib/action_view/helpers/text_helper.rb', line 36

def highlight(text, phrase, highlighter = '<strong class="highlight">\1</strong>')
  if phrase.blank? then return text end
  text.gsub(/(#{Regexp.escape(phrase)})/i, highlighter) unless text.nil?
end

#pluralize(count, singular, plural = nil) ⇒ Object

Attempts to pluralize the singular word unless count is 1. See source for pluralization rules.


62
63
64
65
66
67
68
69
70
71
72
# File 'lib/action_view/helpers/text_helper.rb', line 62

def pluralize(count, singular, plural = nil)
   "#{count} " + if count == 1
    singular
  elsif plural
    plural
  elsif Object.const_defined?("Inflector")
    Inflector.pluralize(singular)
  else
    singular + "s"
  end
end

#reset_cycle(name = "default") ⇒ Object

Resets a cycle so that it starts from the first element in the array the next time it is used.


278
279
280
281
282
# File 'lib/action_view/helpers/text_helper.rb', line 278

def reset_cycle(name = "default")
  cycle = get_cycle(name)
  return if cycle.nil?
  cycle.reset
end

#sanitize(html) ⇒ Object

Sanitizes the given HTML by making form and script tags into regular text, and removing all “onxxx” attributes (so that arbitrary Javascript cannot be executed). Also removes href attributes that start with “javascript:”.

Returns the sanitized text.


180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/action_view/helpers/text_helper.rb', line 180

def sanitize(html)
  # only do this if absolutely necessary
  if html.index("<")
    tokenizer = HTML::Tokenizer.new(html)
    new_text = ""

    while token = tokenizer.next
      node = HTML::Node.parse(nil, 0, 0, token, false)
      new_text << case node
        when HTML::Tag
          if VERBOTEN_TAGS.include?(node.name)
            node.to_s.gsub(/</, "&lt;")
          else
            if node.closing != :close
              node.attributes.delete_if { |attr,v| attr =~ VERBOTEN_ATTRS }
              if node.attributes["href"] =~ /^javascript:/i
                node.attributes.delete "href"
              end
            end
            node.to_s
          end
        else
          node.to_s.gsub(/</, "&lt;")
      end
    end

    html = new_text
  end

  html
end

#simple_format(text) ⇒ Object

Returns text transformed into HTML using very simple formatting rules Surrounds paragraphs with &lt;p&gt; tags, and converts line breaks into &lt;br /&gt; Two consecutive newlines(\n\n) are considered as a paragraph, one newline (\n) is considered a linebreak, three or more consecutive newlines are turned into two newlines


122
123
124
125
126
127
128
129
# File 'lib/action_view/helpers/text_helper.rb', line 122

def simple_format(text)
  text.gsub!(/(\r\n|\n|\r)/, "\n") # lets make them newlines crossplatform
  text.gsub!(/\n\n+/, "\n\n") # zap dupes
  text.gsub!(/\n\n/, '</p>\0<p>') # turn two newlines into paragraph
  text.gsub!(/([^\n])(\n)([^\n])/, '\1\2<br />\3') # turn single newline into <br />
  
  ("p", text)
end

Turns all links into words, like “<a href=”something“>else</a>” to “else”.


154
155
156
# File 'lib/action_view/helpers/text_helper.rb', line 154

def strip_links(text)
  text.gsub(/<a.*>(.*)<\/a>/m, '\1')
end

#strip_tags(html) ⇒ Object

Strips all HTML tags from the input, including comments. This uses the html-scanner tokenizer and so it's HTML parsing ability is limited by that of html-scanner.

Returns the tag free text.


216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/action_view/helpers/text_helper.rb', line 216

def strip_tags(html)
  if html.index("<")
    text = ""
    tokenizer = HTML::Tokenizer.new(html)

    while token = tokenizer.next
      node = HTML::Node.parse(nil, 0, 0, token, false)
      # result is only the content of any Text nodes
      text << node.to_s if node.class == HTML::Text  
    end
    # strip any comments, and if they have a newline at the end (ie. line with
    # only a comment) strip that too
    text.gsub(/<!--(.*?)-->[\n]?/m, "") 
  else
    html # already plain text
  end 
end

#truncate(text, length = 30, truncate_string = "...") ⇒ Object

Truncates text to the length of length and replaces the last three characters with the truncate_string if the text is longer than length.


21
22
23
24
25
26
27
28
29
30
# File 'lib/action_view/helpers/text_helper.rb', line 21

def truncate(text, length = 30, truncate_string = "...")
  if text.nil? then return end
  l = length - truncate_string.length
  if $KCODE == "NONE"
    text.length > length ? text[0...l] + truncate_string : text
  else
    chars = text.split(//)
    chars.length > length ? chars[0...l].join + truncate_string : text
  end
end

#word_wrap(text, line_width = 80) ⇒ Object

Word wrap long lines to line_width.


75
76
77
# File 'lib/action_view/helpers/text_helper.rb', line 75

def word_wrap(text, line_width = 80)
  text.gsub(/\n/, "\n\n").gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
end