Skip to content
Gabe Stocco edited this page Aug 4, 2020 · 20 revisions

Quick References

  • Authoring Rules specifies how to create Rules for OAT.
  • Delegates explores the extensibility points available in OAT via delegate declarations.
  • Scripts covers usage of using Scripts directly embedded in your Rules.

Overview

Object Anaylsis Toolkit (OAT) is a meta-programming engine for processing objects using a run-time supplied Rule Set.

Rules contain a boolean Expression evaluated over the Clauses inside the rule. Each Clause performs a specified operation on the Target object's Field. See Authoring Rules for a detailed explanation of Rules and Clauses.

Usage

The simplest usage of OAT is to check if Rules apply to objects.

object target;
IEnumerable<Rule> rules;
var analyzer = new Analyzer();
var rulesWhichApply = analyzer.Analyze(rules,target);

Example

This sample from the the Walkthrough captures the weight of Overweight vehicles

var overweightTruck = new Vehicle()
{
    Weight = 30000,
    Capacity = 20000,
    VehicleType = VehicleType.Truck
};

var overweightCar = new Vehicle()
{
    Weight = 6000,
    Capacity = 5000,
    VehicleType = VehicleType.Car
};

var okayTruck = new Vehicle()
{
    Weight = 20000,
    Capacity = 20000,
    VehicleType = VehicleType.Truck
};

// Set up our Analyzer with the Custom Overweight Operation (see below)
var analyzer = new Analyzer();
analyzer.SetOperation(OverWeightOperation);

// Collect the captures from Rules which apply
var res = analyzer.GetCaptures(rules, overweightTruck);

// We get the First Rule capture and the First Clause Capture
// Since this is our OverweightOperation on an int we know we should get back a TypedClauseCapture<int>
var weight = ((TypedClauseCapture<int>)res.First().Captures[0]).Result;

// And we've captured the weight over the overweightTruck
Assert.IsTrue(weight == 30000);

// The Rule doesn't apply to our Car and Truck that isn't overweight
Assert.IsFalse(analyzer.Analyze(rules, overweightCar).Any());
Assert.IsFalse(analyzer.Analyze(rules, okayTruck).Any());

class Vehicle
{
    public int Weight;
    public int Capacity { get; set; }
    public VehicleType VehicleType { get; internal set; }
}

enum VehicleType
{
    Motorcycle,
    Car,
    Truck
}

var overweightRule = new VehicleRule("Overweight Truck")
{
    // Both clauses must be true for this Rule to apply
    Expression = "Overweight AND IsTruck",
    Target = "Vehicle",
    Clauses = new List<Clause>()
    {
        new Clause(Operation.Custom)
        {
            Label = "Overweight",
            CustomOperation = "OVERWEIGHT",
            Capture = true
        },
        new Clause(Operation.Equals)
        {
            Label = "IsTruck",
            Data = new List<string>() { "Truck" }
        }
    }
}

OatOperation OverweightOperation = new OatOperation(Operation.Custom, analyzer)
{
    CustomOperation = "OVERWEIGHT",
    OperationDelegate = OverweightOperationDelegate,
    ValidationDelegate = OverweightOperationValidationDelegate
};

public OperationResult OverweightOperationDelegate(Clause clause, object? state1, object? state2, IEnumerable<ClauseCapture>? captures)
{
    if (state1 is Vehicle vehicle)
    {
        var res = vehicle.Weight > vehicle.Capacity;
        if ((res && !clause.Invert) || (clause.Invert && !res))
        {
            // The rule applies and is true and the capture is available if capture is enabled
            return new OperationResult(true, clause.Capture ? new TypedClauseCapture<int>(clause, vehicle.Weight, state1, state2) : null);
        }
    }
    return new OperationResult(false, null);
}

public IEnumerable<Violation> OverweightOperationValidationDelegate(Rule r, Clause c)
{
    var violations = new List<Violation>();
    if (r.Target != "Vehicle")
    {
        violations.Add(new Violation("Overweight operation requires a Vehicle object", r, c));
    }

    if (c.Data != null || c.DictData != null)
    {
        violations.Add(new Violation("Overweight operation takes no data.", r, c));
    }
    return violations;
}

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

Clone this wiki locally