Support firing event when keys/variables used as arguments.
This commit is contained in:
parent
6e74fa1fcc
commit
6a272230af
|
@ -349,6 +349,63 @@ Content";
|
||||||
CollectionAssert.AreEqual(expected, actual, "Not all placeholders were found.");
|
CollectionAssert.AreEqual(expected, actual, "Not all placeholders were found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We can track all of the keys that appear in a template by
|
||||||
|
/// registering with the PlaceholderFound event.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_FindsVariables_RecordsVariables()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
HashSet<string> variables = new HashSet<string>();
|
||||||
|
compiler.VariableFound += (o, e) =>
|
||||||
|
{
|
||||||
|
variables.Add(e.Name);
|
||||||
|
};
|
||||||
|
compiler.Compile(@"{{@FirstName}}{{@LastName}}");
|
||||||
|
string[] expected = new string[] { "FirstName", "LastName" };
|
||||||
|
string[] actual = variables.OrderBy(s => s).ToArray();
|
||||||
|
CollectionAssert.AreEqual(expected, actual, "Not all variables were found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We can track all of the keys that appear in a template by
|
||||||
|
/// registering with the PlaceholderFound event.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_FindsPlaceholdersInIf_RecordsPlaceholders()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
HashSet<string> keys = new HashSet<string>();
|
||||||
|
compiler.PlaceholderFound += (o, e) =>
|
||||||
|
{
|
||||||
|
keys.Add(e.Key);
|
||||||
|
};
|
||||||
|
compiler.Compile(@"{{#if FirstName}}{{/if}}");
|
||||||
|
string[] expected = new string[] { "FirstName" };
|
||||||
|
string[] actual = keys.OrderBy(s => s).ToArray();
|
||||||
|
CollectionAssert.AreEqual(expected, actual, "Not all placeholders were found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We can track all of the keys that appear in a template by
|
||||||
|
/// registering with the PlaceholderFound event.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_FindsVariablesInIf_RecordsVariables()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
HashSet<string> variables = new HashSet<string>();
|
||||||
|
compiler.VariableFound += (o, e) =>
|
||||||
|
{
|
||||||
|
variables.Add(e.Name);
|
||||||
|
};
|
||||||
|
compiler.Compile(@"{{#if @FirstName}}{{/if}}");
|
||||||
|
string[] expected = new string[] { "FirstName" };
|
||||||
|
string[] actual = variables.OrderBy(s => s).ToArray();
|
||||||
|
CollectionAssert.AreEqual(expected, actual, "Not all placeholders were found.");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// We can determine the context in which a placeholder is found by looking at the provided context array.
|
/// We can determine the context in which a placeholder is found by looking at the provided context array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -48,6 +48,11 @@ namespace Mustache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<PlaceholderFoundEventArgs> PlaceholderFound;
|
public event EventHandler<PlaceholderFoundEventArgs> PlaceholderFound;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a variable is found in the template.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<VariableFoundEventArgs> VariableFound;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers the given tag definition with the parser.
|
/// Registers the given tag definition with the parser.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -140,7 +145,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)
|
||||||
|
@ -198,12 +203,29 @@ namespace Mustache
|
||||||
string key = match.Groups["key"].Value;
|
string key = match.Groups["key"].Value;
|
||||||
string alignment = match.Groups["alignment"].Value;
|
string alignment = match.Groups["alignment"].Value;
|
||||||
string formatting = match.Groups["format"].Value;
|
string formatting = match.Groups["format"].Value;
|
||||||
|
if (key.StartsWith("@"))
|
||||||
|
{
|
||||||
|
VariableFoundEventArgs args = new VariableFoundEventArgs(key.Substring(1), alignment, formatting, context.ToArray());
|
||||||
|
if (VariableFound != null)
|
||||||
|
{
|
||||||
|
VariableFound(this, args);
|
||||||
|
key = "@" + args.Name;
|
||||||
|
alignment = args.Alignment;
|
||||||
|
formatting = args.Formatting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(key, alignment, formatting, context.ToArray());
|
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(key, alignment, formatting, context.ToArray());
|
||||||
if (PlaceholderFound != null)
|
if (PlaceholderFound != null)
|
||||||
{
|
{
|
||||||
PlaceholderFound(this, args);
|
PlaceholderFound(this, args);
|
||||||
|
key = args.Key;
|
||||||
|
alignment = args.Alignment;
|
||||||
|
formatting = args.Formatting;
|
||||||
}
|
}
|
||||||
KeyGenerator keyGenerator = new KeyGenerator(args.Key, args.Alignment, args.Formatting);
|
}
|
||||||
|
KeyGenerator keyGenerator = new KeyGenerator(key, alignment, formatting);
|
||||||
generator.AddGenerator(keyGenerator);
|
generator.AddGenerator(keyGenerator);
|
||||||
}
|
}
|
||||||
else if (match.Groups["open"].Success)
|
else if (match.Groups["open"].Success)
|
||||||
|
@ -216,10 +238,12 @@ namespace Mustache
|
||||||
string message = String.Format(Resources.UnknownTag, tagName);
|
string message = String.Format(Resources.UnknownTag, tagName);
|
||||||
throw new FormatException(message);
|
throw new FormatException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generator.AddGenerator(new StaticGenerator(leading));
|
||||||
|
ArgumentCollection arguments = getArguments(nextDefinition, match, context);
|
||||||
|
|
||||||
if (nextDefinition.HasContent)
|
if (nextDefinition.HasContent)
|
||||||
{
|
{
|
||||||
generator.AddGenerator(new StaticGenerator(leading));
|
|
||||||
ArgumentCollection arguments = getArguments(nextDefinition, match);
|
|
||||||
CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments);
|
CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments);
|
||||||
IEnumerable<TagParameter> contextParameters = nextDefinition.GetChildContextParameters();
|
IEnumerable<TagParameter> contextParameters = nextDefinition.GetChildContextParameters();
|
||||||
bool hasContext = contextParameters.Any();
|
bool hasContext = contextParameters.Any();
|
||||||
|
@ -237,8 +261,6 @@ namespace Mustache
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
generator.AddGenerator(new StaticGenerator(leading));
|
|
||||||
ArgumentCollection arguments = getArguments(nextDefinition, match);
|
|
||||||
InlineGenerator inlineGenerator = new InlineGenerator(nextDefinition, arguments);
|
InlineGenerator inlineGenerator = new InlineGenerator(nextDefinition, arguments);
|
||||||
generator.AddGenerator(inlineGenerator);
|
generator.AddGenerator(inlineGenerator);
|
||||||
}
|
}
|
||||||
|
@ -270,9 +292,9 @@ namespace Mustache
|
||||||
return formatIndex;
|
return formatIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ArgumentCollection getArguments(TagDefinition definition, Match match)
|
private ArgumentCollection getArguments(TagDefinition definition, Match match, List<Context> context)
|
||||||
{
|
{
|
||||||
ArgumentCollection collection = new ArgumentCollection();
|
// make sure we don't have too many arguments
|
||||||
List<Capture> captures = match.Groups["argument"].Captures.Cast<Capture>().ToList();
|
List<Capture> captures = match.Groups["argument"].Captures.Cast<Capture>().ToList();
|
||||||
List<TagParameter> parameters = definition.Parameters.ToList();
|
List<TagParameter> parameters = definition.Parameters.ToList();
|
||||||
if (captures.Count > parameters.Count)
|
if (captures.Count > parameters.Count)
|
||||||
|
@ -280,26 +302,61 @@ namespace Mustache
|
||||||
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
||||||
throw new FormatException(message);
|
throw new FormatException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// provide default values for missing arguments
|
||||||
if (captures.Count < parameters.Count)
|
if (captures.Count < parameters.Count)
|
||||||
{
|
{
|
||||||
captures.AddRange(Enumerable.Repeat((Capture)null, parameters.Count - captures.Count));
|
captures.AddRange(Enumerable.Repeat((Capture)null, parameters.Count - captures.Count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pair up the parameters to the given arguments
|
||||||
|
// provide default for parameters with missing arguments
|
||||||
|
// throw an error if a missing argument is for a required parameter
|
||||||
|
Dictionary<TagParameter, string> arguments = new Dictionary<TagParameter, string>();
|
||||||
foreach (var pair in parameters.Zip(captures, (p, c) => new { Capture = c, Parameter = p }))
|
foreach (var pair in parameters.Zip(captures, (p, c) => new { Capture = c, Parameter = p }))
|
||||||
{
|
{
|
||||||
if (pair.Capture == null)
|
string value = null;
|
||||||
|
if (pair.Capture != null)
|
||||||
{
|
{
|
||||||
if (pair.Parameter.IsRequired)
|
value = pair.Capture.Value;
|
||||||
|
}
|
||||||
|
else if (pair.Parameter.IsRequired)
|
||||||
{
|
{
|
||||||
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
||||||
throw new FormatException(message);
|
throw new FormatException(message);
|
||||||
}
|
}
|
||||||
collection.AddArgument(pair.Parameter, null);
|
arguments.Add(pair.Parameter, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// indicate that a key/variable has been encountered
|
||||||
|
// update the key/variable name
|
||||||
|
ArgumentCollection collection = new ArgumentCollection();
|
||||||
|
foreach (var pair in arguments)
|
||||||
|
{
|
||||||
|
string placeholder = pair.Value;
|
||||||
|
if (placeholder != null)
|
||||||
|
{
|
||||||
|
if (placeholder.StartsWith("@"))
|
||||||
|
{
|
||||||
|
VariableFoundEventArgs args = new VariableFoundEventArgs(placeholder.Substring(1), String.Empty, String.Empty, context.ToArray());
|
||||||
|
if (VariableFound != null)
|
||||||
|
{
|
||||||
|
VariableFound(this, args);
|
||||||
|
placeholder = "@" + args.Name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
collection.AddArgument(pair.Parameter, pair.Capture.Value);
|
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(placeholder, String.Empty, String.Empty, context.ToArray());
|
||||||
|
if (PlaceholderFound != null)
|
||||||
|
{
|
||||||
|
PlaceholderFound(this, args);
|
||||||
|
placeholder = args.Key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
collection.AddArgument(pair.Key, placeholder);
|
||||||
|
}
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace Mustache
|
||||||
{
|
{
|
||||||
private readonly string _key;
|
private readonly string _key;
|
||||||
private readonly string _format;
|
private readonly string _format;
|
||||||
|
private readonly bool _isVariable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of a KeyGenerator.
|
/// Initializes a new instance of a KeyGenerator.
|
||||||
|
@ -19,8 +20,17 @@ namespace Mustache
|
||||||
/// <param name="alignment">The alignment specifier.</param>
|
/// <param name="alignment">The alignment specifier.</param>
|
||||||
/// <param name="formatting">The format specifier.</param>
|
/// <param name="formatting">The format specifier.</param>
|
||||||
public KeyGenerator(string key, string alignment, string formatting)
|
public KeyGenerator(string key, string alignment, string formatting)
|
||||||
|
{
|
||||||
|
if (key.StartsWith("@"))
|
||||||
|
{
|
||||||
|
_key = key.Substring(1);
|
||||||
|
_isVariable = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_key = key;
|
_key = key;
|
||||||
|
_isVariable = false;
|
||||||
|
}
|
||||||
_format = getFormat(alignment, formatting);
|
_format = getFormat(alignment, formatting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +54,7 @@ namespace Mustache
|
||||||
|
|
||||||
void IGenerator.GetText(Scope scope, TextWriter writer, Scope context)
|
void IGenerator.GetText(Scope scope, TextWriter writer, Scope context)
|
||||||
{
|
{
|
||||||
object value = scope.Find(_key);
|
object value = _isVariable ? context.Find(_key) : scope.Find(_key);
|
||||||
writer.Write(_format, value);
|
writer.Write(_format, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using Mustache.Properties;
|
||||||
|
|
||||||
|
namespace Mustache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the information descibing a variable that is found in a template.
|
||||||
|
/// </summary>
|
||||||
|
public class VariableFoundEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of a VariableFoundEventArgs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key that was found.</param>
|
||||||
|
/// <param name="alignment">The alignment that will be applied to the substitute value.</param>
|
||||||
|
/// <param name="formatting">The formatting that will be applied to the substitute value.</param>
|
||||||
|
/// <param name="context">The context where the placeholder was found.</param>
|
||||||
|
internal VariableFoundEventArgs(string name, string alignment, string formatting, Context[] context)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Alignment = alignment;
|
||||||
|
Formatting = formatting;
|
||||||
|
Context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the key that was found.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the alignment that will be applied to the substitute value.
|
||||||
|
/// </summary>
|
||||||
|
public string Alignment { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the formatting that will be applied to the substitute value.
|
||||||
|
/// </summary>
|
||||||
|
public string Formatting { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the context where the placeholder was found.
|
||||||
|
/// </summary>
|
||||||
|
public Context[] Context { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,7 @@
|
||||||
<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="VariableFoundEventArgs.cs" />
|
||||||
<Compile Include="SetTagDefinition.cs" />
|
<Compile Include="SetTagDefinition.cs" />
|
||||||
<Compile Include="NewlineTagDefinition.cs" />
|
<Compile Include="NewlineTagDefinition.cs" />
|
||||||
<Compile Include="IndexTagDefinition.cs" />
|
<Compile Include="IndexTagDefinition.cs" />
|
||||||
|
|
Loading…
Reference in New Issue