Permalink
Browse files

default helpers

  • Loading branch information...
1 parent f07393b commit 32cdf39d93c96ebe40242a9134afcc07a9734f8a @jdiamond committed Aug 24, 2013
@@ -15,7 +15,7 @@ public void BeforeEach()
[Test]
public void It_can_register_global_helpers()
{
- Helpers.Register("noop", (ctx, args, opts, fn) => fn(null));
+ Helpers.Register("noop", (ctx, args, opts, fn, inverse) => fn(null));
var result = Render.StringToString("{{#noop}}{{value}}{{/noop}}", new {value = 42});
@@ -25,7 +25,7 @@ public void It_can_register_global_helpers()
[Test]
public void It_passes_arguments_into_helpers()
{
- Helpers.Register("link", (ctx, args, opts, fn) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", args[1], args[0])));
+ Helpers.Register("link", (ctx, args, opts, fn, inverse) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", args[1], args[0])));
var result = Render.StringToString("{{link text url}}", new {text = "TEXT", url = "URL"});
@@ -35,7 +35,7 @@ public void It_passes_arguments_into_helpers()
[Test]
public void It_passes_options_into_helpers()
{
- Helpers.Register("link", (ctx, args, opts, fn) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", opts["url"], opts["text"])));
+ Helpers.Register("link", (ctx, args, opts, fn, inverse) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", opts["url"], opts["text"])));
var result = Render.StringToString("{{link text=\"TEXT\" url=\"URL\"}}", new {});
@@ -45,7 +45,7 @@ public void It_passes_options_into_helpers()
[Test]
public void It_passes_arguments_into_block_helpers()
{
- Helpers.Register("list", (ctx, args, opts, fn) =>
+ Helpers.Register("list", (ctx, args, opts, fn, inverse) =>
{
ctx.Write("<ul>");
@@ -74,7 +74,7 @@ public void It_passes_arguments_into_block_helpers()
[Test]
public void It_parses_quoted_arguments_as_literal_strings()
{
- Helpers.Register("link", (ctx, args, opts, fn) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", args[1], args[0])));
+ Helpers.Register("link", (ctx, args, opts, fn, inverse) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", args[1], args[0])));
var result = Render.StringToString("{{link \"TEXT\" \"URL\"}}", new {});
@@ -84,11 +84,67 @@ public void It_parses_quoted_arguments_as_literal_strings()
[Test]
public void It_parses_quoted_options_as_literal_strings()
{
- Helpers.Register("link", (ctx, args, opts, fn) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", opts["url"], opts["text"])));
+ Helpers.Register("link", (ctx, args, opts, fn, inverse) => ctx.Write(string.Format("<a href=\"{0}\">{1}</a>", opts["url"], opts["text"])));
var result = Render.StringToString("{{link text=\"TEXT\" url=\"URL\"}}", new { });
Assert.AreEqual("<a href=\"URL\">TEXT</a>", result);
}
+
+ [Test]
+ public void It_registers_each_by_default()
+ {
+ var result = Render.StringToString(
+ "<ul>{{#each things}}<li>{{.}}</li>{{/each}}</ul>",
+ new { things = new[] { "thing1", "thing2", "thing3" } });
+
+ Assert.AreEqual("<ul><li>thing1</li><li>thing2</li><li>thing3</li></ul>", result);
+ }
+
+ [Test]
+ public void It_registers_if_by_default()
+ {
+ var template = "{{#if error}}<div class=\"alert alert-danger\">{{error.message}}</div>{{else}}<p>No errors</p>{{/if}}";
+
+ var result = Render.StringToString(
+ template,
+ new {error = new {message = "Connection closed"}});
+
+ Assert.AreEqual("<div class=\"alert alert-danger\">Connection closed</div>", result);
+
+ result = Render.StringToString(
+ template,
+ new {error = false});
+
+ Assert.AreEqual("<p>No errors</p>", result);
+ }
+
+ [Test]
+ public void It_registers_unless_by_default()
+ {
+ var template = "{{#unless error}}<p>No errors</p>{{else}}<div class=\"alert alert-danger\">{{error.message}}</div>{{/unless}}";
+
+ var result = Render.StringToString(
+ template,
+ new {error = new {message = "Connection closed"}});
+
+ Assert.AreEqual("<div class=\"alert alert-danger\">Connection closed</div>", result);
+
+ result = Render.StringToString(
+ template,
+ new {error = false});
+
+ Assert.AreEqual("<p>No errors</p>", result);
+ }
+
+ [Test]
+ public void It_registers_with_by_default()
+ {
+ var result = Render.StringToString(
+ "<div class=\"alert alert-danger\">{{#with error}}<p>{{message}}</p>{{/with}}</div>",
+ new { error = new { message = "Connection closed" } });
+
+ Assert.AreEqual("<div class=\"alert alert-danger\"><p>Connection closed</p></div>", result);
+ }
}
}
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using NUnit.Framework;
namespace Nustache.Core.Tests
@@ -132,5 +133,32 @@ public void It_throws_when_the_end_section_does_not_match_any_start_section()
new LiteralText("after")
}));
}
+
+ [Test]
+ public void It_treats_sections_named_else_as_inverse_sections()
+ {
+ var parser = new Parser();
+ var template = new Template();
+
+ parser.Parse(template,
+ new Part[]
+ {
+ new LiteralText("before"),
+ new Block("foo"),
+ new LiteralText("inside1"),
+ new Block("else"),
+ new LiteralText("inside2"),
+ new EndSection("foo"),
+ new LiteralText("after")
+ });
+
+ template.Parts.IsEqualTo(new LiteralText("before"),
+ new Block("foo",
+ new LiteralText("inside1"),
+ new EndSection("foo")),
+ new LiteralText("after"));
+
+ ((Block)template.Parts.ToArray()[1]).Inverse.IsEqualTo(new Block("else", new LiteralText("inside2")));
+ }
}
-}
+}
View
@@ -22,19 +22,31 @@ public override void Render(RenderContext context)
return;
}
- var helper = value as Helper;
+ var helper = value as HelperProxy;
if (helper != null)
{
- helper(context, null, null, data =>
+ helper(data =>
{
context.Enter(this);
context.Push(data);
- base.Render(context);
+ RenderParts(context);
context.Pop();
context.Exit();
+ }, data =>
+ {
+ if (Inverse != null)
+ {
+ context.Enter(Inverse);
+ context.Push(data);
+
+ Inverse.RenderParts(context);
+
+ context.Pop();
+ context.Exit();
+ }
});
return;
View
@@ -1,17 +1,76 @@
-using System.Collections.Generic;
+using System;
+using System.Collections;
+using System.Collections.Generic;
namespace Nustache.Core
{
- public delegate void Helper(RenderContext context, IList<object> arguments, IDictionary<string, object> options, InnerHelper fn);
- public delegate void InnerHelper(object data);
+ public delegate void Helper(RenderContext context, IList<object> arguments, IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse);
+ public delegate void HelperProxy(RenderBlock fn, RenderBlock inverse);
+ public delegate void RenderBlock(object data);
public static class Helpers
{
- private static Dictionary<string, Helper> _helpers = new Dictionary<string, Helper>();
+ private static readonly Dictionary<string, Helper> DefaultHelpers = new Dictionary<string, Helper>();
+ private static readonly Dictionary<string, Helper> CustomHelpers = new Dictionary<string, Helper>();
public static void Register(string name, Helper helper)
{
- _helpers.Add(name, helper);
+ CustomHelpers.Add(name, helper);
+ }
+
+ public static bool Contains(string name)
+ {
+ return CustomHelpers.ContainsKey(name) || DefaultHelpers.ContainsKey(name);
+ }
+
+ public static Helper Get(string name)
+ {
+ return CustomHelpers.ContainsKey(name) ? CustomHelpers[name] : DefaultHelpers[name];
+ }
+
+ public static void Clear()
+ {
+ CustomHelpers.Clear();
+ }
+
+ static Helpers()
+ {
+ DefaultHelpers["each"] = EachHelper;
+ DefaultHelpers["if"] = IfHelper;
+ DefaultHelpers["unless"] = UnlessHelper;
+ DefaultHelpers["with"] = WithHelper;
+ }
+
+ public static void EachHelper(RenderContext context, IList<object> arguments, IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
+ {
+ foreach (var item in (IEnumerable) arguments[0])
+ {
+ fn(item);
+ }
+ }
+
+ public static void IfHelper(RenderContext context, IList<object> arguments, IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
+ {
+ var value = arguments[0];
+
+ if (context.IsTruthy(value))
+ {
+ fn(null);
+ }
+ else
+ {
+ inverse(null);
+ }
+ }
+
+ public static void UnlessHelper(RenderContext context, IList<object> arguments, IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
+ {
+ IfHelper(context, arguments, options, inverse, fn);
+ }
+
+ public static void WithHelper(RenderContext context, IList<object> arguments, IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
+ {
+ fn(arguments[0]);
}
public static void Parse(RenderContext ctx, string path, out string name, out IList<object> arguments, out IDictionary<string, object> options)
@@ -68,7 +127,7 @@ private static void ParseOptions(RenderContext ctx, string[] splits, out IDictio
options = new Dictionary<string, object>();
}
- var splits2 = arg.Split(new[] {'='}, 2);
+ var splits2 = arg.Split(new[] { '=' }, 2);
var key = splits2[0];
var val = splits2[1];
@@ -83,20 +142,5 @@ private static void ParseOptions(RenderContext ctx, string[] splits, out IDictio
}
}
}
-
- public static bool Contains(string name)
- {
- return _helpers.ContainsKey(name);
- }
-
- public static Helper Get(string name)
- {
- return _helpers[name];
- }
-
- public static void Clear()
- {
- _helpers.Clear();
- }
}
}
View
@@ -19,13 +19,29 @@ public void Parse(Section section, IEnumerable<Part> parts)
if (part is Section)
{
- sectionStack.Push(section);
- section = (Section)part;
+ var newSection = (Section)part;
+
+ if (newSection.Name == "else")
+ {
+ section.Inverse = newSection;
+ newSection.Inverse = section;
+ section = newSection;
+ }
+ else
+ {
+ sectionStack.Push(section);
+ section = newSection;
+ }
}
else if (part is EndSection)
{
var endSection = (EndSection)part;
+ if (section.Name == "else")
+ {
+ section = section.Inverse;
+ }
+
if (sectionStack.Count == 1)
{
throw new NustacheException(
@@ -83,7 +83,7 @@ public object GetValue(string path)
{
var helper = Helpers.Get(name);
- return (Helper)((ctx, args, opts, fn) => helper(ctx, arguments, options, fn));
+ return (HelperProxy)((fn, inverse) => helper(this, arguments, options, fn, inverse));
}
if (_renderContextBehaviour.RaiseExceptionOnDataContextMiss)
@@ -182,7 +182,32 @@ public IEnumerable<object> GetValues(string path)
public bool IsTruthy(string path)
{
- return GetValues(path).GetEnumerator().MoveNext();
+ return IsTruthy(GetValue(path));
+ }
+
+ public bool IsTruthy(object value)
+ {
+ if (value == null)
+ {
+ return false;
+ }
+
+ if (value is bool)
+ {
+ return (bool)value;
+ }
+
+ if (value is string)
+ {
+ return !string.IsNullOrEmpty((string)value);
+ }
+
+ if (value is IEnumerable)
+ {
+ return ((IEnumerable)value).GetEnumerator().MoveNext();
+ }
+
+ return true;
}
public void WriteLiteral(string text)
Oops, something went wrong.

0 comments on commit 32cdf39

Please sign in to comment.