diff --git a/Fluid.Tests/TemplateContextTests.cs b/Fluid.Tests/TemplateContextTests.cs index 1ffb9855..27c58957 100644 --- a/Fluid.Tests/TemplateContextTests.cs +++ b/Fluid.Tests/TemplateContextTests.cs @@ -180,6 +180,18 @@ public void ShouldUseTemplateOptionsStringComparer() Assert.Equal("insert", context.GetValue("pageState").ToStringValue()); } + [Fact] + public void ShouldUseTemplateOptionsStringComparerWithCaseSensitive() + { + var options = new TemplateOptions { ModelNamesComparer = StringComparer.Ordinal }; + var context = new TemplateContext(options); + context.SetValue("case", "lower"); + context.SetValue("CASE", "upper"); + context.SetValue("Case", "mixed"); + + Assert.Equal("lowerupper", context.GetValue("case").ToStringValue() + context.GetValue("CASE").ToStringValue()); + } + private class TestClass { public string Name { get; set; } diff --git a/Fluid/Scope.cs b/Fluid/Scope.cs index 662be0ee..97d2ce81 100644 --- a/Fluid/Scope.cs +++ b/Fluid/Scope.cs @@ -1,5 +1,5 @@ -using System.Runtime.CompilerServices; using Fluid.Values; +using System.Runtime.CompilerServices; namespace Fluid { @@ -7,27 +7,28 @@ public sealed class Scope { private Dictionary _properties; private readonly bool _forLoopScope; + private readonly StringComparer _stringComparer; - public Scope() : this(null) + public Scope() : this(null, false, null) { } - public Scope(Scope parent) + public Scope(Scope parent) : this(parent, false, null) { - Parent = parent; } - public Scope(Scope parent, bool forLoopScope) + public Scope(Scope parent, bool forLoopScope, StringComparer stringComparer = null) { if (forLoopScope && parent == null) ExceptionHelper.ThrowArgumentNullException(nameof(parent)); + // For loops are also ordinal by default + _stringComparer = stringComparer ?? StringComparer.Ordinal; + Parent = parent; + // A ForLoop scope reads and writes its values in the parent scope. // Internal accessors to the inner properties grant access to the local properties. _forLoopScope = forLoopScope; - - // ForLoop scopes are ordinal since the properties are keywords: "forloop" - _properties = new Dictionary(StringComparer.OrdinalIgnoreCase); } /// @@ -114,7 +115,7 @@ public void SetValue(string name, FluidValue value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetOwnValue(string name, FluidValue value) { - _properties ??= new Dictionary(Parent?._properties?.Comparer ?? TemplateOptions.Default.ModelNamesComparer); + _properties ??= new Dictionary(Parent?._properties?.Comparer ?? _stringComparer); _properties[name] = value ?? NilValue.Instance; } @@ -137,4 +138,4 @@ public void CopyTo(Scope scope) } } } -} \ No newline at end of file +} diff --git a/Fluid/TemplateContext.cs b/Fluid/TemplateContext.cs index c9209c41..dd7d0e32 100644 --- a/Fluid/TemplateContext.cs +++ b/Fluid/TemplateContext.cs @@ -47,8 +47,10 @@ public TemplateContext(object model, TemplateOptions options, bool allowModelMem /// An optional instance used when comparing model names. public TemplateContext(TemplateOptions options, StringComparer modelNamesComparer = null) { + modelNamesComparer ??= options.ModelNamesComparer; + Options = options; - LocalScope = new Scope(options.Scope); + LocalScope = new Scope(options.Scope, forLoopScope: false, modelNamesComparer); RootScope = LocalScope; CultureInfo = options.CultureInfo; TimeZone = options.TimeZone; @@ -56,7 +58,7 @@ public TemplateContext(TemplateOptions options, StringComparer modelNamesCompare Assigned = options.Assigned; Now = options.Now; MaxSteps = options.MaxSteps; - ModelNamesComparer = modelNamesComparer ?? options.ModelNamesComparer; + ModelNamesComparer = modelNamesComparer; } ///