【发布时间】:2015-07-22 04:40:36
【问题描述】:
Chef 非常适合配置基本模板,但我希望加入更高级的模板逻辑。这样的事情可能吗:
<%
def say_hi()
-%>
<%= "hi" %>
<%
end
-%>
# Extraneous template data here
<% say_hi() -%> # Call to template method
在此示例中,我希望每当调用 say_hi() 时都会生成 hi,但它不起作用。
这种行为是否可能,如果没有,有没有办法产生类似的行为?我假设 Chef 模板遵循通用 ERB 模板规则。
谢谢!
更新:一点背景故事
我正在尝试模板化一个非常复杂的config.yml,它有自己的格式方案。它看起来像这样:
key: value
some other key:
- some other value
- another value
hash-like key:
hash-like value:
- element A
- element B
其中有很多,我认为与其直接内联映射属性,不如将它们全部定义在一个公共键下并循环遍历它们:
<% node['section']['help'].each do |key, value| -%>
<%= "#{key}: #{value}" %>
<% end -%>
这很好用!它使我不必定义所有内容两次(一次在属性文件中,一次在模板中),但是我觉得这种结构已经失控了,尤其是对于数组中的嵌套哈希:
<% node['section']['help'].each do |key, value| -%>
<% if value.kind_of?(Hash) -%>
<%= "#{key}: "%>
<% value.each do |subkey, subvalue| -%>
<%= " #{subkey}: #{subvalue}" %>
<% end -%>
<% else -%>
<%= "#{key}: #{value}" %>
<% end -%>
<% end -%>
所以我想创建一个递归方法来识别三种类型(普通值、数组值和哈希值)并处理每种类型的格式。我原型化的完整方法如下所示:
<%
def determine_type(key, value, iteration)
if value.kind_of?(Hash)
-%>
<%= %Q(#{" " * (iteration * 2)} #{key}:) %>
<% value.keys do |subkey, subvalue| -%>
<% determine_type(subkey, subvalue, iteration + 1) -%>
<% end -%>
<%
elsif value.kind_of?(Array)
-%>
<%= %Q(#{" " * (iteration * 2)} #{key}:) %>
<% value.each do |subvalue| -%>
<%= %Q(#{" " * ((iteration + 1) * 2)} - #{subvalue}) %>
<% end -%>
<%
else
-%>
<%= %Q(#{" " * (iteration * 2)} #{key}: #{value}) %>
<%
end
end
-%>
它在这里被调用:
<% node['section']['help'].each do |key, value| -%>
<% determine_type(key, value, 1) -%>
<% end -%>
遗憾的是,如果只能返回值而不能直接输出到 ERB 模板,这个相对优雅的策略就失效了。
【问题讨论】:
-
你试过了吗?输出是什么?用例是什么? (我真的看不出这在哪里有用)。由于对尝试目标的描述如此之少,因此无法知道是否可以使用变量或部分模板。
-
当模板开始包含这么多逻辑时,我发现很难长期维护模板。当模板很简单并且逻辑位于配方或配方调用的库中时,阅读起来会容易得多。
-
函数应该返回字符串,你应该用
=打印函数的结果,就像<%= say_hi %>一样。但是在模板中包含逻辑和功能是一个坏主意。只需创建另一个模板,并在配方中包含使用哪个模板的逻辑。
标签: templates chef-infra erb