Pop Context When Exiting Tag
I was not removing context when I was leaving a tag. This caused the context to grow indefinitely, which is not a valid representation of where the placeholder was located in the template.
This commit is contained in:
parent
42463a888f
commit
11b73b696e
|
@ -362,10 +362,34 @@ Content";
|
||||||
|
|
||||||
Assert.IsNotNull(context, "The context was not set.");
|
Assert.IsNotNull(context, "The context was not set.");
|
||||||
Assert.AreEqual(2, context.Length, "The context did not contain the right number of items.");
|
Assert.AreEqual(2, context.Length, "The context did not contain the right number of items.");
|
||||||
Assert.AreEqual(String.Empty, context[0].Tag.Name, "The top-most context had the wrong tag type.");
|
|
||||||
Assert.AreEqual("this", context[0].Argument, "The top-level argument should always be 'this'.");
|
Assert.AreEqual(String.Empty, context[0].TagName, "The top-most context had the wrong tag type.");
|
||||||
Assert.AreEqual("with", context[1].Tag.Name, "The inner context should have been a 'with' tag.");
|
Assert.AreEqual("with", context[1].TagName, "The bottom context had the wrong tag type.");
|
||||||
Assert.AreEqual("Address", context[1].Argument, "The inner context argument was wrong.");
|
|
||||||
|
Assert.AreEqual(0, context[0].Parameters.Length, "The top-most context had the wrong number of parameters.");
|
||||||
|
Assert.AreEqual(1, context[1].Parameters.Length, "The bottom context had the wrong number of parameters.");
|
||||||
|
Assert.AreEqual("Address", context[1].Parameters[0].Argument, "The bottom context had the wrong argument.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// I was leaving behind context even after reaching a closing tag. We need to make sure
|
||||||
|
/// that context is like a call stack and that it is cleaned up after leaving the context.
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TestCompile_ExitContext_RemoveContext()
|
||||||
|
{
|
||||||
|
FormatCompiler compiler = new FormatCompiler();
|
||||||
|
Context[] context = null;
|
||||||
|
compiler.PlaceholderFound += (o, e) =>
|
||||||
|
{
|
||||||
|
context = e.Context;
|
||||||
|
};
|
||||||
|
compiler.Compile(@"{{#with Address}}{{/with}}{{FirstName}}");
|
||||||
|
|
||||||
|
Assert.IsNotNull(context, "The context was not set.");
|
||||||
|
Assert.AreEqual(1, context.Length, "The context did not contain the right number of items.");
|
||||||
|
|
||||||
|
Assert.AreEqual(String.Empty, context[0].TagName, "The top-most context had the wrong tag type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -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.7.0")]
|
[assembly: AssemblyVersion("0.0.7.1")]
|
||||||
[assembly: AssemblyFileVersion("0.0.7.0")]
|
[assembly: AssemblyFileVersion("0.0.7.1")]
|
||||||
|
|
|
@ -26,20 +26,6 @@ namespace mustache
|
||||||
_primaryGenerators = new LinkedList<IGenerator>();
|
_primaryGenerators = new LinkedList<IGenerator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the argument that will act as the context for the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The argument that will act as the context for the content.</returns>
|
|
||||||
public string GetContextArgument()
|
|
||||||
{
|
|
||||||
TagParameter parameter = _definition.GetChildContextParameter();
|
|
||||||
if (parameter == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return _arguments.GetKey(parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the given generator.
|
/// Adds the given generator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -90,12 +90,12 @@ namespace mustache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameter that is used to create a new child context.
|
/// Gets the parameters that are used to create a new child context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The parameter that is used to create a new child context.</returns>
|
/// <returns>The parameters that are used to create a new child context.</returns>
|
||||||
public override TagParameter GetChildContextParameter()
|
public override IEnumerable<TagParameter> GetChildContextParameters()
|
||||||
{
|
{
|
||||||
return null;
|
return new TagParameter[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,22 +10,22 @@ namespace mustache
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of a Context.
|
/// Initializes a new instance of a Context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="definition">The definition of tag that created the context.</param>
|
/// <param name="tagName">The name of the tag that created the context.</param>
|
||||||
/// <param name="argument">The argument used to create the context.</param>
|
/// <param name="argument">The argument used to create the context.</param>
|
||||||
internal Context(TagDefinition definition, string argument)
|
internal Context(string tagName, ContextParameter[] parameters)
|
||||||
{
|
{
|
||||||
Tag = definition;
|
TagName = tagName;
|
||||||
Argument = argument;
|
Parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the tag that created the context.
|
/// Gets the tag that created the context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TagDefinition Tag { get; private set; }
|
public string TagName { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the argument used to create the context.
|
/// Gets the argument used to create the context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Argument { get; private set; }
|
public ContextParameter[] Parameters { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mustache
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds information describing a parameter that creates a new context.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ContextParameter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of a ContextParameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">The parameter that is used to create a new context.</param>
|
||||||
|
/// <param name="argument">The key whose corresponding value will be used to create the context.</param>
|
||||||
|
internal ContextParameter(string parameter, string argument)
|
||||||
|
{
|
||||||
|
Parameter = parameter;
|
||||||
|
Argument = argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parameter that is used to create a new context.
|
||||||
|
/// </summary>
|
||||||
|
public string Parameter { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the key whose corresponding value will be used to create the context.
|
||||||
|
/// </summary>
|
||||||
|
public string Argument { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -70,12 +70,12 @@ namespace mustache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameter that is used to create a new child context.
|
/// Gets the parameters that are used to create a new child context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The parameter that is used to create a new child context.</returns>
|
/// <returns>The parameters that are used to create a new child context.</returns>
|
||||||
public override TagParameter GetChildContextParameter()
|
public override IEnumerable<TagParameter> GetChildContextParameters()
|
||||||
{
|
{
|
||||||
return collection;
|
return new TagParameter[] { collection };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,12 @@ namespace mustache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameter that is used to create a new child context.
|
/// Gets the parameters that are used to create a new child context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The parameter that is used to create a new child context.</returns>
|
/// <returns>The parameters that are used to create a new child context.</returns>
|
||||||
public override TagParameter GetChildContextParameter()
|
public override IEnumerable<TagParameter> GetChildContextParameters()
|
||||||
{
|
{
|
||||||
return null;
|
return new TagParameter[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace mustache
|
||||||
}
|
}
|
||||||
CompoundGenerator generator = new CompoundGenerator(_masterDefinition, new ArgumentCollection());
|
CompoundGenerator generator = new CompoundGenerator(_masterDefinition, new ArgumentCollection());
|
||||||
Trimmer trimmer = new Trimmer();
|
Trimmer trimmer = new Trimmer();
|
||||||
List<Context> context = new List<Context>() { new Context(_masterDefinition, "this") };
|
List<Context> context = new List<Context>() { new Context(_masterDefinition.Name, new ContextParameter[0]) };
|
||||||
int formatIndex = buildCompoundGenerator(_masterDefinition, context, generator, trimmer, format, 0);
|
int formatIndex = buildCompoundGenerator(_masterDefinition, context, generator, trimmer, format, 0);
|
||||||
string trailing = format.Substring(formatIndex);
|
string trailing = format.Substring(formatIndex);
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(trailing, false, false));
|
generator.AddStaticGenerators(trimmer.RecordText(trailing, false, false));
|
||||||
|
@ -218,13 +218,19 @@ namespace mustache
|
||||||
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
generator.AddStaticGenerators(trimmer.RecordText(leading, true, false));
|
||||||
ArgumentCollection arguments = getArguments(nextDefinition, match);
|
ArgumentCollection arguments = getArguments(nextDefinition, match);
|
||||||
CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments);
|
CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments);
|
||||||
string newContext = compoundGenerator.GetContextArgument();
|
IEnumerable<TagParameter> contextParameters = nextDefinition.GetChildContextParameters();
|
||||||
if (newContext != null)
|
bool hasContext = contextParameters.Any();
|
||||||
|
if (hasContext)
|
||||||
{
|
{
|
||||||
context.Add(new Context(nextDefinition, newContext));
|
ContextParameter[] parameters = contextParameters.Select(p => new ContextParameter(p.Name, arguments.GetKey(p))).ToArray();
|
||||||
|
context.Add(new Context(nextDefinition.Name, parameters));
|
||||||
}
|
}
|
||||||
formatIndex = buildCompoundGenerator(nextDefinition, context, compoundGenerator, trimmer, format, formatIndex);
|
formatIndex = buildCompoundGenerator(nextDefinition, context, compoundGenerator, trimmer, format, formatIndex);
|
||||||
generator.AddGenerator(nextDefinition, compoundGenerator);
|
generator.AddGenerator(nextDefinition, compoundGenerator);
|
||||||
|
if (hasContext)
|
||||||
|
{
|
||||||
|
context.RemoveAt(context.Count - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,12 +38,12 @@ namespace mustache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameter that is used to create a child context.
|
/// Gets the parameters that are used to create a child context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The parameter that is used to create a child context.</returns>
|
/// <returns>The parameters that are used to create a child context.</returns>
|
||||||
public override TagParameter GetChildContextParameter()
|
public override IEnumerable<TagParameter> GetChildContextParameters()
|
||||||
{
|
{
|
||||||
return null;
|
return new TagParameter[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,12 @@ namespace mustache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameter that is used to create a new child context.
|
/// Gets the parameters that are used to create a new child context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The parameter that is used to create a new child context.</returns>
|
/// <returns>The parameters that are used to create a new child context.</returns>
|
||||||
public override TagParameter GetChildContextParameter()
|
public override IEnumerable<TagParameter> GetChildContextParameters()
|
||||||
{
|
{
|
||||||
return null;
|
return new TagParameter[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.7.0")]
|
[assembly: AssemblyVersion("0.0.7.1")]
|
||||||
[assembly: AssemblyFileVersion("0.0.7.0")]
|
[assembly: AssemblyFileVersion("0.0.7.1")]
|
||||||
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
|
@ -133,7 +133,7 @@ namespace mustache
|
||||||
/// Gets the parameter that will be used to create a new child scope.
|
/// Gets the parameter that will be used to create a new child scope.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The parameter that will be used to create a new child scope -or- null if no new scope is created.</returns>
|
/// <returns>The parameter that will be used to create a new child scope -or- null if no new scope is created.</returns>
|
||||||
public abstract TagParameter GetChildContextParameter();
|
public abstract IEnumerable<TagParameter> GetChildContextParameters();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the context to use when building the inner text of the tag.
|
/// Gets the context to use when building the inner text of the tag.
|
||||||
|
|
|
@ -38,12 +38,12 @@ namespace mustache
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the parameter that is used to create a new child context.
|
/// Gets the parameters that are used to create a new child context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The parameter that is used to create a new child context.</returns>
|
/// <returns>The parameters that are used to create a new child context.</returns>
|
||||||
public override TagParameter GetChildContextParameter()
|
public override IEnumerable<TagParameter> GetChildContextParameters()
|
||||||
{
|
{
|
||||||
return context;
|
return new TagParameter[] { context };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
<Compile Include="ConditionTagDefinition.cs" />
|
<Compile Include="ConditionTagDefinition.cs" />
|
||||||
<Compile Include="ContentTagDefinition.cs" />
|
<Compile Include="ContentTagDefinition.cs" />
|
||||||
<Compile Include="Context.cs" />
|
<Compile Include="Context.cs" />
|
||||||
|
<Compile Include="ContextParameter.cs" />
|
||||||
<Compile Include="KeyFoundEventArgs.cs" />
|
<Compile Include="KeyFoundEventArgs.cs" />
|
||||||
<Compile Include="InlineTagDefinition.cs" />
|
<Compile Include="InlineTagDefinition.cs" />
|
||||||
<Compile Include="EachTagDefinition.cs" />
|
<Compile Include="EachTagDefinition.cs" />
|
||||||
|
|
Loading…
Reference in New Issue