«#{ }» нотация против erb нотации

#ruby #string #templates #eval #erb

#ruby #строка #шаблоны #вычисление #erb

Вопрос:

В чем различия между нотацией:

 "
  some text
  #{some_ruby_code}
  some text
  #{some_more_ruby_code}
  some_other_text
"
  

и

 ERB.new("
  some text
  <%=some_ruby_code%>
  some text
  <%=some_more_ruby_code%>
  some_other_text
").result
  

У меня просто сложилось общее впечатление, что нотация erb может быть более мощной, но я не настолько ясен. Можете ли вы сравнить их с разных точек зрения и сказать, какие из них следует использовать в каких случаях? Какие вещи могут быть выполнены в одной нотации, а не в другой?

Дополнение 1

Большинство ответов на данный момент, похоже, утверждают, что erb неэффективен и не должен использоваться, когда "#{ }" может быть использован. Теперь давайте зададим другой вопрос. Почему "#{ }" нотация не может заменить erb? Разве это не было бы намного быстрее и лучше?

Дополнение 2

Большинство ответов ниже, похоже, предполагают, что одно событие "#{ }" не распространяется на несколько строк, так что фрагмент кода, подобный циклу, занимающему несколько строк, не может быть встроен внутрь. Но почему бы и нет? Если вы это сделаете, я не вижу никакой разницы от выполнения этого с <% > , за исключением того, что в последнем случае вы вставляете <% > в каждую строку.

Комментарии:

1. Я не разработчик ruby, но я бы выбрал наименее мощный и наиболее читаемый синтаксис в любое время. Это предотвращает добавление логики в представления, которой там не место, и облегчает чтение представлений.

2. @jgauffin Я согласен. И вы, вероятно, имеете в виду, что "#{ }" следует отдавать предпочтение erb, когда это возможно. Тогда, когда следует использовать erb? Почему это может быть заменено на "#{ }" ?

3. Я не большой поклонник ERB и был бы счастлив, если бы он вообще не использовался. OTOH, это стандарт, и каждому поколению нужен свой собственный ужасный стандарт, который все используют (Fortran, SQL, ERB, RPG, JCL, …).

4. @muistoosh SQL — это реальный язык для доступа к базе данных, и его невозможно избежать, в отличие от ERB. Настоящий язык — HTML; ERB — это просто промежуточный язык, поэтому у него меньше основы. Пока у вас есть другие способы генерировать HTML, вам может сойти с рук ERB.

Ответ №1:

Вы правы в том, что ваша ERB версия должна выдавать тот же результат, что и обычная версия (я думаю), но ее назначение совершенно иное.

ERB на самом деле это просто для создания шаблонов: если вам нужно сгенерировать текст (например, HTML-страницу или документ), какой-нибудь движок для создания шаблонов, подобный ERB , будет подходящим инструментом. Тем не менее, он не предназначен для простой интерполяции строк: хотя он, безусловно, способен это делать, это довольно периферийный способ сделать это. Действительно, вы фактически создаете ERB объект из строки, а затем оцениваете его обратно в строку.

Вы можете получить представление о том, насколько это неэффективно, проведя быстрый тест:

 $ irb -rbenchmark -rerb
ruby-1.9.2-p136 :023 > Benchmark.bm do |bm|
ruby-1.9.2-p136 :024 >     bm.report 'interpolation' do
ruby-1.9.2-p136 :025 >       a = 'hello there'
ruby-1.9.2-p136 :026?>     5000.times { "well #{a}" }
ruby-1.9.2-p136 :027?>     end
ruby-1.9.2-p136 :028?>   bm.report 'erb' do
ruby-1.9.2-p136 :029 >       a = 'hello there'
ruby-1.9.2-p136 :030?>     5000.times { ERB.new("well <%= a %>").result(binding) }
ruby-1.9.2-p136 :031?>     end
ruby-1.9.2-p136 :032?>   end
      user     system      total        real
interpolation  0.000000   0.000000   0.000000 (  0.001495)
erb  0.340000   0.000000   0.340000 (  0.352098)
 => true 
  

Стандартным способом интерполяции кода Ruby в строки является использование #{} внутри строкового литерала. Это встроено на уровне языка (в отличие от уровня библиотеки).

Комментарии:

1. Вы убедительно показываете, насколько медленным является erb. Тогда почему нельзя создать шаблон с помощью "#{ }" ?

2. @sawa: Я полагаю, что это было бы возможно, но для этого потребовался бы запуск gsub или eval для загруженной строки. ERB допускает простую интерполяцию наряду с циклированием, условными обозначениями и так далее.

3. @Hans Почему нельзя встроить циклирование, условные обозначения и другие вещи "#{ }" ? Я не понимаю, почему "#{ }" требуется gsub , в то время как erb этого не делает.

4. @Jonathan, нет проблем! @sawa, если только все эти строки, которые вы пишете, не являются статическими в вашем коде, вам нужно будет использовать некоторую комбинацию gsub и eval для замены вхождений #{...} в пределах динамически генерируемой строки. ИМХО, лучше полагаться на библиотеки шаблонов (ERB и friends) для фактического создания шаблонов и использовать встроенную интерполяцию строк ( #{...} ) внутри вашего статического кода.

5. Действительно! #{} работает в строковых литералах. Когда вы загружаете строку динамически, она будет отображаться в строке как » #{} «; поэтому вам пришлось бы переопределить функциональность #{} , если вы собирались использовать ее вне строкового литерала. И тогда вам придется переопределить часть ERB . Понимаете, к чему я клоню?

Ответ №2:

Преимущества ERB:

  1. Все уже знают и «любят» этот PHP-подобный стиль
  2. Вам не нужно беспокоиться о балансировке или экранировании ' или "
  3. Обычно вам не нужно программировать базовый механизм Ruby, т. Е. вам не нужно определять метод, возможно, расположенный в классе, возможно, дополненный модулем и т.д…

В общей картине, я полагаю, общая идея заключается в том, чтобы отделить части программы, которые должны быть выполнены разработчиком программного обеспечения, от той части, которую может выполнить интерфейсный веб-разработчик. Например, разработчик программного обеспечения может просто указать, что @account_number доступно, и на него могут ссылаться HTMLеры без квалификации Ruby.

В реальной жизни, похоже, существует множество проектов, выполняемых одним человеком, но, по крайней мере, когда-то нормой было привлекать команду к решению типичной проблемы. Даже сегодня посмотрите на все вопросы Rails здесь, на SO, от разработчиков, которые, очевидно, почти не знают Ruby. И ERB предшествует Rails, поэтому, если вы вернетесь к истокам механизма, было время, когда вам действительно всегда был нужен настоящий отдел программного обеспечения, потому что каждый проект включал в себя создание фреймворка, поэтому вы, вероятно, не хотели требовать квалификации Ruby software от каждого последнего члена команды.

Теперь я понимаю, что вы имеете в виду. Если вы уже знаете Ruby, намного сложнее оправдать уродство erb.

Комментарии:

1. Что касается ваших первых двух пунктов, я думаю, это просто тонкая разница в том, как вы выходите и переходите в режим кода. Что касается вашего третьего пункта, я не вижу, как это не относится к нотации «# { }».

2. Я бы отметил, что не всем нравится синтаксис PHP. Вот почему существуют такие проекты, как haml.

3. @egarcia: верно, вот почему я написал это с кавычками для запугивания , которые означают, что я не собираюсь ссылаться на буквальное значение фразы. Разве я не говорил , что это уродливо?

4. @sawa: что касается третьего пункта, то я пытался сказать следующее: обычно синтаксис ERB находится в файле шаблона, управляемом Rails или Puppet, или какой-либо другой платформой. Так что это всего лишь шаблон. Здесь не указано ERB.new( ... ) , потому что фреймворк считывает файл шаблона. Но в известных мне фреймворках нет соответствующего механизма для файлов с голыми объектами Ruby String в них. Конечно, такую вещь можно было бы разработать тривиально, но в настоящее время это не функция, и поэтому ответ на ваш вопрос таков: фреймворки поддерживают ERB, а не голые объекты Ruby String .

Ответ №3:

Одним из недостатков попыток использовать ERB для общей интерполяции строк является то, что ERB действительно нацелен на генерацию HTML. Результатом будет множество проблем с кодированием, когда вы забудете все выполнить в необработанном виде и запутаетесь в том, почему ваши символы амперсандов, больше, чем, меньше, чем и т.д. искажаются.

Я думаю, что для ERB также будет больше вычислительных затрат, но это может не иметь значения.

Кроме того, если вы поместите встроенный ERB внутри Ruby, в конечном итоге Ruby inside ERB окажется внутри Ruby (и, вполне возможно, больше уровней, поскольку вы вызываете методы из ERB), и это будет немного запутанным беспорядком. Подумайте о беднягах, которым придется поддерживать ваш код, возможно, это даже вы сами.

ОБНОВЛЕНИЕ: Вы могли бы использовать #{} для простых HTML-шаблонов (см. Mustache для чего-то подобного), но было бы сложно и довольно некрасиво создавать повторяющийся раздел; повторяющиеся разделы довольно распространены в HTML-шаблонах, так что это должно быть легко и естественно для системы шаблонов HTML. С помощью ERB вы можете просто:

 <% a.each do |e| %>
    <!-- ... -->
<% end %>
  

но это было бы ошибкой при #{} интерполяции. Вы также в конечном итоге будете делать #{html(blahblah)} все время, и большинство людей забудут.

Кроме того, «#» имеет особое значение в URL-адресах и другое специальное значение в CSS (где фигурные скобки также имеют особое значение); фрагментированные URL-адреса и фрагменты CSS довольно распространены в шаблонах HTML, поэтому вы постоянно беспокоитесь о том, чтобы что-то перепутать. Эта конкретная неприятность, вероятно, была бы проблемой только при использовании #{} для создания CSS-селектора или фрагмента в URL-адресе, но этого достаточно, чтобы сделать его громоздким.

Комментарии:

1. Что касается вашего первого пункта, я думаю, это просто разница в том, что нужно экранировать. Я согласен с вами, что erb все усложнит. Тогда почему "#{ }" нотацию нельзя использовать там, где используется erb?

2. Следуя вашим аргументам, единственное существенное различие, которое я вижу, — это escape-символ. Таким образом, единственной причиной наличия erb было бы то, что в ruby отсутствует альтернативная нотация для "#{ }" , которая не конфликтует с html, css или xml. Я не понимал, почему было бы беспорядочно использовать "#{ }" интерполяцию помимо проблемы с экранированием.

3. @mu Я думаю, что я кое-что понял из этих ответов. Ваши ответы и ответы других являются конструктивными.