Spec-Zone.ru › Ruby 2.6

класс ERB

Родитель:
Объект

ERB – Шаблонизация Ruby

Введение

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

Очень простой пример:

require 'erb'

x = 42
template = ERB.new <<-EOF
  The value of x is: <%= x %>
EOF
puts template.result(binding)

Вывод: Значение x равно: 42

Более сложные примеры приведены ниже.

Распознаваемые теги

ERB распознает определённые теги в предоставленном шаблоне и преобразует их в соответствии с правилами ниже:

<% Ruby code -- inline with output %>
<%= Ruby expression -- replace with result %>
<%# comment -- ignored -- useful in testing %>
% a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
%% replaced with % if first thing on a line and % processing is used
<%% or %%> -- replace with <% or %> respectively

Весь остальной текст передаётся через ERB фильтрацию без изменений.

Параметры

Существует несколько настроек, которые вы можете изменить при использовании ERB:

  • характер распознаваемых тегов;

  • значение $SAFE, в котором выполняется шаблон;

  • связывание, используемое для разрешения локальных переменных в шаблоне.

См. методы ERB.new и ERB#result для получения более подробной информации.

Кодировки символов

ERB (или код Ruby, сгенерированный ERB) возвращает строку в той же кодировке символов, что и входная строка. Однако, если входная строка имеет магический комментарий, она возвращает строку в кодировке, указанной в магическом комментарии.

# -*- coding: utf-8 -*-
require 'erb'

template = ERB.new <<EOF
<%#-*- coding: Big5 -*-%>
  \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
EOF
puts template.result

Вывод: _ENCODING_ равно Big5.

Примеры

Обычный текст

ERB полезен для любых ситуаций общей шаблонизации. Обратите внимание, что в этом примере мы используем удобный тег «% в начале строки», и мы буквально цитируем шаблон с %q{...}, чтобы избежать проблем с обратными слешами.

require "erb"

# Create template.
template = %q{
  From:  James Edward Gray II <james@grayproductions.net>
  To:  <%= to %>
  Subject:  Addressing Needs

  <%= to[/\w+/] %>:

  Just wanted to send a quick note assuring that your needs are being
  addressed.

  I want you to know that my team will keep working on the issues,
  especially:

  <%# ignore numerous minor requests -- focus on priorities %>
  % priorities.each do |priority|
    * <%= priority %>
  % end

  Thanks for your patience.

  James Edward Gray II
}.gsub(/^  /, '')

message = ERB.new(template, trim_mode: "%<>")

# Set up template data.
to = "Community Spokesman <spokesman@ruby_community.org>"
priorities = [ "Run Ruby Quiz",
               "Document Modules",
               "Answer Questions on Ruby Talk" ]

# Produce result.
email = message.result
puts email

Результат:

From:  James Edward Gray II <james@grayproductions.net>
To:  Community Spokesman <spokesman@ruby_community.org>
Subject:  Addressing Needs

Community:

Just wanted to send a quick note assuring that your needs are being addressed.

I want you to know that my team will keep working on the issues, especially:

    * Run Ruby Quiz
    * Document Modules
    * Answer Questions on Ruby Talk

Thanks for your patience.

James Edward Gray II

Ruby в HTML

ERB часто используется в файлах .rhtml (HTML с встроенным Ruby). Обратите внимание на необходимость в этом примере предоставить специальное связывание при выполнении шаблона, чтобы можно было разрешить экземпляры переменных в объекте Product.

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

# Create template.
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(template)

# Set up template data.
toy = Product.new( "TZ-1002",
                   "Rubysapien",
                   "Geek's Best Friend!  Responds to Ruby commands...",
                   999.95 )
toy.add_feature("Listens for verbal commands in the Ruby language!")
toy.add_feature("Ignores Perl, Java, and all C variants.")
toy.add_feature("Karate-Chop Action!!!")
toy.add_feature("Matz signature on left leg.")
toy.add_feature("Gem studded eyes... Rubies, of course!")

# Produce result.
rhtml.run(toy.get_binding)

Результат (некоторые пустые строки удалены):

<html>
  <head><title>Ruby Toys -- Rubysapien</title></head>
  <body>

    <h1>Rubysapien (TZ-1002)</h1>
    <p>Geek's Best Friend!  Responds to Ruby commands...</p>

    <ul>
        <li><b>Listens for verbal commands in the Ruby language!</b></li>
        <li><b>Ignores Perl, Java, and all C variants.</b></li>
        <li><b>Karate-Chop Action!!!</b></li>
        <li><b>Matz signature on left leg.</b></li>
        <li><b>Gem studded eyes... Rubies, of course!</b></li>
    </ul>

    <p>
         Call for a price, today!
    </p>

  </body>
