如果模板中缺少值,则ruby ERB类将静默继续。
例如@config['bar']
和ENV['DOESNTEXIST']
未定义。
require 'erb'
@config = {}
@config['foo'] = 42
template = ERB.new <<-EOF
FOO=<%= @config['foo'] %>
BAR=<%= @config['bar'] %>
LANG=<%= ENV['LANG'] %>
BAD=<%= ENV['DOESNTEXIST'] %>
EOF
template.result(binding)
输出
FOO=42
BAR=
LANG=en_US.UTF-8
BAD=
所需的输出
Warning: @config['bar'] is undefined
Warning: ENV['DOESNTEXIST'] is undefined
FOO=42
BAR=
LANG=en_US.UTF-8
BAD=
是否可以警告ERB模板是否为零或未定义值?
有没有办法显示erb模板中的所有变量,以便我可以遍历它们进行验证?
我不了解模板的所有值,因为用户可以指定自己的模板。
我尝试过的事情:
template.inspect
给了我一个显示占位符的字符串。我可以过滤子字符串,但这是不可靠的。
template.inspect
=> "#<ERB:0x00007ff4e50b1288 @safe_level=nil, @src=\"#coding:UTF-8\\n_erbout = +''; _erbout.<< \\\" FOO=\\\".freeze; _erbout.<<(( @config['foo'] ).to_s); _erbout.<< \\\"\\\\n BAR=\\\".freeze\\n; _erbout.<<(( @config['bar'] ).to_s); _erbout.<< \\\"\\\\n LANG=\\\".freeze\\n; _erbout.<<(( ENV['LANG'] ).to_s); _erbout.<< \\\"\\\\n BAD=\\\".freeze\\n; _erbout.<<(( ENV['DOESNT EXIST'] ).to_s); _erbout.<< \\\"\\\\n\\\".freeze\\n; _erbout\", @encoding=#<Encoding:UTF-8>, @frozen_string=nil, @filename=nil, @lineno=0>"`
更新:我承认这个问题的措词不是很清楚。问题的实质是如何将像"@config['foo']"
这样的字符串转换成像@config['foo']
这样的变量?
我了解到,这通常是通过eval()
完成的,它存在已知问题。
相关问题:how can i avoid eval in this situation
答案 0 :(得分:1)
使用fetch
。从文档中:
从散列返回给定键的值。如果找不到密钥,则有几种选择:没有其他参数,它将引发KeyError异常;如果给定默认值,则将返回该值;如果指定了可选代码块,则将运行该代码块并返回其结果。
具有您所描述的行为的不仅是ERB;还包括您所描述的行为。每当哈希中没有任何内容时,任何Ruby数组都将返回nil
。我们希望它在出现某些缺失时“快速失败”。
2.5.1 :000 > {foo: "something"}[:foo]
=> "something"
2.5.1 :001 > {foo: "something"}[:bar]
=> nil
使用fetch
访问@config
中的项目:
2.5.1 :000 > @config = {foo: "something"}
=> "something"
2.5.1 :001 > @config.fetch(:foo)
=> "something"
2.5.1 :002 > @config.fetch(:bar)
KeyError (key not found: :bar)
在代码中使用fetch
来检索不存在的bar
将返回以下内容:
undefined local variable or method `‘bar’' for main:Object
这不是警告,因为最初的问题是错误。如果只需要警告,则fetch
接受默认值作为可以充当该角色的第二个参数。
答案 1 :(得分:0)
一种选择是使用正则表达式过滤掉所有样式,例如<%= -%>
和<%= %>
。
text.scan(/<%= ?([^>]+) -?%>/)
哪个会回来
=> [["@config['foo']"], ["@config['bar']"], ["ENV['LANG']"], ["ENV['DOESNTEXIST']"]]
然后使用eval()
验证变量@config['foo']
存在。因为eval()
很危险,所以最好将允许计算的变量列入白名单。在这种情况下,仅允许使用@config[;
和ENV['
之类的字符串。
require 'erb'
@config = {}
@config['foo'] = 42
text = <<-EOF
FOO=<%= @config['foo'] %>
BAR=<%= @config['bar'] %>
LANG=<%= ENV['LANG'] %>
BAD=<%= ENV['DOESNTEXIST'] %>
EOF
# Match strings like <%= -%> and <%= %>
variables = text.scan(/<%= ?([^>]+) -?%>/)
template = ERB.new text
template.result(binding)
# Only evaluate variables that start with '@config' or 'ENV'
variables.each do |variable|
if variable.start_with?("@config")
variable.sub!("@config", "")
@config2 = builder.instance_variable_get("@config")
puts "WARNING: Undefined variable: @config#{variable}" unless eval("@config2#{variable}")
elsif variable.start_with?("ENV")
puts "WARNING: Undefined variable: #{variable}" unless eval(variable)
else
raise "Variable '#{variable}' not allowed"
end
end