diff --git a/mustache-sharp.test/FormatCompilerTester.cs b/mustache-sharp.test/FormatCompilerTester.cs index 148ba2b..a05cb60 100644 --- a/mustache-sharp.test/FormatCompilerTester.cs +++ b/mustache-sharp.test/FormatCompilerTester.cs @@ -362,10 +362,34 @@ Content"; 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(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("with", context[1].Tag.Name, "The inner context should have been a 'with' tag."); - Assert.AreEqual("Address", context[1].Argument, "The inner context argument was wrong."); + + Assert.AreEqual(String.Empty, context[0].TagName, "The top-most context had the wrong tag type."); + Assert.AreEqual("with", context[1].TagName, "The bottom context had the wrong tag type."); + + 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."); + } + + /// + /// 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. + /// + [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 diff --git a/mustache-sharp.test/Properties/AssemblyInfo.cs b/mustache-sharp.test/Properties/AssemblyInfo.cs index 8a79168..ee7d29c 100644 --- a/mustache-sharp.test/Properties/AssemblyInfo.cs +++ b/mustache-sharp.test/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("0.0.7.0")] -[assembly: AssemblyFileVersion("0.0.7.0")] +[assembly: AssemblyVersion("0.0.7.1")] +[assembly: AssemblyFileVersion("0.0.7.1")] diff --git a/mustache-sharp/CompoundGenerator.cs b/mustache-sharp/CompoundGenerator.cs index c01add3..a6fb146 100644 --- a/mustache-sharp/CompoundGenerator.cs +++ b/mustache-sharp/CompoundGenerator.cs @@ -26,20 +26,6 @@ namespace mustache _primaryGenerators = new LinkedList(); } - /// - /// Gets the argument that will act as the context for the content. - /// - /// The argument that will act as the context for the content. - public string GetContextArgument() - { - TagParameter parameter = _definition.GetChildContextParameter(); - if (parameter == null) - { - return null; - } - return _arguments.GetKey(parameter); - } - /// /// Adds the given generator. /// diff --git a/mustache-sharp/ConditionTagDefinition.cs b/mustache-sharp/ConditionTagDefinition.cs index 6e08a54..14e1d82 100644 --- a/mustache-sharp/ConditionTagDefinition.cs +++ b/mustache-sharp/ConditionTagDefinition.cs @@ -90,12 +90,12 @@ namespace mustache } /// - /// Gets the parameter that is used to create a new child context. + /// Gets the parameters that are used to create a new child context. /// - /// The parameter that is used to create a new child context. - public override TagParameter GetChildContextParameter() + /// The parameters that are used to create a new child context. + public override IEnumerable GetChildContextParameters() { - return null; + return new TagParameter[0]; } } } diff --git a/mustache-sharp/Context.cs b/mustache-sharp/Context.cs index b9d97b5..6e754b6 100644 --- a/mustache-sharp/Context.cs +++ b/mustache-sharp/Context.cs @@ -10,22 +10,22 @@ namespace mustache /// /// Initializes a new instance of a Context. /// - /// The definition of tag that created the context. + /// The name of the tag that created the context. /// The argument used to create the context. - internal Context(TagDefinition definition, string argument) + internal Context(string tagName, ContextParameter[] parameters) { - Tag = definition; - Argument = argument; + TagName = tagName; + Parameters = parameters; } /// /// Gets the tag that created the context. /// - public TagDefinition Tag { get; private set; } + public string TagName { get; private set; } /// /// Gets the argument used to create the context. /// - public string Argument { get; private set; } + public ContextParameter[] Parameters { get; private set; } } } diff --git a/mustache-sharp/ContextParameter.cs b/mustache-sharp/ContextParameter.cs new file mode 100644 index 0000000..2cc19b3 --- /dev/null +++ b/mustache-sharp/ContextParameter.cs @@ -0,0 +1,31 @@ +using System; + +namespace mustache +{ + /// + /// Holds information describing a parameter that creates a new context. + /// + public sealed class ContextParameter + { + /// + /// Initializes a new instance of a ContextParameter. + /// + /// The parameter that is used to create a new context. + /// The key whose corresponding value will be used to create the context. + internal ContextParameter(string parameter, string argument) + { + Parameter = parameter; + Argument = argument; + } + + /// + /// Gets the parameter that is used to create a new context. + /// + public string Parameter { get; private set; } + + /// + /// Gets the key whose corresponding value will be used to create the context. + /// + public string Argument { get; private set; } + } +} diff --git a/mustache-sharp/EachTagDefinition.cs b/mustache-sharp/EachTagDefinition.cs index 05c512d..3d798d7 100644 --- a/mustache-sharp/EachTagDefinition.cs +++ b/mustache-sharp/EachTagDefinition.cs @@ -70,12 +70,12 @@ namespace mustache } /// - /// Gets the parameter that is used to create a new child context. + /// Gets the parameters that are used to create a new child context. /// - /// The parameter that is used to create a new child context. - public override TagParameter GetChildContextParameter() + /// The parameters that are used to create a new child context. + public override IEnumerable GetChildContextParameters() { - return collection; + return new TagParameter[] { collection }; } } } diff --git a/mustache-sharp/ElseTagDefinition.cs b/mustache-sharp/ElseTagDefinition.cs index 35a0868..08f5aff 100644 --- a/mustache-sharp/ElseTagDefinition.cs +++ b/mustache-sharp/ElseTagDefinition.cs @@ -33,12 +33,12 @@ namespace mustache } /// - /// Gets the parameter that is used to create a new child context. + /// Gets the parameters that are used to create a new child context. /// - /// The parameter that is used to create a new child context. - public override TagParameter GetChildContextParameter() + /// The parameters that are used to create a new child context. + public override IEnumerable GetChildContextParameters() { - return null; + return new TagParameter[0]; } } } diff --git a/mustache-sharp/FormatCompiler.cs b/mustache-sharp/FormatCompiler.cs index 4910c00..bf99be4 100644 --- a/mustache-sharp/FormatCompiler.cs +++ b/mustache-sharp/FormatCompiler.cs @@ -74,7 +74,7 @@ namespace mustache } CompoundGenerator generator = new CompoundGenerator(_masterDefinition, new ArgumentCollection()); Trimmer trimmer = new Trimmer(); - List context = new List() { new Context(_masterDefinition, "this") }; + List context = new List() { new Context(_masterDefinition.Name, new ContextParameter[0]) }; int formatIndex = buildCompoundGenerator(_masterDefinition, context, generator, trimmer, format, 0); string trailing = format.Substring(formatIndex); generator.AddStaticGenerators(trimmer.RecordText(trailing, false, false)); @@ -218,13 +218,19 @@ namespace mustache generator.AddStaticGenerators(trimmer.RecordText(leading, true, false)); ArgumentCollection arguments = getArguments(nextDefinition, match); CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments); - string newContext = compoundGenerator.GetContextArgument(); - if (newContext != null) + IEnumerable contextParameters = nextDefinition.GetChildContextParameters(); + 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); generator.AddGenerator(nextDefinition, compoundGenerator); + if (hasContext) + { + context.RemoveAt(context.Count - 1); + } } else { diff --git a/mustache-sharp/InlineTagDefinition.cs b/mustache-sharp/InlineTagDefinition.cs index 264e35e..b658b51 100644 --- a/mustache-sharp/InlineTagDefinition.cs +++ b/mustache-sharp/InlineTagDefinition.cs @@ -38,12 +38,12 @@ namespace mustache } /// - /// Gets the parameter that is used to create a child context. + /// Gets the parameters that are used to create a child context. /// - /// The parameter that is used to create a child context. - public override TagParameter GetChildContextParameter() + /// The parameters that are used to create a child context. + public override IEnumerable GetChildContextParameters() { - return null; + return new TagParameter[0]; } } } diff --git a/mustache-sharp/MasterTagDefinition.cs b/mustache-sharp/MasterTagDefinition.cs index e55146e..b733def 100644 --- a/mustache-sharp/MasterTagDefinition.cs +++ b/mustache-sharp/MasterTagDefinition.cs @@ -34,12 +34,12 @@ namespace mustache } /// - /// Gets the parameter that is used to create a new child context. + /// Gets the parameters that are used to create a new child context. /// - /// The parameter that is used to create a new child context. - public override TagParameter GetChildContextParameter() + /// The parameters that are used to create a new child context. + public override IEnumerable GetChildContextParameters() { - return null; + return new TagParameter[0]; } } } diff --git a/mustache-sharp/Properties/AssemblyInfo.cs b/mustache-sharp/Properties/AssemblyInfo.cs index 1103a73..c2029f3 100644 --- a/mustache-sharp/Properties/AssemblyInfo.cs +++ b/mustache-sharp/Properties/AssemblyInfo.cs @@ -34,6 +34,6 @@ using System.Runtime.CompilerServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.0.7.0")] -[assembly: AssemblyFileVersion("0.0.7.0")] +[assembly: AssemblyVersion("0.0.7.1")] +[assembly: AssemblyFileVersion("0.0.7.1")] [assembly: InternalsVisibleTo("mustache-sharp.test")] \ No newline at end of file diff --git a/mustache-sharp/TagDefinition.cs b/mustache-sharp/TagDefinition.cs index 89f56a0..45fe938 100644 --- a/mustache-sharp/TagDefinition.cs +++ b/mustache-sharp/TagDefinition.cs @@ -133,7 +133,7 @@ namespace mustache /// Gets the parameter that will be used to create a new child scope. /// /// The parameter that will be used to create a new child scope -or- null if no new scope is created. - public abstract TagParameter GetChildContextParameter(); + public abstract IEnumerable GetChildContextParameters(); /// /// Gets the context to use when building the inner text of the tag. diff --git a/mustache-sharp/WithGenerator.cs b/mustache-sharp/WithGenerator.cs index 6525f57..c36131a 100644 --- a/mustache-sharp/WithGenerator.cs +++ b/mustache-sharp/WithGenerator.cs @@ -38,12 +38,12 @@ namespace mustache } /// - /// Gets the parameter that is used to create a new child context. + /// Gets the parameters that are used to create a new child context. /// - /// The parameter that is used to create a new child context. - public override TagParameter GetChildContextParameter() + /// The parameters that are used to create a new child context. + public override IEnumerable GetChildContextParameters() { - return context; + return new TagParameter[] { context }; } /// diff --git a/mustache-sharp/mustache-sharp.csproj b/mustache-sharp/mustache-sharp.csproj index fefc132..3dee76a 100644 --- a/mustache-sharp/mustache-sharp.csproj +++ b/mustache-sharp/mustache-sharp.csproj @@ -39,6 +39,7 @@ +