Skip to content

Commit

Permalink
Merge pull request #21 from typicalzergling/working
Browse files Browse the repository at this point in the history
Working
  • Loading branch information
typicalzergling authored Aug 3, 2018
2 parents 5dfada4 + bc88f5a commit c07a84c
Show file tree
Hide file tree
Showing 13 changed files with 402 additions and 93 deletions.
15 changes: 8 additions & 7 deletions RulesEngine/category.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ local CATEGORY_OBJECT_TYPE = (PackageName .. "::Category");

--[[===========================================================================
| category_Find
| Searches this category for a rule which matches the specified id, if
| Searches this category for a rule which matches the specified id, if
| such a rule is found then this returns it, otherwise nil is returned.
=======================================================================--]]
local function category_Find(self, id)
Expand All @@ -12,14 +12,14 @@ local function category_Find(self, id)
for _, rule in ipairs(self.rules) do
if (rule:CheckMatch(id)) then
return rule
end
end
end
end

--[[===========================================================================
| category_Add
| Adds the specified rule to the category, if the rule is already in
| the category list then this is noop, it will not add the rule a
| the category list then this is noop, it will not add the rule a
| second time.
=======================================================================--]]
local function category_Add(self, rule)
Expand Down Expand Up @@ -98,24 +98,25 @@ local category_API =
GetName = function(self) return self.name end,
GetId = function(self) return self.id end,
GetRuleStatus = category_GetRuleStatus,
Find = category_Find,
};

--[[===========================================================================
| new_Category
| Create a new category with the specified name, the name must be a
| Create a new category with the specified name, the name must be a
| non-empty string.
=======================================================================--]]
local function new_Category(id, name)
assert(type(name) == "string" and (string.len(name) ~= 0), "The category name must be a valid string");
assert(id and type(id) == "number", "The category id must be provided and be non-empty");

local instance =
{
local instance =
{
name = name,
id = id,
rules = {},
};

return Package.CreateObject(CATEGORY_OBJECT_TYPE, instance, category_API);
end

Expand Down
60 changes: 50 additions & 10 deletions RulesEngine/engine.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ local function engine_CreateCategory(self, categoryId, categoryName)
self.log:Write("Created category(%d, %s)", categoryId, categoryName);
end

--[[===========================================================================
| engine_RemoveCategory:
| This removes the specified category if it already exists in the
| engine, removing an non-existing category is a no-op.
=========================================================================]]
local function engine_RemoveCategory(self, categoryId)
assert(tonumber(categoryId), "Category IDs must be numeric");

for i, category in ipairs(self.categories) do
if (category:GetId() == categoryId) then
self.log:Write("Removing category(%d, %s)", category:GetId(), category:GetName());
table.remove(self.categories, i);
end
end
end

--[[===========================================================================
| engine_ImportGlobals
| This imports globals which should be exposed to the rule scripts, this
Expand Down Expand Up @@ -130,33 +146,33 @@ local function engine_AddConstants(self, constants)
end

--[[===========================================================================
| validate_Rule (local)
| validateRuleDefinition (package)
| Given a table which represents a rule definition tis applies all of
| constraints to make sure it adheres to what we need.
=======================================================================--]]
local function validateRule(rule)
function Package.validateRuleDefinition(rule, skip)
-- Valid the ID
local id = rule.Id;
if (not id or (type(id) ~= "string") or (string.len(id) == 0)) then
error("The rule identifier is invalid", 3);
error("The rule identifier is invalid", skip or 3);
end

-- Valid the name
local name = rule.Name;
if (not name or (type(name) ~= "string") or (string.len(name) == 0)) then
error("The rule name must be a valid string", 3);
error("The rule name must be a valid string", skip or 3);
end

-- Validate the script.
local script = rule.Script;
if (not script) then
error("The rule script must be valid.", 2);
error("The rule script must be valid.", skip or 3);
end

if (type(script) == "string") and (string.len(script) == 0) then
error("The rule cannot have an empty script", 3);
error("The rule cannot have an empty script", skip or 3);
elseif (type(script) ~= "function" and type(script) ~= "string") then
error("The rule script is an unsupported type: " .. type(script), 3);
error("The rule script is an unsupported type: " .. type(script), skip or 3);
end

return true;
Expand All @@ -176,7 +192,7 @@ end
=======================================================================--]]
function engine_AddRule(self, categoryId, ruleDef, params)
assert(type(categoryId) == "number", "The category id must be numeric identifier");
validateRule(ruleDef);
Package.validateRuleDefinition(ruleDef, 3);
if (params and type(params) ~= "table") then
error("The rule parameters must be a table, providing the parameters as key-value pairs", 2);
end
Expand Down Expand Up @@ -256,7 +272,7 @@ local function createRestrictedEnvironment(readOnly, ...)
__newindex =
function(self, key, value)
if (readOnly) then
error("The environment is read-only and cannot be changed", 2);
error("The environment is read-only and cannot be changed", 3);
end
rawset(self, key, value);
end,
Expand All @@ -274,7 +290,7 @@ local function createRestrictedEnvironment(readOnly, ...)
end

if (readOnly) then
error(string.format("Identifier '%s' was not found", key, 2));
error(string.format("No function or variable named \"%s\" was not found", key), 3);
end
end
})
Expand Down Expand Up @@ -403,13 +419,35 @@ local function engine_ValidateScript(self, object, script, params)
local renv = createRestrictedEnvironment(true, accessors, self.environment, self.globals);
assignFunctionEnv(self.environment, createRestrictedEnvironment(false, accessors, { OBJECT = object }, _G));
local status, _, message = rule:Execute(renv);

