Allow string and number arguments
This commit is contained in:
parent
60f8294eb4
commit
19a0710d49
|
@ -1387,5 +1387,69 @@ Odd
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Strings
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We will use a string variable to determine whether or not to print out a line.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_StringArgument_PassedToTag()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
const string format = @"{{#if 'hello'}}Hello{{/if}}";
|
||||||
|
Generator generator = compiler.Compile(format);
|
||||||
|
string actual = generator.Render(null);
|
||||||
|
string expected = "Hello";
|
||||||
|
Assert.AreEqual(expected, actual, "The string was not passed to the formatter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We will use a string variable to determine whether or not to print out a line.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_EmptyStringArgument_PassedToTag()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
const string format = @"{{#if ''}}Hello{{/if}}";
|
||||||
|
Generator generator = compiler.Compile(format);
|
||||||
|
string actual = generator.Render(null);
|
||||||
|
string expected = "";
|
||||||
|
Assert.AreEqual(expected, actual, "The string was not passed to the formatter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Numbers
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We will use a number variable to determine whether or not to print out a line.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_NumberArgument_PassedToTag()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
const string format = @"{{#if 4}}Hello{{/if}}";
|
||||||
|
Generator generator = compiler.Compile(format);
|
||||||
|
string actual = generator.Render(null);
|
||||||
|
string expected = "Hello";
|
||||||
|
Assert.AreEqual(expected, actual, "The number was not passed to the formatter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We will use a string variable to determine whether or not to print out a line.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_ZeroNumberArgument_PassedToTag()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
const string format = @"{{#if 00.0000}}Hello{{/if}}";
|
||||||
|
Generator generator = compiler.Compile(format);
|
||||||
|
string actual = generator.Render(null);
|
||||||
|
string expected = "";
|
||||||
|
Assert.AreEqual(expected, actual, "The number was not passed to the formatter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,25 +9,25 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ArgumentCollection
|
internal sealed class ArgumentCollection
|
||||||
{
|
{
|
||||||
private readonly Dictionary<TagParameter, string> _argumentLookup;
|
private readonly Dictionary<TagParameter, IArgument> _argumentLookup;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of an ArgumentCollection.
|
/// Initializes a new instance of an ArgumentCollection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ArgumentCollection()
|
public ArgumentCollection()
|
||||||
{
|
{
|
||||||
_argumentLookup = new Dictionary<TagParameter, string>();
|
_argumentLookup = new Dictionary<TagParameter, IArgument>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Associates the given parameter to the key placeholder.
|
/// Associates the given parameter to the key placeholder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parameter">The parameter to associate the key with.</param>
|
/// <param name="parameter">The parameter to associate the key with.</param>
|
||||||
/// <param name="key">The key placeholder used as the argument.</param>
|
/// <param name="key">The argument.</param>
|
||||||
/// <remarks>If the key is null, the default value of the parameter will be used.</remarks>
|
/// <remarks>If the key is null, the default value of the parameter will be used.</remarks>
|
||||||
public void AddArgument(TagParameter parameter, string key)
|
public void AddArgument(TagParameter parameter, IArgument argument)
|
||||||
{
|
{
|
||||||
_argumentLookup.Add(parameter, key);
|
_argumentLookup.Add(parameter, argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -36,10 +36,10 @@ namespace Mustache
|
||||||
/// <param name="parameterName">The name of the parameter.</param>
|
/// <param name="parameterName">The name of the parameter.</param>
|
||||||
public string GetKey(TagParameter parameter)
|
public string GetKey(TagParameter parameter)
|
||||||
{
|
{
|
||||||
string key;
|
IArgument argument;
|
||||||
if (_argumentLookup.TryGetValue(parameter, out key))
|
if (_argumentLookup.TryGetValue(parameter, out argument) && argument != null)
|
||||||
{
|
{
|
||||||
return key;
|
return argument.GetKey();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -56,20 +56,16 @@ namespace Mustache
|
||||||
public Dictionary<string, object> GetArguments(Scope keyScope, Scope contextScope)
|
public Dictionary<string, object> GetArguments(Scope keyScope, Scope contextScope)
|
||||||
{
|
{
|
||||||
Dictionary<string, object> arguments = new Dictionary<string,object>();
|
Dictionary<string, object> arguments = new Dictionary<string,object>();
|
||||||
foreach (KeyValuePair<TagParameter, string> pair in _argumentLookup)
|
foreach (KeyValuePair<TagParameter, IArgument> pair in _argumentLookup)
|
||||||
{
|
{
|
||||||
object value;
|
object value;
|
||||||
if (pair.Value == null)
|
if (pair.Value == null)
|
||||||
{
|
{
|
||||||
value = pair.Key.DefaultValue;
|
value = pair.Key.DefaultValue;
|
||||||
}
|
}
|
||||||
else if (pair.Value.StartsWith("@"))
|
|
||||||
{
|
|
||||||
value = contextScope.Find(pair.Value.Substring(1));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
value = keyScope.Find(pair.Value);
|
value = pair.Value.GetValue(keyScope, contextScope);
|
||||||
}
|
}
|
||||||
arguments.Add(pair.Key.Name, value);
|
arguments.Add(pair.Key.Name, value);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +74,7 @@ namespace Mustache
|
||||||
|
|
||||||
public Dictionary<string, object> GetArgumentKeyNames()
|
public Dictionary<string, object> GetArgumentKeyNames()
|
||||||
{
|
{
|
||||||
return _argumentLookup.ToDictionary(p => p.Key.Name, p => (object)p.Value);
|
return _argumentLookup.ToDictionary(p => p.Key.Name, p => (object)GetKey(p.Key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ namespace Mustache
|
||||||
|
|
||||||
private static string getKeyRegex()
|
private static string getKeyRegex()
|
||||||
{
|
{
|
||||||
return @"((?<key>@?" + RegexHelper.CompoundKey + @")(,(?<alignment>(\+|-)?[\d]+))?(:(?<format>.*?))?)";
|
return @"((?<key>" + RegexHelper.CompoundKey + @")(,(?<alignment>(\+|-)?[\d]+))?(:(?<format>.*?))?)";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string getTagRegex(TagDefinition definition)
|
private static string getTagRegex(TagDefinition definition)
|
||||||
|
@ -164,8 +164,8 @@ namespace Mustache
|
||||||
foreach (TagParameter parameter in definition.Parameters)
|
foreach (TagParameter parameter in definition.Parameters)
|
||||||
{
|
{
|
||||||
regexBuilder.Append(@"(\s+?");
|
regexBuilder.Append(@"(\s+?");
|
||||||
regexBuilder.Append(@"(?<argument>(@?");
|
regexBuilder.Append(@"(?<argument>(");
|
||||||
regexBuilder.Append(RegexHelper.CompoundKey);
|
regexBuilder.Append(RegexHelper.Argument);
|
||||||
regexBuilder.Append(@")))");
|
regexBuilder.Append(@")))");
|
||||||
if (!parameter.IsRequired)
|
if (!parameter.IsRequired)
|
||||||
{
|
{
|
||||||
|
@ -341,28 +341,46 @@ namespace Mustache
|
||||||
foreach (var pair in arguments)
|
foreach (var pair in arguments)
|
||||||
{
|
{
|
||||||
string placeholder = pair.Value;
|
string placeholder = pair.Value;
|
||||||
|
IArgument argument = null;
|
||||||
if (placeholder != null)
|
if (placeholder != null)
|
||||||
{
|
{
|
||||||
if (placeholder.StartsWith("@"))
|
if (placeholder.StartsWith("@"))
|
||||||
{
|
{
|
||||||
|
string variableName = placeholder.Substring(1);
|
||||||
VariableFoundEventArgs args = new VariableFoundEventArgs(placeholder.Substring(1), String.Empty, String.Empty, context.ToArray());
|
VariableFoundEventArgs args = new VariableFoundEventArgs(placeholder.Substring(1), String.Empty, String.Empty, context.ToArray());
|
||||||
if (VariableFound != null)
|
if (VariableFound != null)
|
||||||
{
|
{
|
||||||
VariableFound(this, args);
|
VariableFound(this, args);
|
||||||
placeholder = "@" + args.Name;
|
variableName = args.Name;
|
||||||
|
}
|
||||||
|
argument = new VariableArgument(variableName);
|
||||||
|
}
|
||||||
|
else if (RegexHelper.IsString(placeholder))
|
||||||
|
{
|
||||||
|
string value = placeholder.Trim('\'');
|
||||||
|
argument = new StringArgument(value);
|
||||||
|
}
|
||||||
|
else if (RegexHelper.IsNumber(placeholder))
|
||||||
|
{
|
||||||
|
decimal number;
|
||||||
|
if (Decimal.TryParse(placeholder, out number))
|
||||||
|
{
|
||||||
|
argument = new NumberArgument(number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
string placeholderName = placeholder;
|
||||||
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(placeholder, String.Empty, String.Empty, context.ToArray());
|
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(placeholder, String.Empty, String.Empty, context.ToArray());
|
||||||
if (PlaceholderFound != null)
|
if (PlaceholderFound != null)
|
||||||
{
|
{
|
||||||
PlaceholderFound(this, args);
|
PlaceholderFound(this, args);
|
||||||
placeholder = args.Key;
|
placeholderName = args.Key;
|
||||||
|
}
|
||||||
|
argument = new PlaceholderArgument(placeholderName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
collection.AddArgument(pair.Key, argument);
|
||||||
collection.AddArgument(pair.Key, placeholder);
|
|
||||||
}
|
}
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
public interface IArgument
|
||||||
|
{
|
||||||
|
string GetKey();
|
||||||
|
|
||||||
|
object GetValue(Scope keyScope, Scope contextScope);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
public class NumberArgument : IArgument
|
||||||
|
{
|
||||||
|
private readonly decimal value;
|
||||||
|
|
||||||
|
public NumberArgument(decimal value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetKey()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetValue(Scope keyScope, Scope contextScope)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
public class PlaceholderArgument : IArgument
|
||||||
|
{
|
||||||
|
private readonly string name;
|
||||||
|
|
||||||
|
public PlaceholderArgument(string name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetKey()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetValue(Scope keyScope, Scope contextScope)
|
||||||
|
{
|
||||||
|
return keyScope.Find(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,10 +6,13 @@ namespace Mustache
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides utility methods that require regular expressions.
|
/// Provides utility methods that require regular expressions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class RegexHelper
|
internal static class RegexHelper
|
||||||
{
|
{
|
||||||
internal const string Key = @"[_\w][_\w\d]*";
|
public const string Key = @"[_\w][_\w\d]*";
|
||||||
internal const string CompoundKey = Key + @"(\." + Key + ")*";
|
public const string String = @"'.*?'";
|
||||||
|
public const string Number = @"[-+]?\d*\.?\d+";
|
||||||
|
public const string CompoundKey = "@?" + Key + @"(?:\." + Key + ")*";
|
||||||
|
public const string Argument = @"(?:(?<arg_key>" + CompoundKey + @")|(?<arg_string>" + String + @")|(?<arg_number>" + Number + @"))";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the given name is a legal identifier.
|
/// Determines whether the given name is a legal identifier.
|
||||||
|
@ -25,5 +28,25 @@ namespace Mustache
|
||||||
Regex regex = new Regex("^" + Key + "$");
|
Regex regex = new Regex("^" + Key + "$");
|
||||||
return regex.IsMatch(name);
|
return regex.IsMatch(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsString(string value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Regex regex = new Regex("^" + String + "$");
|
||||||
|
return regex.IsMatch(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsNumber(string value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Regex regex = new Regex("^" + Number + "$");
|
||||||
|
return regex.IsMatch(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
public class StringArgument : IArgument
|
||||||
|
{
|
||||||
|
private readonly string value;
|
||||||
|
|
||||||
|
public StringArgument(string value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetKey()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetValue(Scope keyScope, Scope contextScope)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
public class VariableArgument : IArgument
|
||||||
|
{
|
||||||
|
private readonly string name;
|
||||||
|
|
||||||
|
public VariableArgument(string name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetKey()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetValue(Scope keyScope, Scope contextScope)
|
||||||
|
{
|
||||||
|
return contextScope.Find(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,12 @@
|
||||||
<Compile Include="ContentTagDefinition.cs" />
|
<Compile Include="ContentTagDefinition.cs" />
|
||||||
<Compile Include="Context.cs" />
|
<Compile Include="Context.cs" />
|
||||||
<Compile Include="ContextParameter.cs" />
|
<Compile Include="ContextParameter.cs" />
|
||||||
|
<Compile Include="IArgument.cs" />
|
||||||
|
<Compile Include="NumberArgument.cs" />
|
||||||
|
<Compile Include="PlaceholderArgument.cs" />
|
||||||
|
<Compile Include="StringArgument.cs" />
|
||||||
<Compile Include="UpcastDictionary.cs" />
|
<Compile Include="UpcastDictionary.cs" />
|
||||||
|
<Compile Include="VariableArgument.cs" />
|
||||||
<Compile Include="VariableFoundEventArgs.cs" />
|
<Compile Include="VariableFoundEventArgs.cs" />
|
||||||
<Compile Include="SetTagDefinition.cs" />
|
<Compile Include="SetTagDefinition.cs" />
|
||||||
<Compile Include="NewlineTagDefinition.cs" />
|
<Compile Include="NewlineTagDefinition.cs" />
|
||||||
|
|
Loading…
Reference in New Issue