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': []});