if (not status) then
return false, message;
end

return true;
end

--[[===========================================================================
| engine_AddRuleset:
| Adds a ruleset to the given category. The rule set is created empty
| and rules can be added to it. If we fail to create the object
| the returns "nil".
=========================================================================]]
function engine_AddRuleset(self, categoryId, id, name)
assert(type(categoryId) == "number", "The category identifier must be numeric.");

local category = assert(findCategory(self, categoryId), "The specified categoryId (" .. tostring(categoryId) .. ") is invalid, remember to call AddCategory first");
local ruleset = Package.CreateRuleset(self, id, name);
if (not ruleset) then
self.log:Write("Failed to add set '%s' to category=%d", id, categoryId);
return nil;
end

category:Add(ruleset);
self.log:Write("Added set '%s' [%d]", ruleset:GetId(), categoryId);
return ruleset;
end

-- Define the API we expose
local engine_API =
{
Expand All @@ -420,11 +458,13 @@ local engine_API =
AddFunctions = engine_AddFunctions,
AddConstants = engine_AddConstants,
CreateCategory = engine_CreateCategory,
RemoveCategory = engine_RemoveCategory,
GetId = function(self) return self.id end,
GetRuleStatus = engine_GetRuleStatus,
ClearRules = engine_ClearRules,
SetVerbose = engine_SetVerbose,
ValidateScript = engine_ValidateScript,
AddRuleset = engine_AddRuleset,
};

--[[===========================================================================
Expand Down
7 changes: 3 additions & 4 deletions RulesEngine/rule.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ local function rule_Execute(self, environment)
if status then
self.healthy = true;
return true, result, nil;
elseif not status then
else
self.healthy = false;
local _, _, _, _, message = result:find("^(.*:)(%d+:)(.*)$")
self.error = message;
return false, nil, message;
self.error = result;
return false, false, result;
end
end

Expand Down
1 change: 1 addition & 0 deletions RulesEngine/rules.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<Script file="log.lua"/>
<Script file="object.lua"/>
<Script file="rule.lua"/>
<Script file="set.lua"/>
<Script file="category.lua"/>
<Script file="engine.lua"/>
</Ui>
Loading

0 comments on commit c07a84c

Please sign in to comment.