Allow string and number arguments
This commit is contained in:
parent
60f8294eb4
commit
19a0710d49
|
@ -1387,5 +1387,69 @@ Odd
|
|||
}
|
||||
|
||||
#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>
|
||||
internal sealed class ArgumentCollection
|
||||
{
|
||||
private readonly Dictionary<TagParameter, string> _argumentLookup;
|
||||
private readonly Dictionary<TagParameter, IArgument> _argumentLookup;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an ArgumentCollection.
|
||||
/// </summary>
|
||||
public ArgumentCollection()
|
||||
{
|
||||
_argumentLookup = new Dictionary<TagParameter, string>();
|
||||
_argumentLookup = new Dictionary<TagParameter, IArgument>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Associates the given parameter to the key placeholder.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public void AddArgument(TagParameter parameter, string key)
|
||||
public void AddArgument(TagParameter parameter, IArgument argument)
|
||||
{
|
||||
_argumentLookup.Add(parameter, key);
|
||||
_argumentLookup.Add(parameter, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -36,10 +36,10 @@ namespace Mustache
|
|||
/// <param name="parameterName">The name of the parameter.</param>
|
||||
public string GetKey(TagParameter parameter)
|
||||
{
|
||||
string key;
|
||||
if (_argumentLookup.TryGetValue(parameter, out key))
|
||||
IArgument argument;
|
||||
if (_argumentLookup.TryGetValue(parameter, out argument) && argument != null)
|
||||
{
|
||||
return key;
|
||||
return argument.GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -56,20 +56,16 @@ namespace Mustache
|
|||
public Dictionary<string, object> GetArguments(Scope keyScope, Scope contextScope)
|
||||
{
|
||||
Dictionary<string, object> arguments = new Dictionary<string,object>();
|
||||
foreach (KeyValuePair<TagParameter, string> pair in _argumentLookup)
|
||||
foreach (KeyValuePair<TagParameter, IArgument> pair in _argumentLookup)
|
||||
{
|
||||
object value;
|
||||
if (pair.Value == null)
|
||||
{
|
||||
value = pair.Key.DefaultValue;
|
||||
}
|
||||
else if (pair.Value.StartsWith("@"))
|
||||
{
|
||||
value = contextScope.Find(pair.Value.Substring(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
value = keyScope.Find(pair.Value);
|
||||
value = pair.Value.GetValue(keyScope, contextScope);
|
||||
}
|
||||
arguments.Add(pair.Key.Name, value);
|
||||
}
|
||||
|
@ -78,7 +74,7 @@ namespace Mustache
|
|||
|
||||
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()
|
||||
{
|
||||
return @"((?<key>@?" + RegexHelper.CompoundKey + @")(,(?<alignment>(\+|-)?[\d]+))?(:(?<format>.*?))?)";
|
||||
return @"((?<key>" + RegexHelper.CompoundKey + @")(,(?<alignment>(\+|-)?[\d]+))?(:(?<format>.*?))?)";
|
||||
}
|
||||
|
||||
private static string getTagRegex(TagDefinition definition)
|
||||
|
@ -164,8 +164,8 @@ namespace Mustache
|
|||
foreach (TagParameter parameter in definition.Parameters)
|
||||
{
|
||||
regexBuilder.Append(@"(\s+?");
|
||||
regexBuilder.Append(@"(?<argument>(@?");
|
||||
regexBuilder.Append(RegexHelper.CompoundKey);
|
||||
regexBuilder.Append(@"(?<argument>(");
|
||||
regexBuilder.Append(RegexHelper.Argument);
|
||||
regexBuilder.Append(@")))");
|
||||
if (!parameter.IsRequired)
|
||||
{
|
||||
|
@ -341,28 +341,46 @@ namespace Mustache
|
|||
foreach (var pair in arguments)
|
||||
{
|
||||
string placeholder = pair.Value;
|
||||
IArgument argument = null;
|
||||
if (placeholder != null)
|
||||
{
|
||||
if (placeholder.StartsWith("@"))
|
||||
{
|
||||
string variableName = placeholder.Substring(1);
|
||||
VariableFoundEventArgs args = new VariableFoundEventArgs(placeholder.Substring(1), String.Empty, String.Empty, context.ToArray());
|
||||
if (VariableFound != null)
|
||||
{
|
||||
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
|
||||
{
|
||||
string placeholderName = placeholder;
|
||||
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(placeholder, String.Empty, String.Empty, context.ToArray());
|
||||
if (PlaceholderFound != null)
|
||||
{
|
||||
PlaceholderFound(this, args);
|
||||
placeholder = args.Key;
|
||||
placeholderName = args.Key;
|
||||
}
|
||||
argument = new PlaceholderArgument(placeholderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
collection.AddArgument(pair.Key, placeholder);
|
||||
collection.AddArgument(pair.Key, argument);
|
||||
}
|
||||
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>
|
||||
/// Provides utility methods that require regular expressions.
|
||||
/// </summary>
|
||||
public static class RegexHelper
|
||||
internal static class RegexHelper
|
||||
{
|
||||
internal const string Key = @"[_\w][_\w\d]*";
|
||||
internal const string CompoundKey = Key + @"(\." + Key + ")*";
|
||||
public const string Key = @"[_\w][_\w\d]*";
|
||||
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>
|
||||
/// Determines whether the given name is a legal identifier.
|
||||
|
@ -25,5 +28,25 @@ namespace Mustache
|
|||
Regex regex = new Regex("^" + Key + "$");
|
||||
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="Context.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="VariableArgument.cs" />
|
||||
<Compile Include="VariableFoundEventArgs.cs" />
|
||||
<Compile Include="SetTagDefinition.cs" />
|
||||
<Compile Include="NewlineTagDefinition.cs" />
|
||||
|
|
Loading…
Reference in New Issue