Add write, render and optional values to LambdaContext
diff --git a/lib/mustache.dart b/lib/mustache.dart
index eab0f6c..742370c 100644
--- a/lib/mustache.dart
+++ b/lib/mustache.dart
@@ -61,24 +61,26 @@
abstract class LambdaContext {
/// Render the current section tag in the current context and return the
- /// result as a string.
- String renderString();
+ /// result as a string. If provided, value will be added to the top of the
+ /// context's stack.
+ String renderString({Object value});
- /// Render and directly output the current section tag.
- //TODO note in variable case need to capture output in a string buffer and escape.
- //void render();
+ /// Render and directly output the current section tag. If provided, value
+ /// will be added to the top of the context's stack.
+ void render({Object value});
- /// Output a string.
- //TODO note in variable case need to capture output in a string buffer and escape.
- //void write(Object object);
+ /// Output a string. The output will not be html escaped, and will be written
+ /// before the output returned from the lambda.
+ void write(Object object);
/// Get the unevaluated template source for the current section tag.
String get source;
- /// Evaluate the string as a mustache template using the current context.
- String renderSource(String source);
+ /// Evaluate the string as a mustache template using the current context. If
+ /// provided, value will be added to the top of the context's stack.
+ String renderSource(String source, {Object value});
- /// Lookup the value of a variable in the current context.
+ /// Lookup the value of a variable in the current context.
Object lookup(String variableName);
}
diff --git a/lib/src/lambda_context.dart b/lib/src/lambda_context.dart
index 37056a9..158101c 100644
--- a/lib/src/lambda_context.dart
+++ b/lib/src/lambda_context.dart
@@ -20,27 +20,26 @@
'LambdaContext accessed outside of callback.',
_renderer._templateName, _renderer._source, _node.start);
}
-
- /// Render the current section tag in the current context and return the
- /// result as a string.
- String renderString() {
+
+ //TODO is allowing adding value to the stack a good idea?? Not sure.
+ String renderString({Object value}) {
_checkClosed();
- return _renderer._renderSubtree(_node);
+ var buffer = new StringBuffer();
+ _renderer._renderSubtree(_node, buffer, value: value);
+ return buffer.toString();
}
- //FIXME Currently only return values are supported.
- /// Render and directly output the current section tag.
-// void render() {
-// _checkClosed();
-// }
+ //TODO is allowing adding value to the stack a good idea?? Not sure.
+ void render({Object value}) {
+ _checkClosed();
+ _renderer._renderSubtree(_node, _renderer._sink, value: value);
+ }
- //FIXME Currently only return values are supported.
- /// Output a string.
-// void write(Object object) {
-// _checkClosed();
-// }
+ void write(Object object) {
+ _checkClosed();
+ _renderer._sink.write(object);
+ }
- /// Get the unevaluated template source for the current section tag.
String get source {
_checkClosed();
@@ -57,8 +56,8 @@
return source;
}
- /// Evaluate the string as a mustache template using the current context.
- String renderSource(String source) {
+ //TODO is allowing adding value to the stack a good idea?? Not sure.
+ String renderSource(String source, {Object value}) {
_checkClosed();
var sink = new StringBuffer();
// Lambdas used for sections should parse with the current delimiters.
@@ -74,7 +73,11 @@
_renderer._indent,
sink,
_renderer._delimiters);
+
+ if (value != null) renderer._stack.add(value);
renderer.render();
+ if (value != null) renderer._stack.removeLast();
+
return sink.toString();
}
diff --git a/lib/src/renderer.dart b/lib/src/renderer.dart
index 0387aa0..3c4c054 100644
--- a/lib/src/renderer.dart
+++ b/lib/src/renderer.dart
@@ -232,11 +232,11 @@
_stack.removeLast();
}
- String _renderSubtree(node) {
- var sink = new StringBuffer();
+ void _renderSubtree(node, StringSink sink, {Object value}) {
var renderer = new _Renderer.subtree(this, node, sink);
+ if (value != null) renderer._stack.add(value);
renderer.render();
- return sink.toString();
+ if (value != null) renderer._stack.removeLast();
}
_renderSection(_Node node) {
@@ -264,8 +264,8 @@
} else if (value is Function) {
var context = new _LambdaContext(node, this, isSection: true);
var output = value(context);
- context.close();
- _write(output);
+ context.close();
+ if (output != null) _write(output);
} else {
throw _error('Invalid value type for section, '
diff --git a/test/mustache_test.dart b/test/mustache_test.dart
index 8e4f686..6d6cfb5 100644
--- a/test/mustache_test.dart
+++ b/test/mustache_test.dart
@@ -503,8 +503,8 @@
var values = {'markdown': (ctx) => ctx.source};
var output = '<dsfsf dsfsdf dfsdfsd>';
expect(parse(template).renderString(values), equals(output));
- });
-
+ });
+
test('Alternate Delimiters', () {
// A lambda's return value should parse with the default delimiters.
@@ -541,6 +541,65 @@
});
});
+ group('Lambda context', () {
+
+ test("LambdaContext write", () {
+ var template = '<{{#markdown}}{{content}}{{/markdown}}>';
+ var values = {'markdown': (ctx) {
+ ctx.write('foo');
+ }};
+ var output = '<foo>';
+ expect(parse(template).renderString(values), equals(output));
+ });
+
+ test("LambdaContext render", () {
+ var template = '<{{#markdown}}{{content}}{{/markdown}}>';
+ var values = {'content': 'bar', 'markdown': (ctx) {
+ ctx.render();
+ }};
+ var output = '<bar>';
+ expect(parse(template).renderString(values), equals(output));
+ });
+
+ test("LambdaContext render with value", () {
+ var template = '<{{#markdown}}{{content}}{{/markdown}}>';
+ var values = {'markdown': (LambdaContext ctx) {
+ ctx.render(value: {'content': 'oi!'});
+ }};
+ var output = '<oi!>';
+ expect(parse(template).renderString(values), equals(output));
+ });
+
+ test("LambdaContext renderString with value", () {
+ var template = '<{{#markdown}}{{content}}{{/markdown}}>';
+ var values = {'markdown': (LambdaContext ctx) {
+ return ctx.renderString(value: {'content': 'oi!'});
+ }};
+ var output = '<oi!>';
+ expect(parse(template).renderString(values), equals(output));
+ });
+
+ test("LambdaContext write and return", () {
+ var template = '<{{#markdown}}{{content}}{{/markdown}}>';
+ var values = {'markdown': (LambdaContext ctx) {
+ ctx.write('foo');
+ return 'bar';
+ }};
+ var output = '<foobar>';
+ expect(parse(template).renderString(values), equals(output));
+ });
+
+ test("LambdaContext renderSource with value", () {
+ var template = '<{{#markdown}}{{content}}{{/markdown}}>';
+ var values = {'markdown': (LambdaContext ctx) {
+ return ctx.renderSource(ctx.source, value: {'content': 'oi!'});
+ }};
+ var output = '<oi!>';
+ expect(parse(template).renderString(values), equals(output));
+ });
+
+ });
+
group('Other', () {
test('Standalone line', () {
var val = parse('|\n{{#bob}}\n{{/bob}}\n|').renderString({'bob': []});