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

How to find undeclared variables? #354

Open
buremba opened this issue Jul 23, 2019 · 7 comments
Open

How to find undeclared variables? #354

buremba opened this issue Jul 23, 2019 · 7 comments

Comments

@buremba
Copy link

buremba commented Jul 23, 2019

The original API has a method for finding out the undeclared variables. See: http://jinja.pocoo.org/docs/dev/api/#jinja2.meta.find_undeclared_variables

Is there a way to do that in Jinjava? If not, I would like to implement it. What's the best way to start implementing it given that I'm not familiar with the codebase?

@buremba
Copy link
Author

buremba commented Jul 23, 2019

@ilkerc

@xuchaoyong
Copy link

I am also demanding the undeclared variables. Is there anyway to do it in Jinjava?

@bnat1
Copy link

bnat1 commented Dec 6, 2019

I was trying the different configuration options, and found withFailOnUnknownTokens, and it works.

JinjavaConfig jinjavaConfig = JinjavaConfig.newBuilder().withFailOnUnknownTokens(true).build();
Jinjava jinjava = new Jinjava(jinjavaConfig);

If there is an undefined variable, it throws an UnknownTokenException, which has the name of the undefined variable.

I haven't found anything that finds all of the undeclared variables at once though.

@jonathannaguin
Copy link

I would also like this functionality on the API, any guidance on how we can implement this?

@boulter
Copy link
Contributor

boulter commented Feb 19, 2020

You could look at all the places where we throw UnknownToken exceptions and track them in the Context object.

@jonathannaguin
Copy link

I was able to use the Jinja interpreter in a loop like this:

 Map<String, Object> binding = new HashMap<>();
JinjavaConfig config = JinjavaConfig.newBuilder()
                                    .withFailOnUnknownTokens(true)
                                    .build();

Jinjava jinjava = new Jinjava(config);
Context context = new Context(jinjava.getGlobalContext(), binding, config.getDisabled());
JinjavaInterpreter interpreter = config.getInterpreterFactory()
                                       .newInstance(jinjava, context, config);

boolean terminated = false;
do
{
    try
    {
        interpreter.render(content);
        terminated = true;
    }
    catch (UnknownTokenException e)
    {
        binding.put(e.getToken(), "");
    }
}
while (!terminated);

After it finishes, the binding map will contain all the undefined variables.
However, even though that works fine for simple templates like Hello {{user}}, it does not parse templates like:

{%- if GENDER == 'male' -%}
    {%- set greeting = "Good Morning Sir" -%}
{%- elif GENDER == 'female' -%}
    {%- set greeting = "Good Morning Madam" -%}
{%- else -%}
    {%- set greeting = "Good Morning" -%}
{%- endif -%}

Is there a way to parse the above too?

Thanks!

@GregDThomas
Copy link
Contributor

I have submitted a PR at #572 which sort of solves this problem.

Rather than providing a context that (hopefully) contains a list of all your variables, you can supply a VariableFunction. This is a function that is supplied by the caller takes the name of a token, and returns it's value. It's invoked as the template is parsed.

Probably more easily explained from the test case at https://github.com/HubSpot/jinjava/pull/572/files#diff-dd8f89332b7f565f4eda09b58d91342a61ec8ea1729e2b7b280adf8d158707b1R23

Using your more complex example, it would be called with a parameter of "GENDER", twice. Your function could keep track of its invocations, and then you would know the variables in the template.

Note that this won't find all variables - only those in the paths determine from earlier results. e.g. if your "GENDER" returns "male", then only variables rendered in the {%- if GENDER == 'male' -%} ... {%-...} block would be requested.

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

6 participants