Added more methods to LambdaContext
diff --git a/lib/mustache.dart b/lib/mustache.dart
index 197b89a..ba7c513 100644
--- a/lib/mustache.dart
+++ b/lib/mustache.dart
@@ -61,28 +61,29 @@
 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);
 }
 
-
 const MustacheMirrorsUsedAnnotation mustache = const MustacheMirrorsUsedAnnotation();
 
 class MustacheMirrorsUsedAnnotation {
diff --git a/lib/src/lambda_context.dart b/lib/src/lambda_context.dart
index 2ed1e47..2d634af 100644
--- a/lib/src/lambda_context.dart
+++ b/lib/src/lambda_context.dart
@@ -26,29 +26,34 @@
   
   /// Render the current section tag in the current context and return the
   /// result as a string.
-  String renderString() {
+  String renderString({Object value}) {
+    _checkClosed();
     if (_node is! _SectionNode) _error(
         'LambdaContext.renderString() can only be called on section tags.');
-    _checkClosed();
     var sink = new StringBuffer();
-    var ctx = new _RenderContext.subtree(_context, sink);
-    _SectionNode section = _node;
-    _renderWithContext(ctx, section.children);
+    _renderSubtree(sink, value);
     return sink.toString();
   }
 
-  //FIXME Currently only return values are supported.
-  /// Render and directly output the current section tag.
-//  void render() {
-//    _checkClosed();
-//  }
+  void _renderSubtree(StringSink sink, Object value) {
+    var ctx = new _RenderContext.subtree(_context, sink);
+    _SectionNode section = _node;
+    if (value != null) ctx.push(value);
+    _renderWithContext(ctx, section.children);
+  }
+  
+  void render({Object value}) {
+    _checkClosed();
+    if (_node is! _SectionNode) _error(
+        'LambdaContext.render() can only be called on section tags.');
+    _renderSubtree(_context._sink, value);
+  }
 
-  //FIXME Currently only return values are supported.
-  /// Output a string.
-//  void write(Object object) {
-//    _checkClosed();
-//  }
-
+  void write(Object object) {
+    _checkClosed();
+    _context.write(object);
+  }
+  
   /// Get the unevaluated template source for the current section tag.
   String get source {
     _checkClosed();
@@ -69,7 +74,7 @@
   }
 
   /// Evaluate the string as a mustache template using the current context.
-  String renderSource(String source) {
+  String renderSource(String source, {Object value}) {
     _checkClosed();
     var sink = new StringBuffer();
     
@@ -92,6 +97,7 @@
         sink,
         delimiters);
     
+    if (value != null) ctx.push(value);
     _renderWithContext(ctx, nodes);
 
     return sink.toString();
diff --git a/lib/src/node.dart b/lib/src/node.dart
index edd7b4e..5140574 100644
--- a/lib/src/node.dart
+++ b/lib/src/node.dart
@@ -88,7 +88,7 @@
       var output = !escape || !ctx.htmlEscapeValues
         ? valueString
         : _htmlEscape(valueString);
-      ctx.write(output);
+      if (output != null) ctx.write(output);
     }
   }
   
@@ -169,7 +169,7 @@
       var context = new _LambdaContext(this, renderer, isSection: true);
       var output = value(context);
       context.close();        
-      renderer.write(output);
+      if (output != null) renderer.write(output);
       
     } else {
       throw renderer.error('Invalid value type for section, '
@@ -210,9 +210,9 @@
   }
   
   void _renderWithValue(_RenderContext ctx, value) {
-    ctx.pushValue(value);
+    ctx.push(value);
     children.forEach((n) => n.render(ctx));
-    ctx.popValue();
+    ctx.pop();
   }
 }
 
diff --git a/lib/src/render_context.dart b/lib/src/render_context.dart
index 4f1c8f7..c114380 100644
--- a/lib/src/render_context.dart
+++ b/lib/src/render_context.dart
@@ -61,9 +61,9 @@
   final String indent;
   final String source;
 
-  void pushValue(value) => _stack.add(value);
+  void push(value) => _stack.add(value);
   
-  Object popValue() => _stack.removeLast();
+  Object pop() => _stack.removeLast();
   
   write(Object output) => _sink.write(output.toString());
     
diff --git a/test/mustache_test.dart b/test/mustache_test.dart
index f0782f4..055f4fe 100644
--- a/test/mustache_test.dart
+++ b/test/mustache_test.dart
@@ -593,6 +593,65 @@
       expect(val, equals('(It worked!)'));
     });
   });
+  
+  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));      
+    });
+    
+  });
 }
 
 renderFail(source, values) {