Fire event whenever a placeholder is found.
It could be useful to track which placeholders were found when parsing the template. This event will allow keys to be mapped to different keys, and support changing alignment and formatting.
This commit is contained in:
parent
a6c7933bab
commit
20dcfc059d
|
@ -1,8 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
namespace mustache.test
|
namespace mustache.test
|
||||||
{
|
{
|
||||||
|
@ -327,6 +327,25 @@ Content";
|
||||||
Assert.AreEqual(expected, result, "The wrong text was generated.");
|
Assert.AreEqual(expected, result, "The wrong text was generated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// We can track all of the keys that appear in a template by
|
||||||
|
/// registering with the PlaceholderFound event.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_FindsKeys_RecordsKeys()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
HashSet<string> keys = new HashSet<string>();
|
||||||
|
compiler.PlaceholderFound += (o, e) =>
|
||||||
|
{
|
||||||
|
keys.Add(e.Key);
|
||||||
|
};
|
||||||
|
compiler.Compile(@"{{FirstName}} {{LastName}}");
|
||||||
|
string[] expected = new string[] { "FirstName", "LastName" };
|
||||||
|
string[] actual = keys.OrderBy(s => s).ToArray();
|
||||||
|
CollectionAssert.AreEqual(expected, actual, "Not all placeholders were found.");
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Comment
|
#region Comment
|
||||||
|
|
|
@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||||
//
|
//
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
[assembly: AssemblyVersion("0.0.5.0")]
|
[assembly: AssemblyVersion("0.0.6.0")]
|
||||||
[assembly: AssemblyFileVersion("0.0.5.0")]
|
[assembly: AssemblyFileVersion("0.0.6.0")]
|
||||||
|
|
|
@ -1,279 +1,289 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using mustache.Properties;
|
using mustache.Properties;
|
||||||
|
|
||||||
namespace mustache
|
namespace mustache
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses a format string and returns a text generator.
|
/// Parses a format string and returns a text generator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class FormatCompiler
|
public sealed class FormatCompiler
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, TagDefinition> _tagLookup;
|
private readonly Dictionary<string, TagDefinition> _tagLookup;
|
||||||
private readonly Dictionary<string, Regex> _regexLookup;
|
private readonly Dictionary<string, Regex> _regexLookup;
|
||||||
private readonly MasterTagDefinition _masterDefinition;
|
private readonly MasterTagDefinition _masterDefinition;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of a FormatCompiler.
|
/// Initializes a new instance of a FormatCompiler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FormatCompiler()
|
public FormatCompiler()
|
||||||
{
|
{
|
||||||
_tagLookup = new Dictionary<string, TagDefinition>();
|
_tagLookup = new Dictionary<string, TagDefinition>();
|
||||||
_regexLookup = new Dictionary<string, Regex>();
|
_regexLookup = new Dictionary<string, Regex>();
|
||||||
_masterDefinition = new MasterTagDefinition();
|
_masterDefinition = new MasterTagDefinition();
|
||||||
|
|
||||||
IfTagDefinition ifDefinition = new IfTagDefinition();
|
IfTagDefinition ifDefinition = new IfTagDefinition();
|
||||||
_tagLookup.Add(ifDefinition.Name, ifDefinition);
|
_tagLookup.Add(ifDefinition.Name, ifDefinition);
|
||||||
ElifTagDefinition elifDefinition = new ElifTagDefinition();
|
ElifTagDefinition elifDefinition = new ElifTagDefinition();
|
||||||
_tagLookup.Add(elifDefinition.Name, elifDefinition);
|
_tagLookup.Add(elifDefinition.Name, elifDefinition);
|
||||||
ElseTagDefinition elseDefinition = new ElseTagDefinition();
|
ElseTagDefinition elseDefinition = new ElseTagDefinition();
|
||||||
_tagLookup.Add(elseDefinition.Name, elseDefinition);
|
_tagLookup.Add(elseDefinition.Name, elseDefinition);
|
||||||
EachTagDefinition eachDefinition = new EachTagDefinition();
|
EachTagDefinition eachDefinition = new EachTagDefinition();
|
||||||
_tagLookup.Add(eachDefinition.Name, eachDefinition);
|
_tagLookup.Add(eachDefinition.Name, eachDefinition);
|
||||||
WithTagDefinition withDefinition = new WithTagDefinition();
|
WithTagDefinition withDefinition = new WithTagDefinition();
|
||||||
_tagLookup.Add(withDefinition.Name, withDefinition);
|
_tagLookup.Add(withDefinition.Name, withDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers the given tag definition with the parser.
|
/// Occurs when a placeholder is found in the template.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="definition">The tag definition to register.</param>
|
public event EventHandler<PlaceholderFoundEventArgs> PlaceholderFound;
|
||||||
/// <param name="isTopLevel">Specifies whether the tag is immediately in scope.</param>
|
|
||||||
public void RegisterTag(TagDefinition definition, bool isTopLevel)
|
/// <summary>
|
||||||
{
|
/// Registers the given tag definition with the parser.
|
||||||
if (definition == null)
|
/// </summary>
|
||||||
{
|
/// <param name="definition">The tag definition to register.</param>
|
||||||
throw new ArgumentNullException("definition");
|
/// <param name="isTopLevel">Specifies whether the tag is immediately in scope.</param>
|
||||||
}
|
public void RegisterTag(TagDefinition definition, bool isTopLevel)
|
||||||
if (_tagLookup.ContainsKey(definition.Name))
|
{
|
||||||
{
|
if (definition == null)
|
||||||
string message = String.Format(Resources.DuplicateTagDefinition, definition.Name);
|
{
|
||||||
throw new ArgumentException(message, "definition");
|
throw new ArgumentNullException("definition");
|
||||||
}
|
}
|
||||||
_tagLookup.Add(definition.Name, definition);
|
if (_tagLookup.ContainsKey(definition.Name))
|
||||||
}
|
{
|
||||||
|
string message = String.Format(Resources.DuplicateTagDefinition, definition.Name);
|
||||||
/// <summary>
|
throw new ArgumentException(message, "definition");
|
||||||
/// Builds a text generator based on the given format.
|
}
|
||||||
/// </summary>
|
_tagLookup.Add(definition.Name, definition);
|
||||||
/// <param name="format">The format to parse.</param>
|
}
|
||||||
/// <returns>The text generator.</returns>
|
|
||||||
public Generator Compile(string format)
|
/// <summary>
|
||||||
{
|
/// Builds a text generator based on the given format.
|
||||||
if (format == null)
|
/// </summary>
|
||||||
{
|
/// <param name="format">The format to parse.</param>
|
||||||
throw new ArgumentNullException("format");
|
/// <returns>The text generator.</returns>
|
||||||
}
|
public Generator Compile(string format)
|
||||||
CompoundGenerator generator = new CompoundGenerator(_masterDefinition, new ArgumentCollection());
|
{
|
||||||
Trimmer trimmer = new Trimmer();
|
if (format == null)
|
||||||
int formatIndex = buildCompoundGenerator(_masterDefinition, generator, trimmer, format, 0);
|
{
|
||||||
string trailing = format.Substring(formatIndex);
|
throw new ArgumentNullException("format");
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(trailing, false, false));
|
}
|
||||||
trimmer.Trim();
|
CompoundGenerator generator = new CompoundGenerator(_masterDefinition, new ArgumentCollection());
|
||||||
return new Generator(generator);
|
Trimmer trimmer = new Trimmer();
|
||||||
}
|
int formatIndex = buildCompoundGenerator(_masterDefinition, generator, trimmer, format, 0);
|
||||||
|
string trailing = format.Substring(formatIndex);
|
||||||
private Match findNextTag(TagDefinition definition, string format, int formatIndex)
|
generator.AddStaticGenerators(trimmer.RecordText(trailing, false, false));
|
||||||
{
|
trimmer.Trim();
|
||||||
Regex regex = prepareRegex(definition);
|
return new Generator(generator);
|
||||||
return regex.Match(format, formatIndex);
|
}
|
||||||
}
|
|
||||||
|
private Match findNextTag(TagDefinition definition, string format, int formatIndex)
|
||||||
private Regex prepareRegex(TagDefinition definition)
|
{
|
||||||
{
|
Regex regex = prepareRegex(definition);
|
||||||
Regex regex;
|
return regex.Match(format, formatIndex);
|
||||||
if (!_regexLookup.TryGetValue(definition.Name, out regex))
|
}
|
||||||
{
|
|
||||||
List<string> matches = new List<string>();
|
private Regex prepareRegex(TagDefinition definition)
|
||||||
matches.Add(getKeyRegex());
|
{
|
||||||
matches.Add(getCommentTagRegex());
|
Regex regex;
|
||||||
foreach (string closingTag in definition.ClosingTags)
|
if (!_regexLookup.TryGetValue(definition.Name, out regex))
|
||||||
{
|
{
|
||||||
matches.Add(getClosingTagRegex(closingTag));
|
List<string> matches = new List<string>();
|
||||||
}
|
matches.Add(getKeyRegex());
|
||||||
foreach (TagDefinition globalDefinition in _tagLookup.Values)
|
matches.Add(getCommentTagRegex());
|
||||||
{
|
foreach (string closingTag in definition.ClosingTags)
|
||||||
if (!globalDefinition.IsContextSensitive)
|
{
|
||||||
{
|
matches.Add(getClosingTagRegex(closingTag));
|
||||||
matches.Add(getTagRegex(globalDefinition));
|
}
|
||||||
}
|
foreach (TagDefinition globalDefinition in _tagLookup.Values)
|
||||||
}
|
{
|
||||||
foreach (string childTag in definition.ChildTags)
|
if (!globalDefinition.IsContextSensitive)
|
||||||
{
|
{
|
||||||
TagDefinition childDefinition = _tagLookup[childTag];
|
matches.Add(getTagRegex(globalDefinition));
|
||||||
matches.Add(getTagRegex(childDefinition));
|
}
|
||||||
}
|
}
|
||||||
matches.Add(getUnknownTagRegex());
|
foreach (string childTag in definition.ChildTags)
|
||||||
string match = "{{(" + String.Join("|", matches) + ")}}";
|
{
|
||||||
regex = new Regex(match, RegexOptions.Compiled);
|
TagDefinition childDefinition = _tagLookup[childTag];
|
||||||
_regexLookup.Add(definition.Name, regex);
|
matches.Add(getTagRegex(childDefinition));
|
||||||
}
|
}
|
||||||
return regex;
|
matches.Add(getUnknownTagRegex());
|
||||||
}
|
string match = "{{(" + String.Join("|", matches) + ")}}";
|
||||||
|
regex = new Regex(match, RegexOptions.Compiled);
|
||||||
private static string getClosingTagRegex(string tagName)
|
_regexLookup.Add(definition.Name, regex);
|
||||||
{
|
}
|
||||||
StringBuilder regexBuilder = new StringBuilder();
|
return regex;
|
||||||
regexBuilder.Append(@"(?<close>(/(?<name>");
|
}
|
||||||
regexBuilder.Append(tagName);
|
|
||||||
regexBuilder.Append(@")\s*?))");
|
private static string getClosingTagRegex(string tagName)
|
||||||
return regexBuilder.ToString();
|
{
|
||||||
}
|
StringBuilder regexBuilder = new StringBuilder();
|
||||||
|
regexBuilder.Append(@"(?<close>(/(?<name>");
|
||||||
private static string getCommentTagRegex()
|
regexBuilder.Append(tagName);
|
||||||
{
|
regexBuilder.Append(@")\s*?))");
|
||||||
return @"(?<comment>#!.*?)";
|
return regexBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string getKeyRegex()
|
private static string getCommentTagRegex()
|
||||||
{
|
{
|
||||||
return @"((?<key>" + RegexHelper.CompoundKey + @")(,(?<alignment>(\+|-)?[\d]+))?(:(?<format>.*?))?)";
|
return @"(?<comment>#!.*?)";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string getTagRegex(TagDefinition definition)
|
private static string getKeyRegex()
|
||||||
{
|
{
|
||||||
StringBuilder regexBuilder = new StringBuilder();
|
return @"((?<key>" + RegexHelper.CompoundKey + @")(,(?<alignment>(\+|-)?[\d]+))?(:(?<format>.*?))?)";
|
||||||
regexBuilder.Append(@"(?<open>(#(?<name>");
|
}
|
||||||
regexBuilder.Append(definition.Name);
|
|
||||||
regexBuilder.Append(@")");
|
private static string getTagRegex(TagDefinition definition)
|
||||||
foreach (TagParameter parameter in definition.Parameters)
|
{
|
||||||
{
|
StringBuilder regexBuilder = new StringBuilder();
|
||||||
regexBuilder.Append(@"(\s+?");
|
regexBuilder.Append(@"(?<open>(#(?<name>");
|
||||||
regexBuilder.Append(@"(?<argument>");
|
regexBuilder.Append(definition.Name);
|
||||||
regexBuilder.Append(RegexHelper.CompoundKey);
|
regexBuilder.Append(@")");
|
||||||
regexBuilder.Append(@"))");
|
foreach (TagParameter parameter in definition.Parameters)
|
||||||
if (!parameter.IsRequired)
|
{
|
||||||
{
|
regexBuilder.Append(@"(\s+?");
|
||||||
regexBuilder.Append("?");
|
regexBuilder.Append(@"(?<argument>");
|
||||||
}
|
regexBuilder.Append(RegexHelper.CompoundKey);
|
||||||
}
|
regexBuilder.Append(@"))");
|
||||||
regexBuilder.Append(@"\s*?))");
|
if (!parameter.IsRequired)
|
||||||
return regexBuilder.ToString();
|
{
|
||||||
}
|
regexBuilder.Append("?");
|
||||||
|
}
|
||||||
private string getUnknownTagRegex()
|
}
|
||||||
{
|
regexBuilder.Append(@"\s*?))");
|
||||||
return @"(?<unknown>(#.*?))";
|
return regexBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int buildCompoundGenerator(
|
private string getUnknownTagRegex()
|
||||||
TagDefinition tagDefinition,
|
{
|
||||||
CompoundGenerator generator,
|
return @"(?<unknown>(#.*?))";
|
||||||
Trimmer trimmer,
|
}
|
||||||
string format, int formatIndex)
|
|
||||||
{
|
private int buildCompoundGenerator(
|
||||||
while (true)
|
TagDefinition tagDefinition,
|
||||||
{
|
CompoundGenerator generator,
|
||||||
Match match = findNextTag(tagDefinition, format, formatIndex);
|
Trimmer trimmer,
|
||||||
|
string format, int formatIndex)
|
||||||
if (!match.Success)
|
{
|
||||||
{
|
while (true)
|
||||||
if (tagDefinition.ClosingTags.Any())
|
{
|
||||||
{
|
Match match = findNextTag(tagDefinition, format, formatIndex);
|
||||||
string message = String.Format(Resources.MissingClosingTag, tagDefinition.Name);
|
|
||||||
throw new FormatException(message);
|
if (!match.Success)
|
||||||
}
|
{
|
||||||
break;
|
if (tagDefinition.ClosingTags.Any())
|
||||||
}
|
{
|
||||||
|
string message = String.Format(Resources.MissingClosingTag, tagDefinition.Name);
|
||||||
string leading = format.Substring(formatIndex, match.Index - formatIndex);
|
throw new FormatException(message);
|
||||||
|
}
|
||||||
if (match.Groups["key"].Success)
|
break;
|
||||||
{
|
}
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(leading, true, true));
|
|
||||||
formatIndex = match.Index + match.Length;
|
string leading = format.Substring(formatIndex, match.Index - formatIndex);
|
||||||
string key = match.Groups["key"].Value;
|
|
||||||
string alignment = match.Groups["alignment"].Value;
|
if (match.Groups["key"].Success)
|
||||||
string formatting = match.Groups["format"].Value;
|
{
|
||||||
KeyGenerator keyGenerator = new KeyGenerator(key, alignment, formatting);
|
generator.AddStaticGenerators(trimmer.RecordText(leading, true, true));
|
||||||
generator.AddGenerator(keyGenerator);
|
formatIndex = match.Index + match.Length;
|
||||||
}
|
string key = match.Groups["key"].Value;
|
||||||
else if (match.Groups["open"].Success)
|
string alignment = match.Groups["alignment"].Value;
|
||||||
{
|
string formatting = match.Groups["format"].Value;
|
||||||
formatIndex = match.Index + match.Length;
|
PlaceholderFoundEventArgs args = new PlaceholderFoundEventArgs(key, alignment, formatting);
|
||||||
string tagName = match.Groups["name"].Value;
|
if (PlaceholderFound != null)
|
||||||
TagDefinition nextDefinition = _tagLookup[tagName];
|
{
|
||||||
if (nextDefinition == null)
|
PlaceholderFound(this, args);
|
||||||
{
|
}
|
||||||
string message = String.Format(Resources.UnknownTag, tagName);
|
KeyGenerator keyGenerator = new KeyGenerator(args.Key, args.Alignment, args.Formatting);
|
||||||
throw new FormatException(message);
|
generator.AddGenerator(keyGenerator);
|
||||||
}
|
}
|
||||||
if (nextDefinition.HasContent)
|
else if (match.Groups["open"].Success)
|
||||||
{
|
{
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
formatIndex = match.Index + match.Length;
|
||||||
ArgumentCollection arguments = getArguments(nextDefinition, match);
|
string tagName = match.Groups["name"].Value;
|
||||||
CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments);
|
TagDefinition nextDefinition = _tagLookup[tagName];
|
||||||
formatIndex = buildCompoundGenerator(nextDefinition, compoundGenerator, trimmer, format, formatIndex);
|
if (nextDefinition == null)
|
||||||
generator.AddGenerator(nextDefinition, compoundGenerator);
|
{
|
||||||
}
|
string message = String.Format(Resources.UnknownTag, tagName);
|
||||||
else
|
throw new FormatException(message);
|
||||||
{
|
}
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(leading, true, true));
|
if (nextDefinition.HasContent)
|
||||||
Match nextMatch = findNextTag(nextDefinition, format, formatIndex);
|
{
|
||||||
ArgumentCollection arguments = getArguments(nextDefinition, nextMatch);
|
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
||||||
InlineGenerator inlineGenerator = new InlineGenerator(nextDefinition, arguments);
|
ArgumentCollection arguments = getArguments(nextDefinition, match);
|
||||||
generator.AddGenerator(inlineGenerator);
|
CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments);
|
||||||
}
|
formatIndex = buildCompoundGenerator(nextDefinition, compoundGenerator, trimmer, format, formatIndex);
|
||||||
}
|
generator.AddGenerator(nextDefinition, compoundGenerator);
|
||||||
else if (match.Groups["close"].Success)
|
}
|
||||||
{
|
else
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
{
|
||||||
string tagName = match.Groups["name"].Value;
|
generator.AddStaticGenerators(trimmer.RecordText(leading, true, true));
|
||||||
TagDefinition nextDefinition = _tagLookup[tagName];
|
Match nextMatch = findNextTag(nextDefinition, format, formatIndex);
|
||||||
formatIndex = match.Index;
|
ArgumentCollection arguments = getArguments(nextDefinition, nextMatch);
|
||||||
if (tagName == tagDefinition.Name)
|
InlineGenerator inlineGenerator = new InlineGenerator(nextDefinition, arguments);
|
||||||
{
|
generator.AddGenerator(inlineGenerator);
|
||||||
formatIndex += match.Length;
|
}
|
||||||
}
|
}
|
||||||
break;
|
else if (match.Groups["close"].Success)
|
||||||
}
|
{
|
||||||
else if (match.Groups["comment"].Success)
|
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
||||||
{
|
string tagName = match.Groups["name"].Value;
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
TagDefinition nextDefinition = _tagLookup[tagName];
|
||||||
formatIndex = match.Index + match.Length;
|
formatIndex = match.Index;
|
||||||
}
|
if (tagName == tagDefinition.Name)
|
||||||
else if (match.Groups["unknown"].Success)
|
{
|
||||||
{
|
formatIndex += match.Length;
|
||||||
throw new FormatException(Resources.UnknownTag);
|
}
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
return formatIndex;
|
else if (match.Groups["comment"].Success)
|
||||||
}
|
{
|
||||||
|
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
||||||
private static ArgumentCollection getArguments(TagDefinition definition, Match match)
|
formatIndex = match.Index + match.Length;
|
||||||
{
|
}
|
||||||
ArgumentCollection collection = new ArgumentCollection();
|
else if (match.Groups["unknown"].Success)
|
||||||
List<Capture> captures = match.Groups["argument"].Captures.Cast<Capture>().ToList();
|
{
|
||||||
List<TagParameter> parameters = definition.Parameters.ToList();
|
throw new FormatException(Resources.UnknownTag);
|
||||||
if (captures.Count > parameters.Count)
|
}
|
||||||
{
|
}
|
||||||
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
return formatIndex;
|
||||||
throw new FormatException(message);
|
}
|
||||||
}
|
|
||||||
if (captures.Count < parameters.Count)
|
private static ArgumentCollection getArguments(TagDefinition definition, Match match)
|
||||||
{
|
{
|
||||||
captures.AddRange(Enumerable.Repeat((Capture)null, parameters.Count - captures.Count));
|
ArgumentCollection collection = new ArgumentCollection();
|
||||||
}
|
List<Capture> captures = match.Groups["argument"].Captures.Cast<Capture>().ToList();
|
||||||
foreach (var pair in parameters.Zip(captures, (p, c) => new { Capture = c, Parameter = p }))
|
List<TagParameter> parameters = definition.Parameters.ToList();
|
||||||
{
|
if (captures.Count > parameters.Count)
|
||||||
if (pair.Capture == null)
|
{
|
||||||
{
|
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
||||||
if (pair.Parameter.IsRequired)
|
throw new FormatException(message);
|
||||||
{
|
}
|
||||||
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
if (captures.Count < parameters.Count)
|
||||||
throw new FormatException(message);
|
{
|
||||||
}
|
captures.AddRange(Enumerable.Repeat((Capture)null, parameters.Count - captures.Count));
|
||||||
collection.AddArgument(pair.Parameter, null);
|
}
|
||||||
}
|
foreach (var pair in parameters.Zip(captures, (p, c) => new { Capture = c, Parameter = p }))
|
||||||
else
|
{
|
||||||
{
|
if (pair.Capture == null)
|
||||||
collection.AddArgument(pair.Parameter, pair.Capture.Value);
|
{
|
||||||
}
|
if (pair.Parameter.IsRequired)
|
||||||
}
|
{
|
||||||
return collection;
|
string message = String.Format(Resources.WrongNumberOfArguments, definition.Name);
|
||||||
}
|
throw new FormatException(message);
|
||||||
}
|
}
|
||||||
}
|
collection.AddArgument(pair.Parameter, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collection.AddArgument(pair.Parameter, pair.Capture.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using mustache.Properties;
|
||||||
|
|
||||||
|
namespace mustache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the information descibing a key that is found in a template.
|
||||||
|
/// </summary>
|
||||||
|
public class PlaceholderFoundEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of a PlaceholderFoundEventArgs.
|
||||||
|
/// </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>
|
||||||
|
internal PlaceholderFoundEventArgs(string key, string alignment, string formatting)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Alignment = alignment;
|
||||||
|
Formatting = formatting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the key that was found.
|
||||||
|
/// </summary>
|
||||||
|
public string Key { 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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,6 @@ using System.Runtime.CompilerServices;
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.0.5.0")]
|
[assembly: AssemblyVersion("0.0.6.0")]
|
||||||
[assembly: AssemblyFileVersion("0.0.4.0")]
|
[assembly: AssemblyFileVersion("0.0.6.0")]
|
||||||
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
|
@ -1,25 +1,29 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace mustache
|
namespace mustache
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides utility methods that require regular expressions.
|
/// Provides utility methods that require regular expressions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class RegexHelper
|
public static class RegexHelper
|
||||||
{
|
{
|
||||||
private const string Key = @"[_\w][_\w\d]*";
|
private const string Key = @"[_\w][_\w\d]*";
|
||||||
internal const string CompoundKey = Key + @"(\." + Key + ")*";
|
internal const string CompoundKey = Key + @"(\." + Key + ")*";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the given name is a legal identifier.
|
/// Determines whether the given name is a legal identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name to check.</param>
|
/// <param name="name">The name to check.</param>
|
||||||
/// <returns>True if the name is a legal identifier; otherwise, false.</returns>
|
/// <returns>True if the name is a legal identifier; otherwise, false.</returns>
|
||||||
public static bool IsValidIdentifier(string name)
|
public static bool IsValidIdentifier(string name)
|
||||||
{
|
{
|
||||||
Regex regex = new Regex("^" + Key + "$");
|
if (name == null)
|
||||||
return regex.IsMatch(name);
|
{
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
}
|
Regex regex = new Regex("^" + Key + "$");
|
||||||
|
return regex.IsMatch(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
<Compile Include="IfTagDefinition.cs" />
|
<Compile Include="IfTagDefinition.cs" />
|
||||||
<Compile Include="IGenerator.cs" />
|
<Compile Include="IGenerator.cs" />
|
||||||
<Compile Include="InlineGenerator.cs" />
|
<Compile Include="InlineGenerator.cs" />
|
||||||
|
<Compile Include="PlaceholderFoundEventArgs.cs" />
|
||||||
<Compile Include="KeyGenerator.cs" />
|
<Compile Include="KeyGenerator.cs" />
|
||||||
<Compile Include="MasterTagDefinition.cs" />
|
<Compile Include="MasterTagDefinition.cs" />
|
||||||
<Compile Include="MissingKeyEventArgs.cs" />
|
<Compile Include="MissingKeyEventArgs.cs" />
|
||||||
|
|
Loading…
Reference in New Issue