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

lamdas with :stencil/pass-render or :stencil/pass-context lose higher-level contexts #38

Open
timclemons opened this issue Jan 13, 2016 · 5 comments

Comments

@timclemons
Copy link

Given the following params:

{:history [{:text "foo"} {:text "bar}]
 :prefix "item:"
 :format-text (with-meta (fn [text context render]
                                         (clojure.string/uppercase (render text context)))
                                       {:stencil/pass-render true})}

And this template:

{{#history}}{{#format-text}}{{prefix}} {{text}}{{/format-text}}{{/history}}

Each invocation of :format-text will be passed only the context of the history item, so top-level items like :prefix will be inaccessible.

@timclemons timclemons changed the title lamdas with :stencil/pass-render or :stencil/pass-context lose higher-level contexts lamdas with :stencil/pass-render or :stencil/pass-context lose higher-level contexts Jan 13, 2016
@timclemons
Copy link
Author

Having had a look at the code, what I would propose is to have callers of call-lambda pass in the entire context-stack, then have the lamda use context-get to obtain the values it needs. This way the context is still fully able to work with calls to 'render'.

@davidsantiago
Copy link
Owner

Hm. I looked at the Mustache spec, and it doesn't really say anything about this. The Mustache spec only goes as far as specifying that lambdas should get the text of their sections, but never says anything about receiving the context. That is something Stencil users have added as a usability extension, and I think it was reasonable.

I remember choosing to only give the current context to a lambda, instead of the entire context stack. My reasoning was that the API was going to be much harder to explain if it was passing a stack of maps, and the writer of the lambda function would have to know the proper way to traverse upwards in this data structure on missing keys. Furthermore, I reasoned, the user of the template usually controls the data map, and could make map entries with the data they needed, if they really needed to. It's a cost of doing business with a very simple template language.

The other issue is that would be a breaking change to the API, and would require any current users of the lambda functionality to rewrite their lambdas to keep them working. I'm open to working on the usability here, but I'm not sure I'm willing to go that far.

@timclemons
Copy link
Author

Ok, so instead of the full context stack, how about collapsing it into a single map using (reduce merge ...) so that higher-level context values override lower-level. This would preserve the API while still allowing access to the lower-level value.

@timclemons
Copy link
Author

Another idea: add another supported metadata :stencil/pass-full-context where call-lambda invokes the lambda with the full stack. If the metadata :stencil/pass-render or :stencil/pass-context are defined, strip off the first item off the context stack and pass that to the lambda.

@timclemons
Copy link
Author

Went with my second idea. Let me know your thoughts.

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