</html>

Примечания

В различных проектах Ruby доступно множество решений для шаблонизации:

  • Большой брат ERB, eRuby, работает так же, но написан на C для повышения скорости;

  • Amrita (умеет создавать HTML/XML);

  • cs/Template (написан на C для повышения скорости);

  • RDoc, поставляется с Ruby, использует собственный движок шаблонов, который может быть повторно использован;

  • и другие; поищите на RubyGems.org или Ruby Toolbox.

Фреймворк веб-приложений Rails использует ERB для создания представлений.

Константы

NOT_GIVEN

Атрибуты

encoding[R]

Кодировка для оценки.

filename[RW]

Необязательный аргумент filename, передаваемый в Kernel#eval при выполнении кода ERB.

lineno[RW]

Необязательный аргумент lineno, передаваемый в Kernel#eval при выполнении кода ERB.

src[R]

Код Ruby, сгенерированный ERB.

Публичные методы класса

new(str, safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, trim_mode: nil, eoutvar: '_erbout') Показать исходный код
# File lib/erb.rb, line 813
def initialize(str, safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, trim_mode: nil, eoutvar: '_erbout')
  # Complex initializer for $SAFE deprecation at Feature #14256, which should be removed at Ruby 2.7.
  if safe_level != NOT_GIVEN
    warn 'Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.', uplevel: 1 if $VERBOSE
  else
    safe_level = nil
  end
  if legacy_trim_mode != NOT_GIVEN
    warn 'Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.', uplevel: 1 if $VERBOSE
    trim_mode = legacy_trim_mode
  end
  if legacy_eoutvar != NOT_GIVEN
    warn 'Passing eoutvar with the 4th argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.', uplevel: 1 if $VERBOSE
    eoutvar = legacy_eoutvar
  end

  @safe_level = safe_level
  compiler = make_compiler(trim_mode)
  set_eoutvar(compiler, eoutvar)
  @src, @encoding, @frozen_string = *compiler.compile(str)
  @filename = nil
  @lineno = 0
end

Создаёт новый объект ERB с шаблоном, указанным в str.

Объект ERB работает путём создания фрагмента кода Ruby, который выведет готовый шаблон при выполнении. Если safe_level установлено в ненулевое значение, код ERB будет выполнен в отдельном потоке с $SAFE, установленным на заданный уровень.

Если trim_mode передаётся в строке, содержащей один или несколько следующих модификаторов, ERB скорректирует генерацию кода, как указано:

%  enables Ruby code processing for lines beginning with %
<> omit newline for lines starting with <% and ending in %>
>  omit newline for lines ending in %>
-  omit blank lines ending in -%>

eoutvar может быть использован для установки имени переменной, в которой ERB будет накапливать свой вывод. Это полезно, когда вам нужно выполнить несколько шаблонов ERB через один и тот же контекст и/или когда вы хотите контролировать, куда попадает вывод. Передайте имя переменной, используемой внутри String.

Пример

require "erb"

# build data class
class Listings
  PRODUCT = { :name => "Chicken Fried Steak",
              :desc => "A well messages pattie, breaded and fried.",
              :cost => 9.95 }

  attr_reader :product, :price

  def initialize( product = "", price = "" )
    @product = product
    @price = price
  end

  def build
    b = binding
    # create and run templates, filling member data variables
    ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@product").result b
      <%= PRODUCT[:name] %>
      <%= PRODUCT[:desc] %>
    END_PRODUCT
    ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@price").result b
      <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
      <%= PRODUCT[:desc] %>
    END_PRICE
  end
end

# setup template data
listings = Listings.new
listings.build

puts listings.product + "\n" + listings.price

Генерирует

Chicken Fried Steak
A well messages pattie, breaded and fried.

Chicken Fried Steak -- 9.95
A well messages pattie, breaded and fried.
version() Показать исходный код
# File lib/erb.rb, line 264
def self.version
  "erb.rb [2.2.0 #{ERB::Revision.split[1]}]"
end

Возвращает информацию о ревизии для модуля erb.rb.

Публичные методы экземпляра

def_class(superklass=Object, methodname='result') Показать исходный код
# File lib/erb.rb, line 973
def def_class(superklass=Object, methodname='result')
  cls = Class.new(superklass)
  def_method(cls, methodname, @filename || '(ERB)')
  cls
end

Определяет безымянный класс, у которого methodname является методом экземпляра, и возвращает его.

