Filters (or pipes) #153
Replies: 9 comments 41 replies
-
I came up with a small but powerful extension to filters in #154 (comment), which I think would offer an elegant solution to the masking problem. Please see that post for the rationale. In that post, I wrote that the first filter in the chain receives a list with fallback values as its second argument. I presented it in that way for simplicity, but I think the second argument actually needs to be a special, implementation-defined object that acts as a proxy to such a list. You probably don't want to fully compute the fallback values before the filter is known to actually use any of those values, firstly because it is expensive and secondly, because any resolved value might be a lambda and invoking that lambda might cause side effects. As a minimal (but sufficient) interface, I suggest that the special object supports a I think this flavor of "power filter" would brilliantly complement a flavor of power lambda that only implements the features 4-7 that I listed in #155. Power filters for ultimate stack access, power lambdas for ultimate template control, and the option to return a lambda from a filter to benefit from both at the same time. ❤️ |
Beta Was this translation helpful? Give feedback.
-
This gets into implementation specifics but I assume one would need to find all the filters apriori before executing a pipeline? There is no chance the pipeline could affect resolution correct? The other question is I assume filter sections only push on the stack if they are the last filter? I'm fairly sure that is the case but that might confuse others. |
Beta Was this translation helpful? Give feedback.
-
@agentgt in #164 (reply in thread):
I think the situation with explaining this to end users is not so dire. You refer to a complicated description that I wrote, but it was complicated because it was directed at a critical audience of implementers. End users can generally rely on their intuition, so the description can be much less detailed. I suggest something like the following: «You may write Of course, there will be end users who just want to get to business and who hate having to learn theory first. As always, you can cater to such users with example code, e.g. "here is how you avoid a trailing comma when separating list items". After the example, you can then write a comment with a link, saying something like «Wonder what that |
Beta Was this translation helpful? Give feedback.
-
@agentgt in #164 (reply in thread):
I have multiple independent answers to this:
|
Beta Was this translation helpful? Give feedback.
-
@agentgt in #163 (reply in thread):
What would you prefer to happen if it fails?
Are these reasons to be opposed to filters in general? What stops you from giving users an alternative that you feel is superior?
Yes, you are doing a good job at that (I mean it). The mental notes I've made so far are:
|
Beta Was this translation helpful? Give feedback.
-
@jgonggrijp I guess the only thing I currently do not like is the name "filter" 😄 . Naming the classic bikeshed. In the Java world the current Also the term "filter" was used in the manual with lambda and it implied more of a textual filter (see below).
Unfortunately So for me I'm currently thinking in order of preference:
I suppose if we kept "filter", I would recommend removing this sentence:
|
Beta Was this translation helpful? Give feedback.
-
On a separate issue (hence top level comment) do we need non-section aka binding filters?
I obviously see how binding filters could be useful but I think section filters can largely do what binding filters do or am I missing something? |
Beta Was this translation helpful? Give feedback.
-
Something that would also have to be addressed in an eventual filters specification, is how pipes interact with dynamic names. For the first time, I just encountered a situation where I might want to use both within a single tag in #178 (reply in thread), where I wrote In #134, it was agreed that dots take precedence over dereference, so The filters proposal as discussed here, implies that dots also take precedence over pipes. Hence, dots take the highest precedence, and the question remains whether pipes precede over dereference or the other way round. In #134 (comment), @bobthecow suggested that dereference would take higher precedence, so it would be possible and allowed to write Today in #178 (reply in thread), I assumed the opposite precedence:
In other words, I probably think that when pipes or other operators come into the picture, the Thoughts? |
Beta Was this translation helpful? Give feedback.
-
What are your thoughts on allowing the last name/key on a pipe to be a lambda? An example might be for i18n (gettext style). {{# blah | preprocess | i18n }}
Hello {{name}}!
{{/ blah | preprocess | i18n }} My only issue is that I can't figure out how dynamic implementations particularly Javascript can disambiguate lambda calls from power filter so that you pass the section body and not the previous output. Then again it is just ergonomics and this is not really that much more typing: {{# blah | preprocess}}
{{#i18n}}
Hello {{name}}!
{{/i18n}}
{{/ blah | preprocess}} |
Beta Was this translation helpful? Give feedback.
-
This is not my own idea, but there was no dedicated ticket for it yet and I thought it deserved one.
@bobthecow gave a semi-formal description of the feature in #41 (comment). He implemented it as described in Mustache.php. There are a few other implementations that include similar features, some of them possibly already before Mustache.php did.
Filters are useful in a variety of common situations that are currently still cumbersome or challenging with standard Mustache:
@index
keyword.#each
helper combined with its@key
keyword.For example, key-value iteration of objects might be implemented using filters, with JavaScript as the host language, as follows.
input data (view)
template
output
Here follows a more formal description of my own interpretation of the feature. I have not implemented it yet, but plan to do so in Wontache.
The filters feature would allow you to write multiple dotted names inside interpolation and section tags, separated by pipe symbols:
Each dotted name (here
a.b.c
,.
,p
,x.y.z
,q
andr
) is resolved from the context in the usual way. The leftmost value (a.b.c
orq
) is used as initial input; the other values should be filters, i.e., functions or methods that take a single argument and return a new value. There are basic fallback rules for when this condition is not met.The input is fed to the filter directly to its right. The output is reused as input for the filter to the right of the previous filter, until there are no more filters in the chain. The final output is used according to the usual rules for the tag, as if that value had been directly retrieved from the context.
For example, in the example interpolation tag above, the following steps would be taken:
a.b.c
,.
(the implicit iterator),p
andx.y.z
are retrieved from the context as usual.a.b.c.
does not exist, or if.
,p
orx.y.z
is not a function that accepts a single argument, skip to step 7 with the empty string as the final result..
is applied to the valuea.b.c
, producing valuek
.p
is applied to the valuek
, producing valuel
.x.y.z
is applied to the valuel
, producing valuem
.m
is the final result.Similarly, for the example section:
q
andr
are retrieved from the context as usual.q
does not exist, or ifr
is not a function that accepts a single argument, use the empty string as the final result and skip to step 5.r
is applied to to the valueq
, producing valuen
.n
is the final result.If the host language supports higher order functions (functions that return functions or function-like objects), then in principle, there is nothing that prevents the last filter in the chain from returning a lambda in the sense of the lambdas extension. This would enable advanced use cases, where a lambda generates a template with knowledge about an arbitrary other value in the context stack. However, it is important to keep in mind that the filters themselves are not lambdas; they might only return lambdas.
Filters and lambdas are both functions (or methods) that are stored in the context along with regular values. There are two key differences:
Beta Was this translation helpful? Give feedback.
All reactions