Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Displaying section if array exists, *without* iterating each element of array. #1

Open
fletcher opened this issue Aug 12, 2018 · 4 comments

Comments

@fletcher
Copy link
Owner

fletcher commented Aug 12, 2018

Given JSON:

{
	"images": [{
			"src": "http://www.fpoimg.com/20x20"
		},
		{
			"src": "http://www.fpoimg.com/30x30"
		},
		{
			"src": "http://www.fpoimg.com/40x40"
		}
	],
	"anEmptyArray": []
}

and template:

{{#images.length}}
    <h3>The images: this should only be rendered once.</h3>
    <ul>
        {{#images}}
            <li><img src="{{src}}"/></li>
        {{/images}}
    </ul>
{{/images.length}}
{{#anEmptyArray.length}}
    <h3>The empty array: this should NOT be rendered.</h3>
{{/anEmptyArray.length}}

Some Mustache implementations (including the Demo here return:

<h3>The images: this should only be rendered once.</h3>
<ul>
<li><img src="http:&#x2F;&#x2F;www.fpoimg.com&#x2F;20x20"/></li>
<li><img src="http:&#x2F;&#x2F;www.fpoimg.com&#x2F;30x30"/></li>
<li><img src="http:&#x2F;&#x2F;www.fpoimg.com&#x2F;40x40"/></li>
</ul>

The {{#images.length}} tag does not appear to be part of the Mustache spec. For that matter, neither does {{#images.0}} which could be used to refer to the first element of the array.

  • This would seem to be a useful function.
  • It is not part of the spec
  • The spec appears to be dead (no commits in 4 years, no meaningful issue closure in 4 years)
  • The ruby implementation appears to have had at least some activity within the last year, and the website within the last month.

It seems that we are in another "Markdown" scenario where the initial parent project is at least partially dead, whereas one or more child projects are still alive (including this one.) Which is unfortunate.

I will probably end up implementing these features, as they seem useful to me, and do not seem to violate the logic-less philosophy as demonstrated by other core features. But I don't have time at the moment, so this is a reminder to myself.

@nickpelling
Copy link

nickpelling commented Jan 3, 2020

According to this page...

https://stackoverflow.com/questions/11147373/only-show-the-first-item-in-list-using-mustache/17950970

...Mustache.js was updated to allow {{a.0}}, while handlebars.js has been updated to allow {{a.[0]}}. From my perspective, I think this is a very basic omission from vanilla Mustache, because there are innumerable cases where you would need this (e.g. to render a preamble to a list conditional on the list existing, etc).

The direct problem for me is that I'd really like to use Magnum to automate some build tasks, but its (entirely reasonable) lack of Lambdas means that I can only use vanilla Mustache. Hence I'd be happy to put some work in to fix this if you're OK with that?

From looking at the code, it looks as though the least intrusive change would be to h(ij)ack the find() function in src/magnum.c so that if the last dot-delimited section of the name is numeric (i.e. index) and the preceding part of the name refers to an array, it instead returns the object array[index]. Does that make sense to you?

@nickpelling
Copy link

As an aside, the Parson author already considered adding code to handle more general array[n] cases, but decided not to do this (because of a memory leak?):

@fletcher
Copy link
Owner Author

fletcher commented Jan 3, 2020

@nickpelling -- thanks for the comments. And forgive the length of this -- it's partially me just thinking out loud, and partially recording my thoughts for future consideration when I decide I was wrong. ;)

In the almost 2 years since I started magnum, I have been using it quite a bit as is (though have not needed to push many updates, there are one or two edge case bugs I need to track down related to comments, and I am currently working on creating fuzzers to stress test most of my software projects to identify more bugs).

In that time, I have come to appreciate the "stated design philosophy as I understand it" of Mustache (the syntax). IF you consider Mustache as a tool to process a JSON object as it is given to you, then there are some clear limitations of the syntax that create troublesome situations (this being one of them.)

Alternatively, IF you consider the workflow to be:

  1. Convert your source data into an appropriately designed JSON object
  2. That is then processed via Mustache

Then some of their design decisions make more sense.

My most common use case over the last 2 years has been "templated programming" -- my unofficial term for trying to pull out repetitive parts of programming into templates, that are then used to build the desired source code via Magnum/JSON/template arrangements. For example, I created templates that:

  1. Allow me to describe (in JSON) a desired database setup, and then automatically create SQLite and C code to work with said database in a native way.
  2. Use a JSON file to automatically generate Objective-C code to completely manage the preferences window/panes in macOS apps (currently used to develop http://nvultra.com/).

In doing this, I would run up against limits of Mustache only to realize that if I redesigned my JSON, there was no problem. For example, I started out my database idea by using a dataType attribute that would consist of a variety of string values (char, int, date, etc.). I quickly ran into trouble using this approach, but realized that if I instead used a variety of booleans, everything worked fine (isChar, isInt, isDate, etc.)

Similarly, a common situation in my uses is that I need to do something different on the last element of an array as compared to all the other elements (usually whether or not to append a comma). To solve this, I have to remember to include a isLast flag on the last item, and remember to move that flag if I rearrange the order of the array elements.

In my mind, the ultimate question becomes, "How complicated do you make the Mustache syntax in order to accept generic JSON input, or how much care do you require users to take when designing their JSON so that it works properly with Mustache?"

Since I am not the maintainer of Mustache, I obviously don't have the answer. My opinion is that there is benefit to a bare bones, but consistent, feature set for the Mustache syntax across all implementations. Individual implementations will, of course, have some custom features as needed for their particular use cases, but hopefully the core syntax will work across them all.

For magnum, this means:

  1. Trying to keep magnum consistent with the standard test suites for core functionality.

  2. Minimizing the addition of custom functionality, except where it really feels like something is missing from Mustache (in my opinion), or where there is something that I really need (and I fully admit this is arbitrary.)

So far, the custom features that have come up for discussion in magnum are:

  1. This feature of an "if-array exists, without iterating through it" -- this would be convenient, but can be worked around with a boolean hasArray flag if needed. I am still inclined to consider this feature, but it's a bit lower priority.

  2. Automatic detection of "last item in an array" -- this would be handy to have, and while it can also be worked around, the workaround requires extra caution when editing the JSON, as you have to remember to ensure that each relevant array as a lastItem flag in one, and only one, item in the array. I am inclined to add this feature, and consider it higher priority than the first one.

  3. Potentially a array.length or array.item[n] syntax. In my mind, these are getting towards the fringes of what I would consider adding. I'm not arguing their utility, simply questioning whether it expands beyond the core scope of Mustache in a way where a different tool might be better. I am currently inclined not to add these at the moment, as I worry about feature-creep here.

As above, I am still considering these, and do not have a final decision. I also have a lot pressing tasks in my personal, professional, and software lives at the moment, so don't expect any changes soon.

ASIDE: At some point, tools like jq can process JSON that you have less control over to add the necessary flags to be compatible with Mustache. So there are solutions to just about any problem one encounters.

@nickpelling
Copy link

For me, JSON is a great way of decoupling data from code, and Mustache is a great way of generating all manner of useful stuff from JSON.

But the minute you start having to add isFirst and/or isLast flags into the data, the tail is wagging the dog. If you're having to make implicit stuff explicit to get by, something has gone badly wrong.

Personally, I think that Mustache was right to aim to stay minimal: but even so, there is a very strong case for #IsFirst and #IsLast built-in wrappers. These aren't "logic", they are template sequencing helpers that you can use to do preambles and remove trailing commas {{^IfLast}},{{/IfLast}} etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants