RoR: каковы преимущества erb в коде Rails? - PullRequest
3 голосов
/ 02 марта 2011

Я прочитал впечатляющий пост Магнуса Холма под названием Block Helpers в Rails 3 , в котором он указывает, что Rails 3 слишком сильно прогнул синтаксис ERB. (В «оригинальном» ERB конструкция ERB может охватывать только один оператор. Rails 3 позволяет - даже требует - охватывать несколько операторов.)

Что заставляет меня задуматься: каковы реальные преимущества использования ERB по сравнению с нативной обработкой строк в Ruby? Чтобы разобраться в этом, я воспользовался примером, приведенным в документации по ERB, и попробовал его как в ERB, так и в собственных строках Ruby. Оказывается, богатая библиотека обработки строк в Ruby делает перевод действительно простым - даже интуитивно понятным.

Вот как это выглядит. Общее для обоих (снято непосредственно с документации ERB):

require "erb"

# Build template data class.
class Product
  def initialize( code, name, desc, cost )
    @code = code
    @name = name
    @desc = desc
    @cost = cost
    @features = [ ]
  end

  def add_feature( feature )
    @features << feature
  end

  # Support templating of member data.
  def get_binding
    binding
  end
end

Вот шаблон и расширение, написанное на ERB:

# ================================================================
# using ERB
erb_template = %{
    <html>
      <head><title>Ruby Toys -- <%= @name %></title></head>
      <body>
        <h1><%= @name %> (<%= @code %>)</h1>
        <p><%= @desc %></p>
        <ul>
          <% @features.each do |f| %>
            <li><b><%= f %></b></li>
          <% end %>
        </ul>
        <p>
          <% if @cost < 10 %>
            <b>Only <%= @cost %>!!!</b>
          <% else %>
             Call for a price, today!
          <% end %>
        </p>
      </body>
    </html>
  }.gsub(/^  /, '')
rhtml = ERB.new(erb_template)
# Produce results
@r1 = rhtml.result(toy.get_binding)

А вот шаблон, написанный на чистом Ruby:

# ================================================================
# using native Ruby strings
ruby_template = %q{"
    <html>
      <head><title>Ruby Toys -- #{ @name }</title></head>
      <body>
        <h1>#{ @name } (#{ @code })</h1>
        <p>#{ @desc }</p>
        <ul>
          #{ @features.map do |f|
               "<li><b>#{f}</b></li>\n"
             end.join }
        </ul>
        <p>
          #{ if @cost < 10
               "<b>Only #{ @cost }!!!</b>"
             else
               "Call for a price, today!"
             end
           }
        </p>
      </body>
    </html>
  "}
# Produce results
@r2 = eval(ruby_template, toy.get_binding)

Они дают одинаковые результаты (по модулю пробела). Является ли ERB проще или сложнее - это вопрос вкуса и опыта. Судя по количеству вопросов о ERB и <% = ...%> против <% ...%> против <% = ... -%>, кажется, что многим людям легче придерживаться прямого Ruby .

За риск начать какую-то священную войну, зачем беспокоиться о ERB, если нативный Ruby выполняет ту же работу? Как вы думаете, ERB полезен? Должен ли Rails также принимать шаблоны "native Ruby"?

Ответы [ 2 ]

4 голосов
/ 03 марта 2011

Магнус Холм здесь; приятно видеть, что вам понравилась статья: -)

Сначала давайте взглянем на шаблоны (да, интерполяция - это шаблон) как эволюцию от построения строки с обычным кодом:

# "Regular" way of constructing a string:
str = "Hello World: "
@users.each do |user|
  str << "How are you today, "
  str << user.name
  str << "? \n"
end

Если мы посмотрим на этот код, очевидно, что есть три шаблона, которые повторяются:

  • У нас есть много статических текстов, которые добавляются: str << "Static"
  • У нас есть некоторый динамический код, который добавляется: str << expresstion
  • У нас есть несколько блоков кода, которые изменяют поток управления: @users.each

Самое замечательное в ERB состоит в том, что это идеальный изоморфизм этих шаблонов, что означает, что пользователь может думать об этом с точки зрения построения строки обычным способом. Это просто способ создать строку, в которой больше внимания уделяется статическим частям (поскольку они являются общими), чем динамическим частям.

