Spec-Zone.ru › Ruby on Rails 8.1

модуль ActionView::Helpers::TextHelper

Подключённые модули:
ActionView::Helpers::SanitizeHelper, ActionView::Helpers::TagHelper, ActionView::Helpers::OutputSafetyHelper

Помощники для работы с текстом в Action View

Модуль TextHelper предоставляет набор методов для фильтрации, форматирования и преобразования строк, которые позволяют сократить объём встроенного кода Ruby в представлениях. Эти вспомогательные методы расширяют Action View, делая их доступными в файлах шаблонов.

Очистка

Большинство помощников для работы с текстом, создающих HTML-код, по умолчанию очищают переданные данные, но не экранируют их. Это означает, что HTML-теги будут отображаться на странице, но любой вредоносный код будет удалён. Рассмотрим несколько примеров с использованием метода simple_format:

simple_format('<a href="http://example.com/">Example</a>')
# => "<p><a href=\"http://example.com/\">Example</a></p>"

simple_format('<a href="javascript:alert(\'no!\')">Example</a>')
# => "<p><a>Example</a></p>"

Чтобы экранировать всё содержимое, вызовите метод h перед вызовом помощника для работы с текстом.

simple_format h('<a href="http://example.com/">Example</a>')
# => "<p>&lt;a href=\"http://example.com/\"&gt;Example&lt;/a&gt;</p>"

Открытые методы экземпляра

concat (string) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 63
def concat(string)
  output_buffer << string
end

Предпочтительный способ вывода текста в представлениях — использовать синтаксис eRuby <%= "text" %>. Обычные методы puts и print не работают должным образом в блоке кода eRuby. Если вам непременно нужно вывести текст внутри блока кода без вывода (то есть <% %>), можно использовать метод concat.

<% concat "hello" %> is equivalent to <%= "hello" %>

<%
   unless signed_in?
     concat link_to("Sign In", action: :sign_in)
   end
%>

is equivalent to

<% unless signed_in? %>
  <%= link_to "Sign In", action: :sign_in %>
<% end %>
current_cycle (name = "default") Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 461
def current_cycle(name = "default")
  cycle = get_cycle(name)
  cycle.current_value if cycle
end

Возвращает строку текущего цикла после его запуска. Полезно для сложного выделения строк таблицы или других задач оформления, для которых строка текущего цикла нужна в нескольких местах.

<%# Alternate background colors %>
<% @items = [1,2,3,4] %>
<% @items.each do |item| %>
  <div style="background-color:<%= cycle("red","white","blue") %>">
    <span style="background-color:<%= current_cycle %>"><%= item %></span>
  </div>
<% end %>
cycle (first_value, *values) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 437
def cycle(first_value, *values)
  options = values.extract_options!
  name = options.fetch(:name, "default")

  values.unshift(*first_value)

  cycle = get_cycle(name)
  unless cycle && cycle.values == values
    cycle = set_cycle(name, Cycle.new(*values))
  end
  cycle.to_s
end

Создаёт объект Cycle, метод to_s которого при каждом вызове переключается между элементами массива. Например, его можно использовать для чередования классов строк таблицы. Именованные циклы позволяют вкладывать циклы друг в друга. Если последним параметром передать Hash с ключом :name, будет создан именованный цикл. Имя цикла по умолчанию, если ключ :name не указан, — "default". Цикл можно сбросить вручную, вызвав reset_cycle и передав имя цикла. Строку текущего цикла можно в любой момент получить с помощью метода current_cycle.

 <%# Alternate CSS classes for even and odd numbers... %>
 <% @items = [1,2,3,4] %>
 <table>
 <% @items.each do |item| %>
   <tr class="<%= cycle("odd", "even") -%>">
     <td><%= item %></td>
   </tr>
 <% end %>
 </table>

 <%# Cycle CSS classes for rows, and text colors for values within each row %>
 <% @items = [
   { first: "Robert", middle: "Daniel", last: "James" },
   { first: "Emily", middle: "Shannon", maiden: "Pike", last: "Hicks" },
   { first: "June", middle: "Dae", last: "Jones" },
 ] %>
 <% @items.each do |item| %>
   <tr class="<%= cycle("odd", "even", name: "row_class") -%>">
     <td>
       <% item.values.each do |value| %>
         <%# Create a named cycle "colors" %>
         <span style="color:<%= cycle("red", "green", "blue", name: "colors") -%>">
           <%= value %>
         </span>
       <% end %>
       <% reset_cycle("colors") %>
     </td>
  </tr>
