user14390627
user14390627

Reputation:

Puppet array loop in erb template

I have the following Yaml:

role::test::logos::filesanddata:
  logo01.jpg:
    title01: 'value01'
    title02: 'value02'
    title03: 'value03'
    title04: 'value04'
    title05: 'value05'
    title06: 'value06'
    title07:
      - title07_01: value07_01
      - title07_02: value07_02
      - title07_03: value07_03
      - title07_04: value07_03
      - title07_05: value07_04
  logo02.jpg:
    title01: 'value01'

Through my Class (in Puppet code) am getting the following result:

["logo01.jpg", {"title01"=>"value01", "title02"=>"value02", "title03"=>"value03", "title04"=>"value04", "title05"=>"value05", "title06"=>"value06", "title07"=>[{"title07_01"=>"value07_01"}, {"title07_02"=>"value07_02"}, {"title07_03"=>"value07_03"}, {"title07_04"=>"value07_04"}, {"title07_05"=>"value07_05}]}]
["logo02.jpg", {"title01"=>"value01"}]

I am writing a template to split the data in multiple files (so far works). I am stuck on the item "title07", how should I continue the loop from there?

<%= @arraydata[0] %>
<% @arraydata.shift -%>
<% @arraydata.each do |item| -%>

  <%= item['title01'] %>
  <%= item['title02'] %>
  <%= item['title03'] %>
  <%= item['title04'] %>
  <%= item['title05'] %>
  <%= item['title06'] %>

  <%  item['title07'].each do |inner_item| -%>
    <%= inner_item['title07']['title07_01'] %>
  <% end -%>

<% end -%>

Upvotes: 0

Views: 3727

Answers (2)

balder
balder

Reputation: 799

Its not clear to me what the end goal is however hopefully the below example should help you unblock the issues you have

given the following hiera data:

role::test::logos::filesanddata:
  logo01.jpg:
    title01: 'value01'
    title02: 'value02'
    title03: 'value03'
    title04: 'value04'
    title05: 'value05'
    title06: 'value06'
    title07:
      - title07_01: value07_01
      - title07_02: value07_02
      - title07_03: value07_03
      - title07_04: value07_03
      - title07_05: value07_04
  logo02.jpg:
    title01: 'value01'

The following code assuming filesanddata = lookup('role::test::logos::filesanddata')

<% @filesanddata.each_pair do |file, titles| -%>
  <%- titles.each_pair do |title, values| -%> 
    <%- if values.is_a?(String) -%>
  <%= value %>
    <%- elsif value.is_a?(Array) -%>
      <%# As mentioned by John Bollinger you have an array %>
      <%# of hashes so we have to unpack that as well %>
      <%-  values.each do |value_hash| -%>
        <%-  value_hash.each_pair do |_, value| -%>
  <%= value %>
        <%- end -%>
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>

would create a file with the following content

  value01
  value02
  value03
  value04
  value05
  value06
  value07_01
  value07_02
  value07_03
  value07_03
  value07_04
  value01

Upvotes: 1

John Bollinger
John Bollinger

Reputation: 180201

There seems to be confusion both in the data and in the ERB about how the data are structured. This YAML ...

    title07:
      - title07_01: value07_01
      - title07_02: value07_02
      - title07_03: value07_03
      - title07_04: value07_03
      - title07_05: value07_04

... provides an array of single-key hashes as the value of the host hash's 'title07' key. That's not necessarily wrong, but it's very suspicious. It's unclear what thge array layer is supposed to be doing for you, relative to making the data a single five-element hash.

Consider the ERB presented in light of that data structure. Here ...

  <%  item['title07'].each do |inner_item| -%>

... item['title07'] is an array of single-key hashes, so each inner_item is one of those hashes. The one key appearing in that hash varies from hash to hash, which makes these unnecessarily difficult to work with. None of the keys is 'title07', however, so this will break:

    <%= inner_item['title07']['title07_01'] %>

You would need something along the lines of

    <%= inner_item['title07_01'] %>

, but accounting for the fact that the key differs from inner_item to inner_item. If you really want to try to work with that, then you might find it useful to use each_with_index instead of each, so that you can construct the needed hash key from the array index. Alternatively, you could just iterate the inner hash to get the value.

But that demonstrates some of the infelicities of that data structure. Suppose that you instead structured the data as a single multi-key hash, bypassing the array level:

title07:
  title07_01: value07_01
  title07_02: value07_02
  title07_03: value07_03
  title07_04: value07_03
  title07_05: value07_04

Then iterating over the entries probably gets you what you want more directly:

  <%  item['title07'].each do |_, value| -%>
    <%= value %>
  <% end -%>

Alternatively, since the keys have a computable form you can compute the keys with which to retrieve the leaf data:

  <%  1...5.each do |i| -%>
    <%= item['title07']["title07_0#{i}"] %>
  <% end -%>

Similar could be made to work with your array-based structure, too, but the needed expression would be more complex (and is left as an exercise).

Upvotes: 1

Related Questions