iva*_*off 53 ruby syntax templates erb
我有一个内联到Ruby代码的ERB模板:
require 'erb'
DATA = {
:a => "HELLO",
:b => "WORLD",
}
template = ERB.new <<-EOF
current key is: <%= current %>
current value is: <%= DATA[current] %>
EOF
DATA.keys.each do |current|
result = template.result
outputFile = File.new(current.to_s,File::CREAT|File::TRUNC|File::RDWR)
outputFile.write(result)
outputFile.close
end
Run Code Online (Sandbox Code Playgroud)
我无法将变量"current"传递给模板.
错误是:
(erb):1: undefined local variable or method `current' for main:Object (NameError)
Run Code Online (Sandbox Code Playgroud)
我该如何解决?
tok*_*and 61
对于简单的解决方案,请使用OpenStruct:
require 'erb'
require 'ostruct'
namespace = OpenStruct.new(name: 'Joan', last: 'Maragall')
template = 'Name: <%= name %> <%= last %>'
result = ERB.new(template).result(namespace.instance_eval { binding })
#=> Name: Joan Maragall
Run Code Online (Sandbox Code Playgroud)
上面的代码很简单,但有(至少)两个问题:1)由于它依赖于OpenStruct,对一个不存在的变量的访问返回,nil而你可能更喜欢它失败了.2)binding在一个块中调用,就是它,在一个闭包中,所以它包含了作用域中的所有局部变量(实际上,这些变量将遮蔽struct的属性!).
所以这是另一个解决方案,更详细,但没有任何这些问题:
class Namespace
def initialize(hash)
hash.each do |key, value|
singleton_class.send(:define_method, key) { value }
end
end
def get_binding
binding
end
end
template = 'Name: <%= name %> <%= last %>'
ns = Namespace.new(name: 'Joan', last: 'Maragall')
ERB.new(template).result(ns.get_binding)
#=> Name: Joan Maragall
Run Code Online (Sandbox Code Playgroud)
当然,如果您要经常使用它,请确保创建一个String#erb允许您编写类似内容的扩展名"x=<%= x %>, y=<%= y %>".erb(x: 1, y: 2).
asf*_*fer 25
使用绑定的简单解决方案:
b = binding
b.local_variable_set(:a, 'a')
b.local_variable_set(:b, 'b')
ERB.new(template).result(b)
Run Code Online (Sandbox Code Playgroud)
iva*_*off 10
得到它了!
我创建了一个绑定类
class BindMe
def initialize(key,val)
@key=key
@val=val
end
def get_binding
return binding()
end
end
Run Code Online (Sandbox Code Playgroud)
并将实例传递给ERB
dataHash.keys.each do |current|
key = current.to_s
val = dataHash[key]
# here, I pass the bindings instance to ERB
bindMe = BindMe.new(key,val)
result = template.result(bindMe.get_binding)
# unnecessary code goes here
end
Run Code Online (Sandbox Code Playgroud)
.erb模板文件如下所示:
Key: <%= @key %>
Run Code Online (Sandbox Code Playgroud)
在原始问题的代码中,只需替换
result = template.result
Run Code Online (Sandbox Code Playgroud)
同
result = template.result(binding)
Run Code Online (Sandbox Code Playgroud)
这将使用每个块的上下文而不是顶级上下文.
(刚刚将@sciurus的评论作为答案提取出来,因为它是最短且最正确的评论.)
小智 6
require 'erb'
class ERBContext
def initialize(hash)
hash.each_pair do |key, value|
instance_variable_set('@' + key.to_s, value)
end
end
def get_binding
binding
end
end
class String
def erb(assigns={})
ERB.new(self).result(ERBContext.new(assigns).get_binding)
end
end
Run Code Online (Sandbox Code Playgroud)
REF:http://stoneship.org/essays/erb-and-the-context-object/