пример:

class MyClass_
  def initialize(arg1, arg2)
    @arg1 = arg1;  @arg2 = arg2
  end
end
filename = 'example.rhtml'  # @arg1 and @arg2 are used in example.rhtml
erb = ERB.new(File.read(filename))
erb.filename = filename
MyClass = erb.def_class(MyClass_, 'render()')
print MyClass.new('foo', 123).render()
def_method(mod, methodname, fname='(ERB)') Показать исходный код
# File lib/erb.rb, line 937
def def_method(mod, methodname, fname='(ERB)')
  src = self.src.sub(/^(?!#|$)/) {"def #{methodname}\n"} << "\nend\n"
  mod.module_eval do
    eval(src, binding, fname, -1)
  end
end

Определяет methodname как метод экземпляра mod из скомпилированного кода Ruby.

пример:

filename = 'example.rhtml'   # 'arg1' and 'arg2' are used in example.rhtml
erb = ERB.new(File.read(filename))
erb.def_method(MyClass, 'render(arg1, arg2)', filename)
print MyClass.new.render('foo', 123)
def_module(methodname='erb') Показать исходный код
# File lib/erb.rb, line 954
def def_module(methodname='erb')
  mod = Module.new
  def_method(mod, methodname, @filename || '(ERB)')
  mod
end

Создаёт безымянный модуль, определяет methodname как метод экземпляра, и возвращает его.

пример:

filename = 'example.rhtml'   # 'arg1' and 'arg2' are used in example.rhtml
erb = ERB.new(File.read(filename))
erb.filename = filename
MyModule = erb.def_module('render(arg1, arg2)')
class MyClass
  include MyModule
end
location=((filename, lineno)) Показать исходный код
# File lib/erb.rb, line 860
def location=((filename, lineno))
  @filename = filename
  @lineno = lineno if lineno
end
make_compiler(trim_mode) Показать исходный код
# File lib/erb.rb, line 842
def make_compiler(trim_mode)
  ERB::Compiler.new(trim_mode)
end

Создаёт новый компилятор для ERB. См. ERB::Compiler.new для деталей.

result(b=new_toplevel) Показать исходный код
# File lib/erb.rb, line 890
def result(b=new_toplevel)
  if @safe_level
    proc do
      prev_safe_level = $SAFE
      $SAFE = @safe_level
      eval(@src, b, (@filename || '(erb)'), @lineno)
    ensure
      $SAFE = prev_safe_level
    end.call
  else
    eval(@src, b, (@filename || '(erb)'), @lineno)
  end
end

Выполняет сгенерированный код ERB для создания завершённого шаблона, возвращая результаты этого кода. (См. ERB::new для подробностей о том, как этот процесс может быть затронут safe_level.)

b принимает объект Binding, который используется для настройки контекста оценки кода.

result_with_hash(hash) Показать исходный код
# File lib/erb.rb, line 906
def result_with_hash(hash)
  b = new_toplevel(hash.keys)
  hash.each_pair do |key, value|
    b.local_variable_set(key, value)
  end
  result(b)
end

Отображает шаблон в новой среде связывания с локальными переменными, заданными объектом Hash.

run(b=new_toplevel) Показать исходный код
# File lib/erb.rb, line 878
def run(b=new_toplevel)
  print self.result(b)
end

Генерирует результаты и выводит их. (См. ERB#result)

set_eoutvar(compiler, eoutvar = '_erbout') Показать исходный код
# File lib/erb.rb, line 870
def set_eoutvar(compiler, eoutvar = '_erbout')
  compiler.put_cmd = "#{eoutvar}.<<"
  compiler.insert_cmd = "#{eoutvar}.<<"
  compiler.pre_cmd = ["#{eoutvar} = +''"]
  compiler.post_cmd = [eoutvar]
end

Может быть использован для установки eoutvar, как описано в ERB::new. Однако, скорее всего, проще использовать конструктор, так как вызов этого метода требует настройки объекта ERB compiler.

Приватные методы экземпляра

new_toplevel(vars = nil) Показать исходный код
# File lib/erb.rb, line 918
def new_toplevel(vars = nil)
  b = TOPLEVEL_BINDING
  if vars
    vars = vars.select {|v| b.local_variable_defined?(v)}
    unless vars.empty?
      return b.eval("tap {|;#{vars.join(',')}| break binding}")
    end
  end
  b.dup
end

Возвращает новую среду связывания каждый раз, когда близка к TOPLEVEL_BINDING для запусков, не указывающих среду связывания.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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