Repository: PebbleTemplates/pebble (java)

Issue:
Accessing globals in macros (again)
The solution of passing a `_context` was a bit overkill as it passes too much data. It doesn't just pass globals, it's passing in local variables. I'm defining globals as the set of key/value pairs returned by the `getGlobalVariables` method overridden on the class `AbstractExtension`. These are the true global variables.

```
    @Override
    public Map<String, Object> getGlobalVariables() {
        final Map<String, Object> globals = new HashMap<>();
        globals.put("DATE_TIME_FULL", DateFormat.FULL);
        globals.put("DATE_TIME_LONG", DateFormat.LONG);
        globals.put("DATE_TIME_MEDIUM", DateFormat.MEDIUM);
        globals.put("DATE_TIME_SHORT", DateFormat.SHORT);
        globals.put("DATE_TIME_NONE", -1);
        return globals;
    }
```

In that same `AbstractExtension` class I'm providing a filter, which I expect to use those globals with.

```
    @Override
    public Map<String, Filter> getFilters() {
        final Map<String, Filter> filters = new HashMap<>();
        filters.put("dateTime", new DateTimeFilter());
        return filters;
    }
```

I encounter the classical globals/macros issue when I trey to wrap my filter into a macro, and within that macro use any specified global. I only want transparent and easy access to the TRUE globals, instead, I have to munge up with a _context parameter...

```
{% macro printDate(timezone, timestamp, _context) %}{{ timestamp ? (timestamp | dateTime(timezone, _context.DATE_TIME_LONG, _context.DATE_TIME_NONE)) : "-" }}{% endmacro %}
```
versus
```
{% macro printDate(timezone, timestamp) %}{{ timestamp ? (timestamp | dateTime(timezone, DATE_TIME_LONG, DATE_TIME_NONE)) : "-" }}{% endmacro %}
```

Requested fix: please make `getGlobalVariables` truly global without requiring usage of `_context`.

Pull request:
Extension global variables in macros
Fixes #500

This change allows macros to use extension global variables (getGlobalVariables).

Patch:
diff --git a/docs/src/orchid/resources/wiki/guide/installation.md b/docs/src/orchid/resources/wiki/guide/installation.md
index 05373cbf..4a045807 100644
--- a/docs/src/orchid/resources/wiki/guide/installation.md
+++ b/docs/src/orchid/resources/wiki/guide/installation.md
@@ -86,7 +86,7 @@ All the settings are set during the construction of the `PebbleEngine` object.
 | `loader` | An implementation of the `Loader` interface which is used to find templates. | An implementation of the `DelegatingLoader` which uses a `ClasspathLoader` and a `FileLoader` behind the scenes. |
 | `strictVariables` | If set to true, Pebble will throw an exception if you try to access a variable or attribute that does not exist (or an attribute of a null variable). If set to false, your template will treat non-existing variables/attributes as null without ever skipping a beat. | `false` |
 | `methodAccessValidator` | Pebble provides two implementations. NoOpMethodAccessValidator which do nothing and BlacklistMethodAccessValidator which checks that the method being called is not blacklisted. | `BlacklistMethodAccessValidator` 
-| `literalDecimalTreatedAsInteger` | option for toggling to enable/disable literal decimal treated as integer | `false` |
+| `literalDecimalTreatedAsInteger` | option for treating literal decimals as `int`. Otherwise it is `long`. | `false` |
 | `literalNumbersAsBigDecimals` | option for toggling to enable/disable literal numbers treated as BigDecimals | `false` |
 | `greedyMatchMethod` | option for toggling to enable/disable greedy matching mode for finding java method. Reduce the limit of the parameter type, try to find other method which has compatible parameter types. | `false` |
 | `maxRenderedSize` | option for limiting the size of the rendered output | `-1 (disabled)` |
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/node/MacroNode.java b/pebble/src/main/java/com/mitchellbosecke/pebble/node/MacroNode.java
index 9a45527f..3d0cc6b2 100644
--- a/pebble/src/main/java/com/mitchellbosecke/pebble/node/MacroNode.java
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/node/MacroNode.java
@@ -72,6 +72,10 @@ public class MacroNode extends AbstractRenderableNode {
 
         // scope for default arguments
         scopeChain.pushLocalScope();
+        
+        // global vars provided by extensions
+        context.getExtensionRegistry().getGlobalVariables().forEach(scopeChain::put);
+        
         for (NamedArgumentNode arg: MacroNode.this.getArgs().getNamedArgs()) {
           Expression<?> valueExpression = arg.getValueExpression();
           if (valueExpression == null) {


Test patch:
diff --git a/pebble/src/test/java/com/mitchellbosecke/pebble/macro/MacroGlobalVariablesTest.java b/pebble/src/test/java/com/mitchellbosecke/pebble/macro/MacroGlobalVariablesTest.java
new file mode 100644
index 00000000..68f35c87
--- /dev/null
+++ b/pebble/src/test/java/com/mitchellbosecke/pebble/macro/MacroGlobalVariablesTest.java
@@ -0,0 +1,33 @@
+package com.mitchellbosecke.pebble.macro;
+
+import com.mitchellbosecke.pebble.PebbleEngine;
+import com.mitchellbosecke.pebble.extension.AbstractExtension;
+import com.mitchellbosecke.pebble.loader.StringLoader;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class MacroGlobalVariablesTest {
+
+  public static final class Extension extends AbstractExtension {
+    @Override
+    public Map<String, Object> getGlobalVariables() {
+      HashMap<String, Object> map = new HashMap<>();
+      map.put("someGlobalValue", 18181);
+      return map;
+    }
+  }
+
+  @Test
+  void test() throws IOException {
+    PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(true).extension(new Extension()).build();
+    StringWriter writer = new StringWriter();
+    pebble.getTemplate("{% macro m() %}{{ someGlobalValue }}{% endmacro %}{{ m() }}").evaluate(writer);
+    assertEquals("18181", writer.toString());
+  }
+}