Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@ public Object eval(final ValueResolver resolver, final Context context, final Ob
*/
public static final String PARAM_SIZE = Context.class.getName() + "#paramSize";

/**
* Last callee of a partial block. Internal use.
*/
public static final String CALLEE = Context.class.getName() + "#callee";

/**
* The parent context. Optional.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,12 @@ public static CharSequence escapeExpression(final CharSequence input) {
*/
private boolean prettyPrint;

/**
* If true, given partial blocks are not evaluated when defined but when used.
* If false, partial blocks are evaluated when defined and used.
*/
private boolean lazyPartialBlockEvaluation;

/**
* The helper registry.
*/
Expand Down Expand Up @@ -740,6 +746,39 @@ public boolean stringParams() {
return stringParams;
}


/**
* If true, given partial blocks are not evaluated when defined but when used.
Copy link
Owner

Choose a reason for hiding this comment

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

Let's add two examples when this flag is on/off

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey I added two tests that deal with this pull request's changes. Is everything okay now?

* If false, partial blocks are evaluated when defined and used.
* @return If true, given partial blocks are not evaluated when defined but when used.
* If false, partial blocks are evaluated when defined and used.
*/
public boolean lazyPartialBlockEvaluation() {
return lazyPartialBlockEvaluation;
}


/**
* If true, given partial blocks are not evaluated when defined but when used.
* If false, partial blocks are evaluated when defined and used.
* @param lazyPartialBlockEvaluation Flag to turn it off and on
*/
public void setLazyPartialBlockEvaluation(final boolean lazyPartialBlockEvaluation) {
this.lazyPartialBlockEvaluation = lazyPartialBlockEvaluation;
}

/**
* If true, given partial blocks are not evaluated when defined but when used.
* If false, partial blocks are evaluated when defined and used.
* @param lazyPartialBlockEvaluation Flag to turn it off and on
* @return The handlebars object.
*/
public Handlebars lazyPartialBlockEvaluation(final boolean lazyPartialBlockEvaluation) {
setLazyPartialBlockEvaluation(lazyPartialBlockEvaluation);
return this;
}


/**
* If true, unnecessary spaces and new lines will be removed from output. Default is: false.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
Expand Down Expand Up @@ -120,10 +121,31 @@ protected void merge(final Context context, final Writer writer)
/** Inline partial? */
LinkedList<Map<String, Template>> partials = context.data(Context.INLINE_PARTIALS);
Map<String, Template> inlineTemplates = partials.getLast();
Template callee = context.data(Context.CALLEE);

final boolean pathIsPartialBlock = "@partial-block".equals(path);
final Template lastPartialBlock = inlineTemplates.get("@partial-block");
final boolean parentIsNotLastPartialBlock = !isCalleeOf(callee, lastPartialBlock);

if (pathIsPartialBlock && parentIsNotLastPartialBlock) {
throw new IllegalArgumentException(
Copy link
Owner

@jknack jknack May 24, 2018

Choose a reason for hiding this comment

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

Already merged it, but I'm struggling to figure out why we do fail here, can you explain?

Here is a test case that fails today bc of this check:

shouldCompileTo("{{#> dude x=23}}{{#> dude x=12}}{{/dude}}{{/dude}}",
        $("hash", $(), "partials",
            $("dude", "<div {{#if x}}x={{x}}{{/if}}>{{> @partial-block}}</div>")),
        "<div x=23><div x=12></div></div>");

Choose a reason for hiding this comment

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

Hi and thanks for the merge! We'll get back to you about this asap.

callee + " does not provide a @partial-block for " + this
);
}

if (this.partial != null) {
this.partial.apply(context);
inlineTemplates.put("@partial-block", this.partial);
if (!handlebars.lazyPartialBlockEvaluation()) {
this.partial.apply(context);
}

inlineTemplates.put("@partial-block",
new PartialBlockForwardingTemplate(this,
this.partial,
inlineTemplates.get("@partial-block"),
callee,
handlebars
)
);
}

Template template = inlineTemplates.get(path);
Expand Down Expand Up @@ -171,8 +193,10 @@ protected void merge(final Context context, final Writer writer)
}

}
context.data(Context.CALLEE, this);
Context ctx = Context.newPartialContext(context, this.scontext, hash(context));
template.apply(ctx, writer);
context.data(Context.CALLEE, callee);
} catch (IOException ex) {
String reason = String.format("The partial '%s' at '%s' could not be found",
loader.resolve(path.text()), ex.getMessage());
Expand All @@ -183,6 +207,23 @@ protected void merge(final Context context, final Writer writer)
}
}

