Skip to content

Commit

Permalink
Merge pull request #1461 from scireum/feature/mko/SIRI-1019
Browse files Browse the repository at this point in the history
Adds a new Macro which checks whether the given guard string is defined or not
  • Loading branch information
mko-sci authored Sep 11, 2024
2 parents 787d302 + 314aa72 commit 5244ad9
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - info@scireum.de
*/

package sirius.pasta.tagliatelle.macros;

import sirius.kernel.commons.Strings;
import sirius.kernel.di.std.Register;
import sirius.kernel.tokenizer.Position;
import sirius.pasta.noodle.Environment;
import sirius.pasta.noodle.compiler.CompilationContext;
import sirius.pasta.noodle.compiler.ir.Node;
import sirius.pasta.noodle.macros.BasicMacro;
import sirius.pasta.tagliatelle.rendering.GlobalRenderContext;
import sirius.pasta.tagliatelle.rendering.LocalRenderContext;

import javax.annotation.Nonnull;
import java.util.List;

/**
* Checks whether the given {@linkplain GlobalRenderContext#hasGuard(String) guard } is defined or not.
*
* @see GlobalRenderContext#addGuard(String)
*/
@Register
public class IfNotDefinedMacro extends BasicMacro {

@Override
protected Class<?> getType() {
return boolean.class;
}

@Override
protected void verifyArguments(CompilationContext compilationContext, Position position, List<Class<?>> args) {
if (args.size() != 1 || !CompilationContext.isAssignableTo(args.getFirst(), String.class)) {
throw new IllegalArgumentException("Expected a single String as argument.");
}
}

@Override
public boolean isConstant(CompilationContext context, List<Node> args) {
return false;
}

@Override
public Object invoke(Environment environment, Object[] args) {
String guard = (String) args[0];
if (Strings.isFilled(guard) && environment instanceof LocalRenderContext localRenderContext) {
GlobalRenderContext globalRenderContext = localRenderContext.getGlobalContext();
if (globalRenderContext.hasGuard(guard)) {
return false;
} else {
globalRenderContext.addGuard(guard);
return true;
}
}

return false;
}

@Override
public String getDescription() {
return """
Checks whether the given guard is defined or not. If the guard is not defined, true is returned and
the guard is added to a Set of guards to the global context of the template. This means that all
subsequent calls to ifNotDefined with the same guard will return false. This allows to run a
block/code exactly once per template. The behavior is somewhat similar to C/C++ #ifndef.
""";
}

@Nonnull
@Override
public String getName() {
return "ifNotDefined";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@
import sirius.pasta.tagliatelle.Template;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -37,6 +41,9 @@ public class GlobalRenderContext {
protected StringBuilder buffer;
protected Map<String, String> extraBlocks;
protected UnaryOperator<String> escaper = GlobalRenderContext::escapeRAW;

private Set<String> guards = new HashSet<>();

private static final Pattern OPENING_SCRIPT_TAG = Pattern.compile("<script(\\s.*)?>", Pattern.CASE_INSENSITIVE);
private static final Pattern CLOSING_SCRIPT_TAG = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
private static final Pattern OPENING_STYLE_TAG = Pattern.compile("<style(\\s.*)?>", Pattern.CASE_INSENSITIVE);
Expand Down Expand Up @@ -382,4 +389,22 @@ public void outputDebug(String string) {
}
}
}

/**
* Checks if the given guard is defined or not.
*
* @param guard the guard String to check
* @return true if the guard is defined, false otherwise
*/
public boolean hasGuard(String guard) {
return guards.contains(guard);
}

/**
* Adds the given guard to the list of defined guards.
* @param guard the guard String to add
*/
public void addGuard(String guard) {
guards.add(guard);
}
}
10 changes: 10 additions & 0 deletions src/main/resources/default/taglib/t/ifNotDefined.html.pasta
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<i:arg type="String" name="value" description="Contains a string which is used as a guard clause to determine whether the body should be rendered."/>

<i:pragma name="description">
Checks whether the defined value is already specified. If the value is not defined, the body of the tag is rendered.
Similar to C/C++ #ifndef.
</i:pragma>

<i:if test="ifNotDefined(value)">
<i:render name="body"/>
</i:if>

0 comments on commit 5244ad9

Please sign in to comment.