Welcome Guest, you are in: Login

dbones docs

RSS RSS

Navigation (boxes)




Search the wiki
»

Intro

The code can be found here: https://github.com/dbones/Calculator.Boxes.Windsor

In this article we are going to look into a small command line calculator app using Boxes. As it’s been done before, we need a twist. So instead of injecting the formula/equation functions such as a Plus command (+) Subtract command (-), we will inject calculator functions. For example: Undo, Memory and Current Value commands. To understand this here is the intended usage of the application:

Image

We can see the user
1. Adds the value 100 to memory location temp1
2. Adds 5 and 5, which updates the Calculators Current Value
3. Applies 6 x Current Value -2
4. Applies Current Values + memory location temp1
5. Undo’s the previous command, returning the calculator to 58
6. Finally quits the app

The Current Value, Memory and Undo are all added features to the calculator, using Boxes. The idea is we can add more or remove functionality easily for the calculator.

Solution Overview

Note: how you arrange your modules is upto you.

In this sample they have been arranged to demo some aspects of Boxes.Integration, take some time and look into the code each module contains, notice they are very small





The solution consists of several .NET projects


Image



This project can be partitioned into a few couple of area's The Calculator application
  • Calc.CommandLine – the host
  • Calc.Core – contains the main contracts and classes
  • Calc. Commands – has a number of extension commands
  • Calc.NCalcEngine – plug-in for NCalc

Supporting Modules - some of these you can copy directly into another project
  • Identities – provides the interfaces (and attributes) to identify contracts (exported classes)
  • Identities.Windsor – provides the Boxes setup using Windsor as the IoC.
  • Process - a default process, which you have full control over. you can make this as simple or advanced as you need.
  • Aspects - provides AOP logging
  • Aspects.Windsor registers the AOP pattern. This will be applied against every module in you application.
  • Container.Windsor - sets up Windsor, to support injecting IEnumerable

For more information about Identities, please read this article.

Calc.CommandLine

An instance of the calculator class is hosted in a console app. The host also sets up Boxes, and also in Debug module, it automatically copies the packages into a packages folder.

Calc.Core

This is the main package, which the command line application uses. The package contains the following classes.


Image

Calculator (transient)

In this program the calculator coordinates a number of CalculatorCommands and a FormularParser. The Calculator Evaluates a string such as “8 + 5 – (4 / 2)”and stores the result in the Value property.


ICalculatorCommand

The commands process the users input and return a modified string, so it is ready to be processed by the FormulaParser.

The commands look at the users input and modify it if they find a required pattern. For example if the user provides “cur - 2”, the “cur” in this can take the current value, so a command would modify the string replacing “cur” with the current value, “55 - 2”.


If the commands return an empty string, the calculator class will not evaluate the input.

QuitCommand (transient)

Converts “q” to “”, the calculator will not process an empty string.


IFormulaParser

A calculator must be able to deal with some complex equations/formula, more than:
[Left] Symbol [Right] i.e 5+5

We should support full BODMAS. This leads to the following interface:



/// <summary>
/// will be responsible for actually calculating the formula
/// </summary>
public interface IFormulaParser
{
    /// <summary>
    /// calculate the formula
    /// </summary>
    /// <param name="input">a string representation of an equation to evaluate</param>
    /// <returns>the output as a decimal</returns>
    decimal Evaluate(string input);
}

We can now plug-in any implementation into the Calculator, and this will evaluate the formula.In this sample, we will use an existing library to evaluate the expression; however we will add multiple common calculator functions.

Calc.Commands

This package contains a number of CalculatorCommands, we can have other packages which also store commands. All the commands are transient.


CurrentCommand

Allows the user to use the current value as part of the expression
Example: “cur + 4”


UndoCommand

Stores the past values, allowing the user to simply transition back to a previous state
Example: “undo”


CalculatorMemoryCommand

Store, remove and use values into/from memory
Example:
“add temp1 500”
“100 + mem temp1”
“remove temp1”


NOTE: each command encapsulates state, used to support their required behaviour.


Example

A quick example is the undo command

/// <summary>
/// allows the user to undo the last command, which affected the current value
/// </summary>
/// <remarks>
/// this is not pretty code, please apply thought before copying it
/// </remarks>
public class UndoCommand : ICalculatorCommand, ITransientDependency
{
    private readonly Stack<decimal> _values = new Stack<decimal>();
    private decimal _undoValue = 0;

    public string Execute(string input, decimal currentValue)
    {
        if (input.ToLower().Equals("undo"))
        {
            var temp = _undoValue;
            if (_values.Count > 0)
            {
                _undoValue = _values.Pop();
            }
            return temp.ToString(CultureInfo.InvariantCulture);
        }

        if (currentValue != _undoValue)
        {
            _values.Push(_undoValue);
            _undoValue = currentValue;
        }
        
        return input;
    }
}

You can see the stack is used to store the values, which allows the program to restore to a previous state.
The command evaluates the user’s input, and acts accordingly:
Storing the current value onto the stack, and returning the input as is

Applying the undo, by popping off the top value of the stack, this will be evaluated and become the current value.


Calc.NCalcEngine

Uses NCalc to evaluate the user’s expression, we could have written own and plug in all the command parsing. The good thing is NCalc already does the expression evaluation.


End notes

Putting all these parts together we have ourselves a simple calculator.
From this simple example we have observed how to integrate Castle Windsor with Boxes Core, through Boxes Integration. Also how we can extend the behaviour of Boxes Integration.
dbones docs, is a sub-site of dbones.co.uk, all its content belongs to dbones.co.uk, this also includes logo's.