/**
* @param callee parent template of the currently traversed template
* @param partialBlock partial block candidate
* @return returns if callee and partialBlock are the same
*/
private boolean isCalleeOf(final Template callee, final Template partialBlock) {
if (callee == null || partialBlock == null) {
return false;
}

if (!callee.filename().equalsIgnoreCase(partialBlock.filename())) {
return false;
}

return Arrays.equals(callee.position(), partialBlock.position());
}

/**
* True, if the file was already processed.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Copyright (c) 2012-2015 Edgar Espina
*
* This file is part of Handlebars.java.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jknack.handlebars.internal;

import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Template;

import java.io.IOException;
import java.io.Writer;
import java.util.LinkedList;
import java.util.Map;

/**
*
*/
public class PartialBlockForwardingTemplate extends BaseTemplate {
/**
* The block to be passed as partial-block.
*/
private final Template block;

/**
* The previous partial-block definition of the template which contains this partial.
*/
private final Template parentPartialBlock;

/**
* The callee of the parent partial.
*/
private final Template callee;

/**
* Constructs a PartialBlockForwardingTemplate.
*
* @param parent the parent partial
* @param block the block to be passed as partial-block.
* @param parentPartialBlock the previous partial-block definition of
* the template which contains this partial.
* @param callee the template that renders the parent
* @param handlebars handlebars
*/
public PartialBlockForwardingTemplate(
final Template parent,
final Template block,
final Template parentPartialBlock,
final Template callee,
final Handlebars handlebars
) {
super(handlebars);
this.block = block;
this.parentPartialBlock = parentPartialBlock;
this.callee = callee;
this.filename(block.filename());
this.position(parent.position()[0], parent.position()[1]);
}

/**
* {@inheritDoc}
*/
@Override
protected void merge(final Context context, final Writer writer) throws IOException {
LinkedList<Map<String, Template>> partials = context.data(Context.INLINE_PARTIALS);
Map<String, Template> inlineTemplates = partials.getLast();
Template oldPartialBlock = inlineTemplates.get("@partial-block");
Template oldCallee = context.data(Context.CALLEE);

context.data(Context.CALLEE, callee);
inlineTemplates.put("@partial-block", parentPartialBlock);
block.apply(context, writer);
inlineTemplates.put("@partial-block", oldPartialBlock);
context.data(Context.CALLEE, oldCallee);
}

/**
* {@inheritDoc}
*/
@Override
public String text() {
return block.text();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.github.jknack.handlebars;

import org.junit.Test;

import java.io.IOException;

import static junit.framework.TestCase.assertEquals;

public class LazyPartialBlockEvaluationTest extends AbstractTest {
@Override
protected void configure(Handlebars handlebars) {
handlebars.setLazyPartialBlockEvaluation(true);
}

@Test
public void shouldSupportMultipleLevelsOfNestedPartialBlocks() throws IOException {
String myMoreNestedPartial = "I{{> @partial-block}}I";
String myNestedPartial = "A{{#> myMoreNestedPartial}}{{> @partial-block}}{{/myMoreNestedPartial}}B";
String myPartial = "{{#> myNestedPartial}}{{> @partial-block}}{{/myNestedPartial}}";
Template t = compile("C{{#> myPartial}}hello{{/myPartial}}D", new Hash(), $("myPartial", myPartial, "myNestedPartial", myNestedPartial,"myMoreNestedPartial", myMoreNestedPartial));
String result = t.apply(null);
assertEquals("'CAIhelloIBD' should === '" + result + "': ", "CAIhelloIBD", result);
}

@Test(expected = HandlebarsException.class)
public void shouldNotDefineInlinePartialsInPartialBlockCall() throws IOException {
// myPartial should not be defined and thus throw a handlebars exception
shouldCompileToWithPartials(
"{{#> dude}}{{#*inline \"myPartial\"}}success{{/inline}}{{/dude}}",
$, $("dude", "{{> myPartial }}"), "");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@

public class PartialBlockTest extends AbstractTest {

@Override
protected Handlebars newHandlebars() {
return super.newHandlebars().lazyPartialBlockEvaluation(false);
}

@Test
public void text() throws IOException {
assertEquals("{{#>dude}}{{#*inline \"myPartial\"}}success{{/inline}}{{/dude}}",
Expand Down