класс 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, в котором выполняется шаблон; -
связывание, используемое для разрешения локальных переменных в шаблоне.
Для получения более подробной информации см. методы ::new и #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, 0, "%<>")
# 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:
-
eRuby, старший брат ERB, работает так же, но написан на C для скорости;
-
Amrita (умён при производстве HTML/XML);
-
cs/Template (написан на C для скорости);
-
RDoc, поставляемый с Ruby, использует собственный движок шаблонов, который можно использовать и в других местах;
-
и другие; поищите на RubyGems.org или The Ruby Toolbox.
Rails, фреймворк для веб-приложений, использует ERB для создания представлений.
Атрибуты
Кодировка для обработки.
Дополнительный аргумент filename, передаваемый в Kernel#eval при выполнении кода ERB.
Дополнительный аргумент lineno, передаваемый в Kernel#eval при выполнении кода ERB.
Код Ruby, сгенерированный ERB.
Публичные методы класса
# File lib/erb.rb, line 807 def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout') @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 через одну и ту же область видимости и/или когда вы хотите контролировать, куда попадает вывод. Передайте имя переменной в виде строки.
Пример
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+/, ""), 0, "", "@product").result b
<%= PRODUCT[:name] %>
<%= PRODUCT[:desc] %>
END_PRODUCT
ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), 0, "", "@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 263
def self.version
"erb.rb [2.1.0 #{ERB::Revision.split[1]}]"
end Возвращает информацию о ревизии модуля erb.rb.
Публичные методы экземпляра
# File lib/erb.rb, line 947 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 911
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 928 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 837 def location=((filename, lineno)) @filename = filename @lineno = lineno if lineno end
# File lib/erb.rb, line 819 def make_compiler(trim_mode) ERB::Compiler.new(trim_mode) end
Создаёт новый компилятор для ERB. Подробнее см. ERB::Compiler.new
# File lib/erb.rb, line 867
def result(b=new_toplevel)
if @safe_level
proc {
$SAFE = @safe_level
eval(@src, b, (@filename || '(erb)'), @lineno)
}.call
else
eval(@src, b, (@filename || '(erb)'), @lineno)
end
end Выполняет сгенерированный код ERB для создания завершённого шаблона, возвращая результаты этого кода. (См. ::new для деталей о том, как этот процесс может быть изменён параметром safe_level.)
b принимает объект Binding, который используется для установки контекста оценки кода.
# File lib/erb.rb, line 880
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 855 def run(b=new_toplevel) print self.result(b) end
Генерирует результаты и выводит их. (см. #result)
# File lib/erb.rb, line 847
def set_eoutvar(compiler, eoutvar = '_erbout')
compiler.put_cmd = "#{eoutvar}.<<"
compiler.insert_cmd = "#{eoutvar}.<<"
compiler.pre_cmd = ["#{eoutvar} = +''"]
compiler.post_cmd = [eoutvar]
end Может быть использован для задания eoutvar, как описано в ::new. Однако, вероятно, проще использовать конструктор, так как вызов этого метода требует подготовки объекта компилятора ERB.
Приватные методы экземпляра
# File lib/erb.rb, line 892
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.