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
(或由 ERB
生成的 Ruby 代码)返回与输入字符串相同的字符编码的字符串。但是,当输入字符串有魔术注释时,它会返回以魔术注释指定的编码的字符串。
# -*- 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 <[email protected]> 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 <[email protected]> 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
HTML 中的 Ruby¶ ↑
ERB
通常用于 .rhtml
文件(包含嵌入式 Ruby 的 HTML)。请注意,在此示例中需要在运行模板时提供特殊绑定,以便可以解析 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 项目中提供了各种模板化解决方案。例如,Ruby 中分发的 RDoc
使用其自己的模板引擎,该引擎可以在其他地方重复使用。
可以在 The Ruby Toolbox 的相应 类别 中找到其他流行的引擎。
常量
- NOT_GIVEN
- VERSION
属性
要 eval 的编码
运行 ERB
代码时传递给 Kernel#eval
的可选 filename 参数
运行 ERB
代码时传递给 Kernel#eval
的可选 lineno 参数
由 ERB
生成的 Ruby 代码
公共类方法
使用 str 中指定的模板构建新的 ERB
对象。
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 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.rb 模块的修订信息。
# File lib/erb.rb, line 266 def self.version VERSION 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 500 def def_class(superklass=Object, methodname='result') cls = Class.new(superklass) def_method(cls, methodname, @filename || '(ERB)') cls end
从编译的 Ruby 源中将methodname定义为mod的实例方法。
示例
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 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定义为它的实例方法,并返回它。
示例
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 481 def def_module(methodname='erb') mod = Module.new def_method(mod, methodname, @filename || '(ERB)') mod 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 394 def location=((filename, lineno)) @filename = filename @lineno = lineno if lineno end
为 ERB
创建一个新的编译器。有关详细信息,请参阅 ERB::Compiler.new
# File lib/erb.rb, line 361 def make_compiler(trim_mode) ERB::Compiler.new(trim_mode) end
执行生成的 ERB
代码以生成一个完整的模板,返回该代码的结果。(有关此过程如何受safe_level影响的详细信息,请参阅 ERB::new
。)
b 接受一个 Binding
对象,该对象用于设置代码评估的上下文。
# 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
使用 Hash
对象指定的局部变量在新顶级绑定上呈现模板。
# 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
生成结果并打印它们。(参见 ERB#result
)
# File lib/erb.rb, line 412 def run(b=new_toplevel) print self.result(b) end
私有实例方法
每次都返回一个新的绑定,该绑定对于未指定绑定的运行接近 TOPLEVEL_BINDING。
# 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