定义 Chef ERB 模板方法

Defining a Chef ERB template method

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 -%>

遗憾的是,如果只能return值而不直接输出到ERB模板,这个相对优雅的策略就失效了。

这不是推荐的设计模式。逻辑应该保留在食谱和资源中。也就是说,有可能哪一个是你问题的核心,什么是我最感兴趣的

<%
def say_hi()
-%>
  <% "hi" %>
<%
end
-%>
# Extraneous template data here

<%= say_hi() -%> # Call to template method

这将呈现以下文件

# Extraneous template data here

hi # Call to template method

注意 <%= 块如何获取 say_hi 的 return 值并打印它,而不是从 say_hi 函数本身打印。

这意味着您的函数需要 return 您希望它生成的整个字符串,并且您不能在该方法中使用模板标签。我要说的是,限制本身就违背了在 erb 模板中使用 functions/methods 的目的。

但是,如果 render 是一个可以用来呈现不同部分模板的函数,那将会很有趣...魅力!

鉴于此,我仍然建议坚持在食谱中保留逻辑,并仅在模板中使用循环、条件和打印。我不确定在模板中使用 render 的指导方针是什么,但我觉得不鼓励这样做。