Будучи «пуристом», вы заметили, что это не самый низкий уровень 1028 *. Это абсолютно верно: пока вы можете оценить полный код Turing, ваш шаблонизатор становится Turing complete, и технически вам больше ничего не нужно. Вам не нужны блоки, когда вы можете просто вложить свой шаблонизатор.

Теперь нам нужно подумать о разнице между низким уровнем и простым для понимания . Да, когда вы удаляете детали здания, вы получаете ядро ​​меньшего размера, но это не обязательно облегчает понимание. Вы можете провести аналогию с GOTO: вы можете создавать любые циклы / условные выражения, используя одну единственную концепцию (GOTO), но оказывается, что легче рассуждать о коде с помощью операторов if / while. Зачем? Потому что шаблон появляется! Вместо того, чтобы концептуально анализировать эти шаблоны каждый раз, когда мы смотрим на них, проще создавать абстракций , которые мы можем сразу понять.

В вашем примере есть один шаблон, который, я думаю, будет использоваться в любом шаблоне: @users.map { |f| code }.join. Это точно , что ERB пытается абстрагировать, чтобы вы могли забыть о деталях и причинах вашей логики.

Я также считаю, что если вы упрощаете шаблонизатор, но все же делаете его полным по Тьюрингу, вы все равно абстрагируете эти детали. Вы поймете, что возникает шаблон, и, как вы являетесь СУХИМЫМ кодером, вы начнете создавать помощников и тому подобное. Вы на самом деле реализуете свой собственный маленький шаблонный движок поверх другого. Теперь все зависит от гибкости синтаксиса базового языка, удастся ли вам абстрагироваться от реальных деталей без особого шума. Например, есть версии Lisp, которые поддерживают статическую типизацию и сопоставление с образцом, но часто он не может превзойти синтаксис, разработанный специально для этой проблемы.

Итак, Каковы реальные преимущества использования ERB над собственной обработкой строк в Ruby? В одном предложении: Это дает вам хороший синтаксис для общих шаблонов.

Как вы думаете, ERB полезен?

Да и нет. Я думаю, что интерполяция определенно не правильный путь. Вы увидите шаблоны в своих шаблонах, и ничто не сравнится с пользовательским синтаксисом, когда дело доходит до шаблонов. Я думаю, что ERB весьма полезен, но в некоторых случаях ему не хватает: у него нет концепции, что блоки также являются выражениями:

# This block is more like a statement (we don't care about the return value)
@users.each do |foo|
  str << "Hello"
end

# This block is an expression
str << form_for(thing) do
  another_string
end

Я понятия не имею, можно ли исправить это с помощью синтаксиса, но сейчас он «исправлен» в каждой среде, и нет способа написать помощники блоков, которые работают в нескольких средах. Я хотел бы видеть более "официальный" способ справиться с этим.

Должен ли Rails также принимать "нативные" шаблоны Ruby?

Tilt уже работает, и лучшее решение было бы, если бы Rails переключился на Tilt, но я не думаю, что "родной Ruby" так полезен.Если это короткий шаблон, вы, конечно, можете просто использовать интерполированную строку прямо в вашем коде.И если это большой шаблон, и вы собираетесь удалить его из вашего файла Ruby, почему бы не использовать синтаксис, разработанный для шаблонов?

1 голос
/ 02 марта 2011

Rails - самоуверенное программное обеспечение. Он поставляется с кучей «стандартных» способов ведения дел, которые, как я полагаю, согласна основная команда, - это предпочтительный способ ведения дел - erb, Test :: Unit, prototype и т. Д., Но ничто не помешает вам изменить их (тем более с рельсами 3).

На мой взгляд, erb в Rails, хотя и не совсем как обычный erb, намного, намного лучше, чем интерполяция ruby-строк - особенно когда речь идет о блоках. Необходимость разбивать строки на HTML внутри блока выглядит для меня ужасно.

Но опять же, хамл выглядит ужасно для меня, в то время как другие клянутся им и ненавидят эрба. Все зависит от ваших предпочтений. Вот почему Rails позволяет разработчикам создавать собственные системы шаблонов. Я не знаю, существует ли он, но ничто не мешает разработчикам создавать систему шаблонов, в которой используются исключительно рубиновые строки.

Итак, в ответ на вопрос «Должен ли Rails также принимать шаблоны« нативного Ruby »?», Он уже это делает. Пока это кто-то еще реализует;)

...