Uploaded image for project: 'CFEngine Community'
  1. CFEngine Community
  2. CFE-2125

Mustache iterates over hashes when rendering

    XMLWordPrintable

    Details

    • Platform:
      Debian, Linux

      Description

      Mustache template rendering duplicates data with

      Expected output:

      # Mustache duplication issue test
      
      # Test1
      Data = v1
      Data = v2
      
      # Test2
      Data = v1
      Data = v2
      Other data = v3
      Other data = v4
      
      

      Produced output (note data duplication in Test2 series):

      # Mustache duplication issue test
      
      # Test1
      Data = v1
      Data = v2
      
      # Test2
      Data = v1
      Data = v2
      Other data = v3
      Other data = v4
      Data = v1
      Data = v2
      Other data = v3
      Other data = v4
      

      This was discussed on #cfengine. Here is the chat log excerpt:

      14:38|  TedZ| OK, I'll look at just JSON then
      14:43|  TedZ| OK, I see it.  When you iterate over a key-value container, you iterate over every key and value pair.
      14:43|  TedZ| so your template for test 2 sees two keys and iterates twice.
      14:44|  TedZ| simply change test2 to an array wrapping the key-value container:     "test2": [{
      14:44|  TedZ|       "data": [
      14:44|  TedZ|         "v1",
      14:44|  TedZ|         "v2"
      14:44|  TedZ|       ],
      14:44|  TedZ|       "otherdata": [
      14:44|  TedZ|         "v3",
      14:44|  TedZ|         "v4"
      14:44|  TedZ|       ]
      14:44|  TedZ|     }]
      14:44|  TedZ|  
      14:44|  TedZ| sorry for the paste, I didn't mean to flood
      14:45|         * neilhwatson head hurts
      14:45|  cfbot| If you write your own CFEngine policy make it as reusable as possible.
      14:46|  dsx| ok, why that worked in 3.6?
      14:46|  TedZ| dsx is iterating over test2.  test2 has two things in it.  So the template iterates twice.
      14:46|  neilhwatson| What if the template had stated test2.data rather than data?
      14:47|  TedZ| dsx: not sure, my guess is that it was a bug in 3.6.  I would check the official Mustache spec to be sure about this, but I think I'm right.
      14:47|  TedZ| neilhwatson: test2.data inside the test2 iteration would look for test2.test2.data
      14:49|  dsx| TedZ: as far as I know, mustache came from JS world, and in JS iterating over a map would essentially iterate over map keys
      14:52|  TedZ| right, so the behavior is correct and my workaround seems the best way forward.
      14:59|  dsx| TedZ: no, behavior is not correct. also, if you have time and curiosity, here is the official demo: http://mustache.github.io/#demo and here is template and 
                   data to put in: http://hastebin.com/efawofifew.txt
      15:06|  TedZ| dsx: at this point I'd take your example and open a ticket.  It seems like we have a disagreement on the official spec.  From 
                    https://mustache.github.io/mustache.5.html I am certain non-empty lists are rendered sequentially, but it's not clear if key-value containers are treated as 
                    lists, and they don't have a specific iteration behavior.  We're not going to resolve it here, but I think we've at least understood the problem.
      

      Some policy for CFE-2125

      bundle agent main
      {
        vars:
      
            "data" data => '{
                              "object0": {
                                "object0-0": {
                                  "object0-0-0": [
                                    "v1",
                                    "v2"
                                  ]
                                },
                                "object0-1": {
                                  "object0-1-0": [
                                    "v1",
                                    "v2"
                                  ],
                                  "object0-1-1": [
                                    "v3",
                                    "v4"
                                  ]
                                }
                              },
                             "object1": [ "object1-val1", "object1-val2" ],
                             "non-false": {
                               "color": "blue"
                             },
                             "false": false
                            }';
      
      
          # Iterate over top object rendering keys with custom extension. -top- is
          # also a custom extension
      
            "iterate_object_keys" string => "# Iterate over custom -top- object rendering keys with custom extension `@`.
      {{#-top-}}{{@}}
      {{/-top-}}";
      
            "at_also_iterate_array_vals" string => "# Iterate over array rendering keys (postion) with custom variable `@`.
      {{#object1}}Iterate array key {{@}} = {{.}}
      {{/object1}}";
      
            "iterate_array_vals" string => "# Iterate over array rendering keys with standard variable `.`
      {{#object1}}Data = {{.}}
      {{/object1}}";
      
            "iterate_deep_array_vals" string => "# Iterate over deep/nested array rendering keys with standard variable `.`
      {{#object0.object0-0.object0-0-0}}object0.object0-0.object0-0-0 = {{.}}
      {{/object0.object0-0.object0-0-0}}";
      
          # Use non-false value as context for single rendering of block
            "deep_object_no_sub_objects" string => "# Use a deep object reference to provide the context for the template
      {{#object0.object0-1.object0-1-0}}object0-1-0 Key {{@}}, object0-1-0 Value {{.}}
      {{/object0.object0-1.object0-1-0}}";
      
          # Use non-false value as context for single rendering of block
            "template" string => "# This should not print twice! Why should it NOT behave like deep_object_no_sub_objects above 
      {{#object0.object0-1}}
      {{#object0-1-0}}object0-1-0 Key {{@}}, object0-1-0 Value {{.}}
      {{/object0-1-0}}{{/object0.object0-1}}";
      
        reports:
          "CFEngine $(sys.cf_version)";
      
          "# Data.$(const.n)$(with)"
              with => string_mustache( '{{%-top-}}', @(data) );
      
          "$(with)"
              with => string_mustache( $(iterate_object_keys), @(data) );
      
          "$(with)"
              with => string_mustache( $(at_also_iterate_array_vals), @(data) );
      
          "$(with)"
              with => string_mustache( $(iterate_array_vals), @(data) );
      
          "$(with)"
              with => string_mustache( $(iterate_deep_array_vals), @(data) );
      
          "$(with)"
              with => string_mustache( $(deep_object_no_sub_objects), @(data) );
      
          "$(with)"
              with => string_mustache( $(template), @(data) );
      }
      
      R: CFEngine 3.11.0
      R: # Data.
      {
        "false": false,
        "non-false": {
          "color": "blue"
        },
        "object0": {
          "object0-0": {
            "object0-0-0": [
              "v1",
              "v2"
            ]
          },
          "object0-1": {
            "object0-1-0": [
              "v1",
              "v2"
            ],
            "object0-1-1": [
              "v3",
              "v4"
            ]
          }
        },
        "object1": [
          "object1-val1",
          "object1-val2"
        ]
      }
      R: # Iterate over custom -top- object rendering keys with custom extension `@`.
      object0
      object1
      non-false
      false
      
      R: # Iterate over array rendering keys (postion) with custom variable `@`.
      Iterate array key 0 = object1-val1
      Iterate array key 1 = object1-val2
      
      R: # Iterate over array rendering keys with standard variable `.`
      Data = object1-val1
      Data = object1-val2
      
      R: # Iterate over deep/nested array rendering keys with standard variable `.`
      object0.object0-0.object0-0-0 = v1
      object0.object0-0.object0-0-0 = v2
      
      R: # Use a deep object reference to provide the context for the template
      object0-1-0 Key 0, object0-1-0 Value v1
      object0-1-0 Key 1, object0-1-0 Value v2
      
      R: # This should not print twice! Why should it NOT behave like deep_object_no_sub_objects above 
      object0-1-0 Key 0, object0-1-0 Value v1
      object0-1-0 Key 1, object0-1-0 Value v2
      object0-1-0 Key 0, object0-1-0 Value v1
      object0-1-0 Key 1, object0-1-0 Value v2
      
      

        Attachments

        1. template.mustache
          0.2 kB
        2. test.cf
          2 kB

          Issue Links

            Activity

              People

              • Assignee:
                vpodzime Vratislav Podzimek
                Reporter:
                egor E M
              • Votes:
                1 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Summary Panel