StubbleOrg / Stubble

Trimmed down {{mustache}} templates in .NET
Other
405 stars 58 forks source link

More stable type sorting #92

Closed mingwli closed 4 years ago

mingwli commented 4 years ago

Hi, Stubble is really amazing, but still we got a problem when trying to add a CustomValueGetterfor newtonsoft JArray. The custom valueGetter got sorted after IList.

Further troubleshooting showed that current TypeBySubclassAndAssignableImpl may give unstable result for complex Class and Interface, which may lead to custom valueGetters get ignored.

Take following Types for example:

JArray < IList
IList = IDictionary
JArray = IDictionary

sort (JArray, IList) => stable
sort (JArray, IList, IDictionary) => can't guarantee order

And normally, a custom valueGetter may come with specific class. So putting class ahead of interface is more reasonable to me.

mingwli commented 4 years ago

Could there be a way configuring not to use default value getters?

Romanx commented 4 years ago

Hi there,

Thanks very much for this and the PR. We could definitely add a way to only use the provided value getters, what would the goal be and when would you see this being used?

mingwli commented 4 years ago

background

For some reason we need to support such syntax.

{{#list.0}} list="{{#list}} {{.}}{{/list}}" {{/list.0}}

Since we are using newtonsoft json as data-model, we added our custom value getter for JObject(the ONLY one). And for such data-model

var input = new JObject();
input["Array"] = new JArray() { "Foo", "Bar" };
var a = renderer.Render("{{#Array.0}}s={{#Array}}{{.}}{{/Array}}{{/Array.0}}", input);// => ""

The section doesn't function as expected.

what we tried

So we added a value getter for JArray, and noticed that this getter is not guaranteed to be invoked due to the Type sort mechanism.(sometimes IList get higher priority and sometimes not) And further thinking, we notice that we ONLY pass JObject, JArray and primitive types, so we don't need those default value getters.

Which leads us here : )

mingwli commented 4 years ago

@Romanx After more investigation, we noticed that for following case

template: {{#list.0}} list="{{#list}} {{.}}{{/list}}" {{/list.0}}

var input = new JObject();
input["Array"] = new JArray() { "Foo", "Bar" };
var a = renderer.Render("{{#Array.0}}s={{#Array}}{{.}}{{/Array}}{{/Array.0}}", input);// => ""

is caused by missing JValue type value getter. By adding JValue type value getter and also add it to section blacklist, the template worked. You can close this one : P

Romanx commented 4 years ago

Hi @mingwli if it helps we have a an extension for Newtonsoft.Json here. which includes value getters.

I think the core issue of an unstable sort still needs to be fixed so i'll keep this open while we fix that. Thanks for the report though!

Romanx commented 4 years ago

@mingwli Thanks for the original contribution. I just merged the changes and cut a release. This is in stubble 1.8.4!