noahmorrison / chevron

A Python implementation of mustache
MIT License
505 stars 55 forks source link

Make scopes available to lambda functions. #68

Closed ergoithz closed 3 years ago

ergoithz commented 4 years ago

With something like changing the lambda render callable parameter from the current lamda function to a callable object, chevron could cleanly expose the current rendering context (chevron scope) to advanced callable contexts.

In the meantime, we're relying in ugly hacks like:

import threading
import chevron.renderer

def chevron_scopes_from_render(render, _lock=threading.Lock()):

    def capture(*args, **kwargs):
        if threading.get_ident() == ident:
            scopes[:] = kwargs['scopes']
            return ''
        return chevron_render(*args, **kwargs)

    scopes = []
    ident = threading.get_ident()
    with _lock:
        chevron_render = chevron.renderer.render
        chevron.renderer.render = capture
        render('')
        chevron.renderer.render = chevron_render
    return scopes

I'll take some time to make a PR for this.

ergoithz commented 3 years ago

I'm closing this based on the following reasons:

Thanks for your time.

ergoithz commented 2 years ago

Some extra context if anyone reaches this issue.

Mustache.js exposes the rendering scope to lambda functions, and its lambdas look like this:

let scope = {
  mylambda(){
    return (content, render) => {
      return render(content);
    };
  }
}

Counterintuitively, the lambda is called inside the current rendering scope and not where gets defined, which is extremely useful as it allows referencing that scope via this.

An example (again, Mustache.js ):

let scope = {
  key: 1,
  nested: {
    key: 2,
    },
  lambda(){
    return (content, render) => {
      return render(`${render(content)}${this.key}`);
    };
  }
};
console.log(Mustache.render('{{#lambda}}value={{/lambda}}', scope));
// value=1
console.log(Mustache.render('{{#nested}}{{#lambda}}value={{/lambda}}{{/nested}}', scope))
// value=2

This essential lambda feature is missing in chevron as, again, there is no way of getting the current rendering scope during a lambda call.