Provide more details when keys not found.
A request was made to provide the original key as well as the member that was not found. In compound keys {{Customer.Address.ZipCode}}, any of the names could be invalid, but knowing the fully-qualified name is useful for error handling. I also detected a bug where the code wasn't handling the case that a sub-key didn't exist. This needs to be handled using the KeyNotFound event.
This commit is contained in:
parent
ac09c8fc38
commit
a6c7933bab
|
@ -151,6 +151,31 @@ namespace mustache.test
|
|||
Assert.AreEqual(expected, actual, "The wrong message was generated.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If part of a key is wrong, the full details should be provided.
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void TestCompile_MultipartKey_PartMissing_ProvidesFullDetail()
|
||||
{
|
||||
FormatCompiler compiler = new FormatCompiler();
|
||||
const string format = @"{{Customer.Name}}";
|
||||
Generator generator = compiler.Compile(format);
|
||||
generator.KeyNotFound += (obj, args) =>
|
||||
{
|
||||
args.Substitute = args.Key + "," + args.MissingMember;
|
||||
args.Handled = true;
|
||||
};
|
||||
string actual = generator.Render(new
|
||||
{
|
||||
Customer = new
|
||||
{
|
||||
FirstName = "Bob"
|
||||
}
|
||||
});
|
||||
string expected = "Customer.Name,Name";
|
||||
Assert.AreEqual(expected, actual, "The wrong message was generated.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If we specify an alignment with a key, the alignment should
|
||||
/// be used when rending the value.
|
||||
|
|
|
@ -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.4.0")]
|
||||
[assembly: AssemblyFileVersion("0.0.4.0")]
|
||||
[assembly: AssemblyVersion("0.0.5.0")]
|
||||
[assembly: AssemblyFileVersion("0.0.5.0")]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using mustache.Properties;
|
||||
|
||||
namespace mustache
|
||||
|
@ -63,39 +64,47 @@ namespace mustache
|
|||
object nextLevel = _source;
|
||||
if (member != "this")
|
||||
{
|
||||
nextLevel = find(member);
|
||||
nextLevel = find(name, member);
|
||||
}
|
||||
for (int index = 1; index < names.Length; ++index)
|
||||
{
|
||||
IDictionary<string, object> context = toLookup(nextLevel);
|
||||
member = names[index];
|
||||
nextLevel = context[member];
|
||||
if (!context.TryGetValue(member, out nextLevel))
|
||||
{
|
||||
nextLevel = handleKeyNotFound(name, member);
|
||||
}
|
||||
}
|
||||
return nextLevel;
|
||||
}
|
||||
|
||||
private object find(string name)
|
||||
private object find(string fullName, string memberName)
|
||||
{
|
||||
IDictionary<string, object> lookup = toLookup(_source);
|
||||
if (lookup.ContainsKey(name))
|
||||
if (lookup.ContainsKey(memberName))
|
||||
{
|
||||
return lookup[name];
|
||||
return lookup[memberName];
|
||||
}
|
||||
if (_parent == null)
|
||||
{
|
||||
MissingKeyEventArgs args = new MissingKeyEventArgs(name);
|
||||
if (KeyNotFound != null)
|
||||
{
|
||||
KeyNotFound(this, args);
|
||||
}
|
||||
if (args.Handled)
|
||||
{
|
||||
return args.Substitute;
|
||||
}
|
||||
string message = String.Format(CultureInfo.CurrentCulture, Resources.KeyNotFound, name);
|
||||
throw new KeyNotFoundException(message);
|
||||
return handleKeyNotFound(fullName, memberName);
|
||||
}
|
||||
return _parent.find(name);
|
||||
return _parent.find(fullName, memberName);
|
||||
}
|
||||
|
||||
private object handleKeyNotFound(string fullName, string memberName)
|
||||
{
|
||||
MissingKeyEventArgs args = new MissingKeyEventArgs(fullName, memberName);
|
||||
if (KeyNotFound != null)
|
||||
{
|
||||
KeyNotFound(this, args);
|
||||
}
|
||||
if (args.Handled)
|
||||
{
|
||||
return args.Substitute;
|
||||
}
|
||||
string message = String.Format(CultureInfo.CurrentCulture, Resources.KeyNotFound, memberName);
|
||||
throw new KeyNotFoundException(message);
|
||||
}
|
||||
|
||||
private static IDictionary<string, object> toLookup(object value)
|
||||
|
|
|
@ -10,16 +10,23 @@ namespace mustache
|
|||
/// <summary>
|
||||
/// Initializes a new instance of a MissingKeyEventArgs.
|
||||
/// </summary>
|
||||
/// <param name="missingKey">The key that had no match.</param>
|
||||
internal MissingKeyEventArgs(string missingKey)
|
||||
/// <param name="key">The fully-qualified key.</param>
|
||||
/// <param name="missingMember">The part of the key that could not be found.</param>
|
||||
internal MissingKeyEventArgs(string key, string missingMember)
|
||||
{
|
||||
MissingKey = missingKey;
|
||||
Key = key;
|
||||
MissingMember = missingMember;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key that could not be found.
|
||||
/// Gets the fully-qualified key.
|
||||
/// </summary>
|
||||
public string MissingKey { get; private set; }
|
||||
public string Key { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the part of the key that could not be found.
|
||||
/// </summary>
|
||||
public string MissingMember { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to use the substitute.
|
||||
|
|
|
@ -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.4.0")]
|
||||
[assembly: AssemblyVersion("0.0.5.0")]
|
||||
[assembly: AssemblyFileVersion("0.0.4.0")]
|
||||
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
Loading…
Reference in New Issue