-
Hi! I am currently struggling doing chained combined formatters and I wanted to know if it was even possible from the beginning. Admitting I create custom formatters "add" and "mul", respectively adding a value to a source and multiplying a value with the source. Is that something possible to do? If that's the case, how can I modify my custom formatters to make it work? In my own use case, I wanted to convert a ratio value to a rounded percent value by doing Thank you for any help you could provide me! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
Yes, generally this can be done. However, by default formatting proceeds from left to right. /// <summary>
/// A simplistic math formatter
/// </summary>
public class SimplisticMathFormatter : IFormatter
{
/// <inheritdoc/>
public string Name { get; set; } = "math";
/// <inheritdoc/>
public bool CanAutoDetect { get; set; } = false;
/// <inheritdoc/>
public bool TryEvaluateFormat(IFormattingInfo formattingInfo)
{
// + - * /
var calculationType = formattingInfo.FormatterOptions;
// back-reference the parent FormattingInfo
var parentValue = ((Core.Formatting.FormattingInfo) formattingInfo).Parent!;
var childFormatter = Smart.CreateDefaultSmartFormat();
childFormatter.AddExtensions(new SimplisticMathFormatter());
var arg1Value = (int) Convert.ChangeType(formattingInfo.CurrentValue, TypeCode.Int32);
var arg2Value = int.Parse(childFormatter.Format(formattingInfo.Format!, parentValue.CurrentValue));
switch (calculationType)
{
case "+":
formattingInfo.Write((arg1Value + arg2Value).ToString());
break;
case "-":
formattingInfo.Write((arg1Value - arg2Value).ToString());
break;
case "*":
formattingInfo.Write((arg1Value * arg2Value).ToString());
break;
case "/":
formattingInfo.Write((arg1Value / arg2Value).ToString());
break;
}
return true;
}
} Here are the corresponding unit tests: [TestFixture]
public class SimplisticMathFormatterTests
{
[TestCase(5, 2, "+", "7")]
[TestCase(20, 15, "-", "5")]
[TestCase(4, 5, "*", "20")]
[TestCase(10, 5, "/", "2")]
public void CalculationTypeTests(int arg1, int arg2, string calcType, string expected)
{
var smart = Smart.CreateDefaultSmartFormat();
smart.AddExtensions(new SimplisticMathFormatter());
var data = new { Arg1 = arg1, Arg2 = arg2};
// calcType must be a literal
var result = smart.Format("{Arg1:math(" + calcType + "):{Arg2}}", data);
Assert.That(result, Is.EqualTo(expected));
}
[TestCase(5, 2, 10, "+", "*", "70")]
[TestCase(20, 15, 10, "-", "*", "50")]
[TestCase(4, 5, 10, "*", "*", "200")]
[TestCase(10, 5, 10, "/", "*", "20")]
public void NestedCalculationTests(int arg1, int arg2, int arg3, string calcType1, string calcType2, string expected)
{
var smart = Smart.CreateDefaultSmartFormat();
smart.AddExtensions(new SimplisticMathFormatter());
var data = new { Arg1 = arg1, Arg2 = arg2, Arg3 = 10};
// calcType1 / calcType2 must be literals
var result = smart.Format("{Arg3:math(" + calcType2 + "):{Arg1:math(" + calcType1 + "):{Arg2}}}", data);
Assert.That(result, Is.EqualTo(expected));
}
} After all: This is feasible, but for more advanced scenarios a formatter extension using a math parser like NCalc or MathParser would be better. |
Beta Was this translation helpful? Give feedback.
-
Put your request to the wish list (see #299) |
Beta Was this translation helpful? Give feedback.
Yes, generally this can be done. However, by default formatting proceeds from left to right.
Before explaining a lot, here is a proof of concept in code.
(Btw: Putting the calculation method into the option part might reduce the number of required custom formatters.)