<% end %>
excerpt (text, phrase, options = {}) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 235
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,
    !first_part.empty? ? separator : "",
    phrase,
    !second_part.empty? ? separator : "",
    second_part
  ].join.strip

  [prefix, affix, postfix].join
end

Извлекает первое вхождение phrase вместе с окружающим текстом из text. Если начало или конец результата не совпадает с началом или концом text, перед результатом или после него добавляется маркер пропуска. В любом случае результат обрезается по краям. Возвращает nil, если phrase не найдено.

Параметры

:radius

Количество символов (или токенов — см. параметр :separator) вокруг phrase, включаемых в результат. По умолчанию — 100.

:omission

Маркер, добавляемый перед результатом или после него, если начало или конец фрагмента не совпадает с началом или концом text. По умолчанию — "...".

:separator

Разделитель между токенами, учитываемыми для :radius. По умолчанию — "", при котором каждый символ считается токеном.

Примеры

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

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

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

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

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..."
highlight (text, phrases, options = {}, &block) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 174
def highlight(text, phrases, options = {}, &block)
  text = sanitize(text) if options.fetch(:sanitize, true)

  if text.blank? || phrases.blank?
    text || ""
  else
    patterns = Array(phrases).map { |phrase| Regexp === phrase ? phrase : Regexp.escape(phrase) }
    pattern = /(#{patterns.join("|")})/i
    highlighter = options.fetch(:highlighter, '<mark>\1</mark>') unless block

    text.scan(/<[^>]*|[^<]+/).each do |segment|
      if !segment.start_with?("<")
        if block
          segment.gsub!(pattern, &block)
        else
          segment.gsub!(pattern, highlighter)
        end
      end
    end.join
  end.html_safe
end

Выделяет вхождения phrases в text, форматируя их с помощью строки выделения. phrases может быть одной или несколькими строками либо регулярными выражениями. Результат будет помечен как безопасный HTML. По умолчанию text очищается перед выделением, чтобы предотвратить возможные XSS-атаки.

Если указан блок, он будет использоваться вместо строки выделения. Каждое вхождение фразы передаётся в блок, а возвращаемое им значение вставляется в итоговый результат.

Параметры

:highlighter

Строка выделения. Использует \1 в качестве заполнителя для фразы, аналогично +String#sub+. По умолчанию — "<mark>\1</mark>". Этот параметр игнорируется, если указан блок.

:sanitize

Следует ли очищать text перед выделением. По умолчанию — true.

Примеры

highlight('You searched for: rails', 'rails')
# => "You searched for: <mark>rails</mark>"

highlight('You searched for: rails', /for|rails/)
# => "You searched <mark>for</mark>: <mark>rails</mark>"

highlight('You searched for: ruby, rails, dhh', 'actionpack')
# => "You searched for: ruby, rails, dhh"

highlight('You searched for: rails', ['for', 'rails'], highlighter: '<em>\1</em>')
# => "You searched <em>for</em>: <em>rails</em>"

highlight('You searched for: rails', 'rails', highlighter: '<a href="search?q=\1">\1</a>')
# => "You searched for: <a href=\"search?q=rails\">rails</a>"

highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match)) }
# => "You searched for: <a href=\"search?q=rails\">rails</a>"

highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
# => "<a href=\"javascript:alert('no!')\">ruby</a> on <mark>rails</mark>"
pluralize (count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 297
def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
  word = if count == 1 || count.to_s.match?(/^1(\.0+)?$/)
    singular
  else
    plural || singular.pluralize(locale)
  end

  "#{count || 0} #{word}"
end

Пытается образовать множественное число для слова singular, если count не равно 1. Если указан plural, он будет использован, когда количество больше 1; в противном случае Inflector определит форму множественного числа для заданной локали, которой по умолчанию является I18n.locale.

Слово будет преобразовано во множественное число по правилам, определённым для локали (для языков, отличных от английского, необходимо определить собственные правила словоизменения). См. ActiveSupport::Inflector.pluralize.

pluralize(1, 'person')
# => "1 person"

pluralize(2, 'person')
# => "2 people"

pluralize(3, 'person', plural: 'users')
# => "3 users"

pluralize(0, 'person')
# => "0 people"

pluralize(2, 'Person', locale: :de)
# => "2 Personen"
reset_cycle (name = "default") Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 484
def reset_cycle(name = "default")
  cycle = get_cycle(name)
  cycle.reset if cycle
end

Сбрасывает цикл, чтобы при следующем вызове он начинался с первого элемента. Чтобы сбросить именованный цикл, передайте name.

<%# Alternate CSS classes for even and odd numbers... %>
<% @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]] %>
<table>
<% @items.each do |item| %>
  <tr class="<%= cycle("even", "odd") -%>">
      <% item.each do |value| %>
        <span style="color:<%= cycle("#333", "#666", "#999", name: "colors") -%>">
          <%= value %>
        </span>
      <% end %>

      <% reset_cycle("colors") %>
  </tr>
<% end %>
</table>
safe_concat (string) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 67
def safe_concat(string)
  output_buffer.respond_to?(:safe_concat) ? output_buffer.safe_concat(string) : concat(string)
end
simple_format (text, html_options = {}, options = {}) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 383
def simple_format(text, html_options = {}, options = {})
  wrapper_tag = options[:wrapper_tag] || "p"

  text = sanitize(text, options.fetch(:sanitize_options, {})) if options.fetch(:sanitize, true)
  paragraphs = split_paragraphs(text)

  if paragraphs.empty?
    content_tag(wrapper_tag, nil, html_options)
  else
    paragraphs.map! { |paragraph|
      content_tag(wrapper_tag, raw(paragraph), html_options)
    }.join("\n\n").html_safe
  end
end

Преобразует text в HTML, применяя простые правила форматирования. Две или более последовательные пустые строки (\n\n или \r\n\r\n) считаются абзацем и заключаются в теги <p>. Одна пустая строка (\n или \r\n) считается разрывом строки, после чего добавляется тег <br />. Этот метод не удаляет символы новой строки из text.

В html_options можно передать любые HTML-атрибуты. Они будут добавлены ко всем созданным абзацам.

Параметры

  • :sanitize — если false, не очищает text.

  • :sanitize_options — любые дополнительные параметры, которые нужно передать методу очистки.

  • :wrapper_tag — String, задающая тег-обёртку; по умолчанию — "p".

Примеры

my_text = "Here is some basic text...\n...with a line break."

simple_format(my_text)
# => "<p>Here is some basic text...\n<br />...with a line break.</p>"

simple_format(my_text, {}, wrapper_tag: "div")
# => "<div>Here is some basic text...\n<br />...with a line break.</div>"

more_text = "We want to put a paragraph...\n\n...right there."

simple_format(more_text)
# => "<p>We want to put a paragraph...</p>\n\n<p>...right there.</p>"

simple_format("Look ma! A class!", class: 'description')
# => "<p class='description'>Look ma! A class!</p>"

simple_format("<blink>Unblinkable.</blink>")
# => "<p>Unblinkable.</p>"

