класс 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 %> (`<% #` doesn't work. Don't use Ruby comments.) % 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:
-
характер распознаваемых тегов;
-
связывание, используемое для разрешения локальных переменных в шаблоне.
См. методы 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 доступно множество решений для шаблонизации. Например, RDoc, поставляемый с Ruby, использует собственный движок шаблонов, который можно повторно использовать в других местах.
Другие популярные движки можно найти в соответствующей Категории Ruby Toolbox.
Константы
- NOT_GIVEN
- VERSION
Атрибуты
Кодировка для вычисления.
Дополнительный аргумент filename, передаваемый в Kernel#eval при выполнении кода ERB.
Дополнительный аргумент lineno, передаваемый в Kernel#eval при выполнении кода ERB.
Код Ruby, сгенерированный ERB.
Публичные Классовые Методы
# File lib/erb.rb, line 334
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]. Use keyword arguments to pass trim_mode or eoutvar.
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
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
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
eoutvar = legacy_eoutvar
end
compiler = make_compiler(trim_mode)
set_eoutvar(compiler, eoutvar)
@src, @encoding, @frozen_string = *compiler.compile(str)
@filename = nil
@lineno = 0
@_init = self.class.singleton_class
end Создаёт новый объект ERB с шаблоном, указанным в str.
Объект ERB работает путём создания куска кода Ruby, который выведет завершённый шаблон при выполнении.
Если trim_mode содержит один или несколько из следующих модификаторов в виде String, 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', trim_mode: "", eoutvar: "@product").result b
<%= PRODUCT[:name] %>
<%= PRODUCT[:desc] %>
END_PRODUCT
ERB.new(<<~'END_PRICE', 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.
# File lib/erb.rb, line 266 def self.version VERSION end
Возвращает информацию о ревизии модуля erb.rb.
Публичные Методы Экземпляров
# File lib/erb.rb, line 500 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()
# File lib/erb.rb, line 464
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)
# File lib/erb.rb, line 481 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
# File lib/erb.rb, line 394 def location=((filename, lineno)) @filename = filename @lineno = lineno if lineno end
Устанавливает необязательные имя файла и номер строки, которые будут использоваться в ERB для оценки кода и сообщений об ошибках. См. также filename= и lineno=
erb = ERB.new('<%= some_x %>')
erb.render
# undefined local variable or method `some_x'
# from (erb):1
erb.location = ['file.erb', 3]
# All subsequent error reporting would use new location
erb.render
# undefined local variable or method `some_x'
# from file.erb:4
# File lib/erb.rb, line 361 def make_compiler(trim_mode) ERB::Compiler.new(trim_mode) end
Создаёт новый компилятор для ERB. Подробности см. в ERB::Compiler.new.
# File lib/erb.rb, line 424
def result(b=new_toplevel)
unless @_init.equal?(self.class.singleton_class)
raise ArgumentError, "not initialized"
end
eval(@src, b, (@filename || '(erb)'), @lineno)
end Выполняет сгенерированный код ERB для создания завершенного шаблона, возвращая результаты этого кода. (См. ERB::new для подробностей о том, как этот процесс может быть изменён параметром safe_level.)
b принимает объект Binding, используемый для установки контекста оценки кода.
# File lib/erb.rb, line 433
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.
# File lib/erb.rb, line 412 def run(b=new_toplevel) print self.result(b) end
Генерирует результаты и выводит их. (см. ERB#result)
# File lib/erb.rb, line 404
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.
Приватные Методы Экземпляров
# File lib/erb.rb, line 445
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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.