Skip to content

Commit

Permalink
Merge pull request #269 from tx-francesco-figari/single-block-rendering
Browse files Browse the repository at this point in the history
Extend PebbleTemplate to allow rendering of single blocks
  • Loading branch information
ebussieres authored May 22, 2017
2 parents 9604b36 + 413f533 commit 317fc8f
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Output filename and line number of non-existent macro
- Fix for null pointer and index out of bounds exceptions when invalid or no endif/endfor tags are used in template (#266)
- Add DynamicAttributeProvider interface. When implemented by an object, tells the expression parser that this object is able to provide attributes dynamically, given their names and the potential arguments(#230)
- Add rendering of single blocks, similar to the Twig renderBlock() method.

## v2.3.0 (2016-11-13)
- Upgrade SLF4J from 1.6.1 to 1.7.21
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,50 @@ public interface PebbleTemplate {
*/
void evaluate(Writer writer, Map<String, Object> context, Locale locale) throws PebbleException, IOException;

/**
* Evaluate the template but only render the contents of a specific block.
*
* @param blockName The name of the template block to return.
* @param writer The results of the evaluation are written to this writer.
* @throws PebbleException An exception with the evaluation of the template
* @throws IOException An IO exception during the evaluation
*/
void evaluateBlock(String blockName, Writer writer) throws PebbleException, IOException;

/**
* Evaluate the template but only render the contents of a specific block.
*
* @param blockName The name of the template block to return.
* @param writer The results of the evaluation are written to this writer.
* @param locale The locale used during the evaluation of the template.
* @throws PebbleException An exception with the evaluation of the template
* @throws IOException An IO exception during the evaluation
*/
void evaluateBlock(String blockName, Writer writer, Locale locale) throws PebbleException, IOException;

/**
* Evaluate the template but only render the contents of a specific block.
*
* @param blockName The name of the template block to return.
* @param writer The results of the evaluation are written to this writer.
* @param context The variables used during the evaluation of the template.
* @throws PebbleException An exception with the evaluation of the template
* @throws IOException An IO exception during the evaluation
*/
void evaluateBlock(String blockName, Writer writer, Map<String, Object> context) throws PebbleException, IOException;

/**
* Evaluate the template but only render the contents of a specific block.
*
* @param blockName The name of the template block to return.
* @param writer The results of the evaluation are written to this writer.
* @param context The variables used during the evaluation of the template.
* @param locale The locale used during the evaluation of the template.
* @throws PebbleException An exception with the evaluation of the template
* @throws IOException An IO exception during the evaluation
*/
void evaluateBlock(String blockName, Writer writer, Map<String, Object> context, Locale locale) throws PebbleException, IOException;

/**
* Returns the name of the template
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,40 @@ public void evaluate(Writer writer, Map<String, Object> map, Locale locale) thro
this.evaluate(writer, context);
}

public void evaluateBlock(String blockName, Writer writer) throws PebbleException, IOException {
EvaluationContext context = this.initContext(null);
this.evaluate(new NoopWriter(), context);

this.block(writer, context, blockName, false);
writer.flush();
}

public void evaluateBlock(String blockName, Writer writer, Locale locale) throws PebbleException, IOException {
EvaluationContext context = this.initContext(locale);
this.evaluate(new NoopWriter(), context);

this.block(writer, context, blockName, false);
writer.flush();
}

public void evaluateBlock(String blockName, Writer writer, Map<String, Object> map) throws PebbleException, IOException {
EvaluationContext context = this.initContext(null);
context.getScopeChain().pushScope(map);
this.evaluate(new NoopWriter(), context);

this.block(writer, context, blockName, false);
writer.flush();
}

public void evaluateBlock(String blockName, Writer writer, Map<String, Object> map, Locale locale) throws PebbleException, IOException {
EvaluationContext context = this.initContext(locale);
context.getScopeChain().pushScope(map);
this.evaluate(new NoopWriter(), context);

this.block(writer, context, blockName, false);
writer.flush();
}

/**
* This is the authoritative evaluate method. It will evaluate the template
* starting at the root node.
Expand Down Expand Up @@ -139,10 +173,9 @@ private EvaluationContext initContext(Locale locale) {
// global vars provided from extensions
scopeChain.pushScope(this.engine.getExtensionRegistry().getGlobalVariables());

EvaluationContext context = new EvaluationContext(this, this.engine.isStrictVariables(), locale,
return new EvaluationContext(this, this.engine.isStrictVariables(), locale,
this.engine.getExtensionRegistry(), this.engine.getTagCache(), this.engine.getExecutorService(),
new ArrayList<PebbleTemplateImpl>(), scopeChain, null);
return context;
}

/**
Expand Down Expand Up @@ -353,4 +386,14 @@ public String getName() {
return this.name;
}

private static class NoopWriter extends Writer {
public void write(char[] cbuf, int off, int len) throws IOException {
}

public void flush() throws IOException {
}

public void close() throws IOException {
}
}
}
106 changes: 106 additions & 0 deletions src/test/java/com/mitchellbosecke/pebble/RenderSingleBlockTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.mitchellbosecke.pebble;

import com.mitchellbosecke.pebble.error.PebbleException;
import com.mitchellbosecke.pebble.loader.StringLoader;
import com.mitchellbosecke.pebble.template.PebbleTemplate;

import org.junit.Test;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import static java.util.Locale.CANADA;
import static org.junit.Assert.assertEquals;

public class RenderSingleBlockTest extends AbstractTest {

@Test
public void testRenderSingleBlock() throws PebbleException, IOException {
PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(false).build();

String source = "Prefix {% block block_a %}Block A{% endblock %}{% block block_b %}Block B{% endblock %} Postfix";
PebbleTemplate template = pebble.getTemplate(source);

Writer writer_a = new StringWriter();
template.evaluateBlock("block_a", writer_a);
assertEquals("Block A", writer_a.toString());

Writer writer_b = new StringWriter();
template.evaluateBlock("block_b", writer_b);
assertEquals("Block B", writer_b.toString());
}

@Test
public void testRenderSingleBlockWithLocale() throws PebbleException, IOException {
PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(false).build();

String source = "Prefix {% block block_a %}Block A{% endblock %}{% block block_b %}Block B{% endblock %} Postfix";
PebbleTemplate template = pebble.getTemplate(source);

Writer writer_a = new StringWriter();
template.evaluateBlock("block_a", writer_a, CANADA);
assertEquals("Block A", writer_a.toString());

Writer writer_b = new StringWriter();
template.evaluateBlock("block_b", writer_b, CANADA);
assertEquals("Block B", writer_b.toString());
}

@Test
public void testRenderSingleBlockWithContext() throws PebbleException, IOException {
PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(false).build();

String source = "Prefix {% block block_a %}{{vara}}{% endblock %}{% block block_b %}{{varb}}{% endblock %} Postfix";
PebbleTemplate template = pebble.getTemplate(source);

Map<String, Object> context = new HashMap<>();
context.put("vara", "FOO");
context.put("varb", "BAR");

Writer writer_a = new StringWriter();
template.evaluateBlock("block_a", writer_a, context, CANADA);
assertEquals("FOO", writer_a.toString());

Writer writer_b = new StringWriter();
template.evaluateBlock("block_b", writer_b, context, CANADA);
assertEquals("BAR", writer_b.toString());
}

@Test
public void testRenderSingleBlockWithContextAndLocale() throws PebbleException, IOException {
PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader()).strictVariables(false).build();

String source = "Prefix {% block block_a %}{{vara}}{% endblock %}{% block block_b %}{{varb}}{% endblock %} Postfix";
PebbleTemplate template = pebble.getTemplate(source);

Map<String, Object> context = new HashMap<>();
context.put("vara", "FOO");
context.put("varb", "BAR");

Writer writer_a = new StringWriter();
template.evaluateBlock("block_a", writer_a, context);
assertEquals("FOO", writer_a.toString());

Writer writer_b = new StringWriter();
template.evaluateBlock("block_b", writer_b, context);
assertEquals("BAR", writer_b.toString());
}

@Test
public void testRenderSingleExtendedBlock() throws PebbleException, IOException {
PebbleEngine pebble = new PebbleEngine.Builder().strictVariables(true).build();
PebbleTemplate template = pebble.getTemplate("templates/single-block/template.renderextendedblock1.peb");

Writer writer_a = new StringWriter();
template.evaluateBlock("container_a", writer_a);
assertEquals("Block A extended", writer_a.toString());

Writer writer_b = new StringWriter();
template.evaluateBlock("container_b", writer_b);
assertEquals("Block B extended", writer_b.toString());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{# used by RenderSingleBlockTest.testRenderSingleExtendedBlock #}
{% extends "./template.renderextendedblock2.peb" %}

Text in the template that should not appear in either block

{% block content_a %}Block A{% endblock %}
{% block content_b %}Block B{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{# used by RenderSingleBlockTest.testRenderSingleExtendedBlock #}

Text in the parent template that should not appear in either block

{% block container_a %}{% block content_a %}{% endblock %} extended{% endblock %}
{% block container_b %}{% block content_b %}{% endblock %} extended{% endblock %}

0 comments on commit 317fc8f

Please sign in to comment.