simple_format("<blink>Blinkable!</blink> It's true.", {}, sanitize: false)
# => "<p><blink>Blinkable!</blink> It's true.</p>"

simple_format("<a target=\"_blank\" href=\"http://example.com\">Continue</a>", {}, { sanitize_options: { attributes: %w[target href] } })
# => "<p><a target=\"_blank\" href=\"http://example.com\">Continue</a></p>"
truncate (text, options = {}, &block) Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 122
def truncate(text, options = {}, &block)
  if text
    length  = options.fetch(:length, 30)

    content = text.truncate(length, options)
    content = options[:escape] == false ? content.html_safe : ERB::Util.html_escape(content)
    content << capture(&block) if block_given? && text.length > length
    content
  end
end

Обрезает text, если его длина превышает заданное значение :length. Если text обрезается, в конец результата добавляется маркер пропуска, так что общая длина не превышает :length.

Также можно передать блок для отображения и добавления дополнительного содержимого после маркера пропуска, если text обрезается. Однако это содержимое может привести к превышению общей длиной значения :length символов.

Результат будет экранирован, если не указан escape: false. В любом случае результат будет помечен как безопасный HTML. Будьте осторожны, если text может содержать HTML-теги или сущности: обрезка может привести к некорректному HTML, например к несбалансированным или незавершённым тегам.

Параметры

:length

Максимальное количество возвращаемых символов, не включая дополнительное содержимое блока. По умолчанию — 30.

:omission

Строка, добавляемая после обрезки. По умолчанию — "...".

:separator

Строка или регулярное выражение для поиска точки, в которой следует выполнить обрезку. По умолчанию обрезка может произойти на любом символе в text.

:escape

Следует ли экранировать результат. По умолчанию — true.

Примеры

truncate("Once upon a time in a world far far away")
# => "Once upon a time in a world..."

truncate("Once upon a time in a world far far away", length: 17)
# => "Once upon a ti..."

truncate("Once upon a time in a world far far away", length: 17, separator: ' ')
# => "Once upon a..."

truncate("And they found that many people were sleeping better.", length: 25, omission: '... (continued)')
# => "And they f... (continued)"

truncate("<p>Once upon a time in a world far far away</p>")
# => "&lt;p&gt;Once upon a time in a wo..."

truncate("<p>Once upon a time in a world far far away</p>", escape: false)
# => "<p>Once upon a time in a wo..."

truncate("Once upon a time in a world far far away") { link_to "Continue", "#" }
# => "Once upon a time in a world...<a href=\"#\">Continue</a>"
word_wrap (text, line_width: 80, break_sequence: "\n") Показать исходный код
# File actionview/lib/action_view/helpers/text_helper.rb, line 327
def word_wrap(text, line_width: 80, break_sequence: "\n")
  return +"" if text.empty?

  # Match up to `line_width` characters, followed by one of
  #   (1) non-newline whitespace plus an optional newline
  #   (2) the end of the string, ignoring any trailing newlines
  #   (3) a newline
  #
  # -OR-
  #
  # Match an empty line
  pattern = /(.{1,#{line_width}})(?:[^\S\n]+\n?|\n*\Z|\n)|\n/

  text.gsub(pattern, "\\1#{break_sequence}").chomp!(break_sequence)
end

Переносит text на строки, длина которых не превышает line_width. Метод выполняет разрыв на первом пробельном символе, не превышающем line_width (по умолчанию — 80).

word_wrap('Once upon a time')
# => "Once upon a time"

word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
# => "Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined..."

word_wrap('Once upon a time', line_width: 8)
# => "Once\nupon a\ntime"

word_wrap('Once upon a time', line_width: 1)
# => "Once\nupon\na\ntime"

Также можно указать пользовательский break_sequence (по умолчанию — «n»):

word_wrap('Once upon a time', line_width: 1, break_sequence: "\r\n")
# => "Once\r\nupon\r\na\r\ntime"

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API