Skip to content

adds support for Custom Token Scanner Symbols #410

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

Merged
merged 8 commits into from
Mar 27, 2020

Conversation

gabru-md
Copy link
Contributor

This pull request aims at implementing the Custom Token Symbols class for Jinjava. The goal is to allow the user to specify the tokens that he/she wants to use. It can be extending using the TokenScannerSymbols abstract class and then filling the abstract methods.

A few lines inside the tree package have been changed from switch-case to if-else since switch-case allows only constant expressions to be used with them. The changes to the tests which were failing initially due to the change have also been made and it should work fine now. Furthermore a JUnit test file has also been added in support of the changes made.

related issue: #402

@KidsDontPlay perhaps this solves your problem.

cheers!

@gabru-md gabru-md force-pushed the gabru-md/token-scanner-upd branch from 40674ed to 14086a6 Compare March 10, 2020 13:35
@gabru-md
Copy link
Contributor Author

even after running java-prettier on my end travis seems to be failing for the same reason of unformatted code. 🤦‍♂️

Copy link
Contributor

@boulter boulter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, @gabru-md!

There's definitely some formatting changes here that I can't explain. When I build locally, it doesn't change anything. Could you revert all the changes that are just formatting-related? That will make this easier to review.

Thanks again!

@@ -51,7 +51,10 @@ public OutputNode render(JinjavaInterpreter interpreter) {
if (interpreter.getConfig().isNestedInterpretationEnabled()) {
if (
!StringUtils.equals(result, master.getImage()) &&
(StringUtils.contains(result, "{{") || StringUtils.contains(result, "{%"))
(
StringUtils.contains(result, "{{") ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this should use the scanner symbols as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the changes. Although I'm not quite sure to if the {{ is to be replaced by
TOKEN_PREFIX_CHAR + TOKEN_EXPR_START_CHAR
or is it just
TOKEN_EXPR_START_CHAR + TOKEN_EXPR_START_CHAR.

Please review it once again.
Cheers!

) return tag((TagToken) token); else if (
token.getType() == symbols.TOKEN_NOTE()
) {
if (!token.getImage().endsWith("#}")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use TOKEN_NOTE_CHAR here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

char TOKEN_TRIM_CHAR = '-';

@Override
public char TOKEN_PREFIX_CHAR() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be getTokenPrefix(). Same for the others below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes made!

startPosition
); else if (
tokenKind == symbols.TOKEN_EXPR_START()
) return new ExpressionToken(image, lineNumber, startPosition); else if (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if should be on a new line

int lineNumber,
int startPosition
) {
if (tokenKind == symbols.TOKEN_FIXED()) return new TextToken(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please always wrap bodies of if statements in { }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

int TOKEN_TRIM = TOKEN_TRIM_CHAR;
public abstract class TokenScannerSymbols {

public abstract char TOKEN_PREFIX_CHAR();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as before

@gabru-md gabru-md force-pushed the gabru-md/token-scanner-upd branch from 96ec8ef to 10bdb16 Compare March 14, 2020 06:55
@gabru-md
Copy link
Contributor Author

@boulter

while debugging the code after making the changes, I noticed something weird here.

this.expr = WhitespaceUtils.unwrap(image, "{{", "}}");
// inside the unwrap function
 return s.substring(start + prefix.length(), end - suffix.length() + 1);

the unwrap function does not care about the prefix and the suffix being passed into the function. The only purpose it serves is when the function calculates the length of the prefix and the suffix to trim the image and return the expression. Should there not be a validation inside the unwrap function that asserts a check that the correct prefix and suffix has been used in the image?

I was just wondering if it should be added as well?

@boulter
Copy link
Contributor

boulter commented Mar 17, 2020

@gabru-md, could you run mvn clean verify on your build so prettier runs and check it in? It's hard to see what the differences are since there's so many whitespace and formatting changes. Thanks!

@gabru-md
Copy link
Contributor Author

@boulter, I executed mvn clean verify and applied the diff created by the prettier. Please see if it is reviewable now.

Copy link
Contributor

@boulter boulter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good. I have a few suggestions for changes.

@@ -48,10 +49,23 @@ public OutputNode render(JinjavaInterpreter interpreter) {

String result = Objects.toString(var, "");

TokenScannerSymbols symbols = interpreter.getConfig().getTokenScannerSymbols();
String expressionBegins = new StringBuilder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you create these once and make it accessible from the TokenScannerSymbols class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't quite get what you're trying to say. Can you please explain a little bit so that I can make the changes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Add getExpressionStart() and getExpressionEnd() methods to TokenScannerSymbols and ensure they're only built once, rather than every time a node is rendered.

} else if (token.getType() == symbols.getTokenTag()) {
return tag((TagToken) token);
} else if (token.getType() == symbols.getTokenNote()) {
String commentClosed = new StringBuilder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can also be defined once.

char TOKEN_TRIM_CHAR = '-';

@Override
public char getTokenPrefixChar() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all of these start with getToken so the Token part is redundant. Can you remove that part?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay. I will remove that !

@gabru-md
Copy link
Contributor Author

@boulter,
I am facing an error. As you might have noticed that I've introduced a new test file called CustomTokenScannerSymbolsTest.java. The problem that I'm facing when I try to run tests on Eclipse. When I run the CustomTokenScannerSymbolsTest.java file then the new tests seem to pass whereas when I execute all the tests in the test package then the new tests which I've created starts failing and the reason I could identify is due to the fact that the interpreter still uses
DefaultTokenScannerSymbols instead of the newly created CustomTokens.

I cannot quite seem to figure out why this behavior is happening.

Copy link
Contributor

@boulter boulter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting there!

I ran this locally and I had a lot of null pointer exceptions, so I think there's some fixes needed there.

I'm not sure about eclipse as I use IntelliJ. In any case, I would use the command line build as the source of truth.

Thanks!

Comment on lines 53 to 54
String expressionBegins = symbols.getExpressionStart();
String expressionWithTag = symbols.getExpressionStartWithTag();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary variables as they are only used once.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stringBuilder
.append(TokenScannerSymbols.TOKEN_EXPR_START_CHAR)
.append(TokenScannerSymbols.TOKEN_TAG_CHAR);
stringBuilder.append(symbols.getExprStartChar()).append(symbols.getTagChar());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a method to construct this string once as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. I might have missed this out in the last commit.
I will add this to the changes as well.

.append(TokenScannerSymbols.TOKEN_TAG_CHAR)
.append(TokenScannerSymbols.TOKEN_EXPR_END_CHAR);

stringBuilder.append(symbols.getTagChar()).append(symbols.getExprEndChar());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

import com.hubspot.jinjava.interpret.TemplateSyntaxException;
import com.hubspot.jinjava.util.WhitespaceUtils;

public class TagToken extends Token {
private static final long serialVersionUID = -4927751270481832992L;
private final int TOKEN_TAG;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private final int TOKEN_TAG;
private final int tokenTag;

only static variables should be in upper case.


private String tagName;
private String rawTagName;
private String helpers;

public TagToken(String image, int lineNumber, int startPosition) {
super(image, lineNumber, startPosition);
TOKEN_TAG =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
TOKEN_TAG =
tokenTag =

import org.apache.commons.lang3.StringUtils;

public class TextToken extends Token {
private static final long serialVersionUID = -6168990984496468543L;
private final int TOKEN_FIXED;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private final int TOKEN_FIXED;
private final int tokenFixed;


public TextToken(String image, int lineNumber, int startPosition) {
super(image, lineNumber, startPosition);
TOKEN_FIXED =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
TOKEN_FIXED =
tokenFixed =

return getTrimChar();
}

public String getExpressionStart() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would good to fill this out with all the other starting and closing sequences that we'll eventually need.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabru-md are all these in there now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, all the required combinations of sequences are in here right now.


public abstract char getTrimChar();

public int getPrefix() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are all these methods that just call abstract methods needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are places when an integer is being required and there are separate places where a character is required during parsing the template. Also, it will be better if the user is allowed to fill in the functions which return char and not the ASCII value instead. Somebody who wants custom tokens will only have to fill in the tokens in form of characters and do not need to write down their ASCII values.
Also, I could've used those abstract methods instead since they can be cast to integers as well but the problem lies with the fact that when I was writing the if..else conditions then it was becoming a lot unclear since the casting had to be done during the comparison. Therefore I thought It'd be better to not mess up the code readability a lot and simply have users fill out the functions which return char and then return their int value using the getPrefix functions instead. I believe it was a better way to make changes.
I hope my explanation is fine. If you feel that it is not okay then I'd try and make the changes.

}

@Test
public void testsThatCustomTokensDoesNotFail() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make these rspec-style? itRendersWithCustomTokens, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure.

@gabru-md
Copy link
Contributor Author

I believe that the command line builds should not fail if the same isn't failing for me in Eclipse. But since they are then I will work on it and try to get to the depth of the problem and commit a fix as soon as I am done with it. Since this does not seem to be a high-priority feature then I wish I can take the time I want to get it all fixed. I will perhaps need some more reviews from your end though and will tag you once changes seem fine to me.

@gabru-md
Copy link
Contributor Author

@boulter,
please review. I've made the changes required and the tests are now passing.
cheers!

Copy link
Contributor

@boulter boulter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just 2 more loose ends

Comment on lines 53 to 54
String expressionBegins = symbols.getExpressionStart();
String expressionWithTag = symbols.getExpressionStartWithTag();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return getTrimChar();
}

public String getExpressionStart() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabru-md are all these in there now?

@boulter boulter merged commit 9c16124 into HubSpot:master Mar 27, 2020
@KidsDontPlay
Copy link

@gabru-md
thanks for your effort

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

Successfully merging this pull request may close these issues.

3 participants