
--[[----------------------------------------------------------------------------
--@ Descrption: 属性节点类库
--@ Changes:
-------------------------------------------------------------------------------]] -- 引入面向对象的类机制
local oopclass = require("misc.oopclass")
local class = oopclass.class -- 引入断言库
local assertlib = require("misc.assertlib")
local typeAssert = assertlib.typeAssert -- 属性节点
local AttrNode = class()
AttrNode.__abstract = true --[[
Function: AttrNode.__attrInitialize
Description: 初始化节点属性
Parm: self(object):对象本身
source(table): 外部设置属性节点表
attrs(table): 属性名称表
return: NA
]]
AttrNode.__attrInitialize = function ( self, source, attrs )
typeAssert(source, "table")
typeAssert(attrs, "table") -- 记录合法的属性名称,用于修改属性
self.__legal_attrs = attrs -- 将参数值记录到对象
for _,para in ipairs(attrs) do
if source[para] then
self[para] = source[para]
end
end -- 只读属性表
self.__readonly_attrs = {}
end --[[
Function: AttrNode.__checkAttrLegal
Description: 校验属性名合法性
Parm: self(object):对象本身
name(string): 属性名
return: bool: 是否校验通过
]]
AttrNode.__checkAttrLegal = function ( self, name )
typeAssert(name, "string") local legalAttrs = self.__legal_attrs -- 只有在合法列表中的属性才校验通过
for _,attr in ipairs(legalAttrs) do
if name == attr then
return
end
end assert(false, "attr name is illegal!")
end --[[
Function: AttrNode.setAttribute
Description:设置节点属性
Parm: self(object):对象本身
name(string): 属性名
value(string): 属性值
return: 菜单节点对象
]]
AttrNode.setAttribute = function (self, name, value)
typeAssert(name, "string") -- 属性类型支持三种类型:
-- string, 例如 菜单id
-- number, 例如 权限
-- table, 例如 backendFile
-- function, 例如 过滤函数
-- nil, 保证可选的参数可以被设置为nil
typeAssert(value, "string", "number", "table", "function", "nil") self:__checkAttrLegal(name) -- 只读属性,不允许修改
for _,readOnlyAttr in ipairs(self.__readonly_attrs) do
if readOnlyAttr == name then
-- 直接返回
return self
end
end self[name] = value -- 链式写法需要
return self
end --[[
Function: AttrNode.getAttribute
Description:设置节点属性
Parm: self(object):对象本身
name(string): 属性名
return: 属性值
]]
AttrNode.getAttribute = function (self, name)
typeAssert(name, "string") self:__checkAttrLegal(name) return self[name]
end --[[
Function: AttrNode.defineAttrReadOnly
Description:设置指定属性为只读
Parm: self(object):对象本身
name(string): 属性名
return: 属性值
]]
AttrNode.defineAttrReadOnly = function (self, name)
typeAssert(name, "string") self:__checkAttrLegal(name) -- 记录属性到只读属性表
table.insert(self.__readonly_attrs, name) -- 链式写法需要
return self
end --[[
Function: AttrNode.searchCollection
Description:搜索节点的附属集合(collection), 例如 子菜单 和 功能区
Parm: self(object):对象本身
collection(table): 待搜索的集合
func(function): 对于集合中的元素执行的操作
return: NA
]]
AttrNode.searchCollection = function (self, collection, func)
typeAssert(collection, "table")
typeAssert(func, "function") local isloop = nil for index,item in ipairs(collection) do
isloop = func(item, index) -- 后面不需要循环了
if isloop == false then
break
end
end
end --[[
Function: AttrNode.__attrToNVPair
Description: 将属性转换为 名值对 NVPair(name value pair): "name:value"
Parm: self(object):对象本身
name(string): 属性名
splitter(string): name 和 value之间的分隔符
return: NVPair(string)
]]
AttrNode.__attrToNVPair = function (self, name, splitter)
typeAssert(name, "string")
typeAssert(splitter, "string") self:__checkAttrLegal(name) local quotedName = string.format("%q", name) local ret = quotedName ..splitter local val = self[name]
local typeOfVal = type(val) local valstr = "null" if typeOfVal == "nil" then
valstr = "null"
elseif typeOfVal == "string" then
valstr = string.format("%q", val)
elseif typeOfVal == "number" then
valstr = tostring(val)
-- 支持backendFile = {"xx", "yy"}的情况
elseif typeOfVal == "table" then
local cache = {}
for _,v in ipairs(val) do
if type(v) == "string" then
local quotedStr = string.format("%q", v)
table.insert(cache, quotedStr)
end
end
local contentStr = table.concat(cache, ",")
valstr = string.format("[%s]", contentStr)
else
end ret = ret .. valstr return ret
end --[[
Function: AttrNode.__getNVPairsofAttrs
Description: 将节点属性转换为字符串NVPair,缓存在表中
Parm: self(object):对象本身
splitter(string): name 和 value之间的分隔符
attrs(table): 指定属性名集合,可选
return: cache(table)
]]
AttrNode.__getNVPairsofAttrs = function (self, splitter, attrs)
typeAssert(splitter, "string")
typeAssert(attrs, "table", "nil") -- 如果未指定属性集合,确定为所有合法属性
if not attrs then
attrs = self.__legal_attrs
end local cache = {} self:searchCollection(attrs, function ( item, index )
-- every cache element is name:value
table.insert(cache, self:__attrToNVPair(item, splitter))
end) return cache
end --[[
Function: AttrNode.__nodeToJSON
Description: 将节点转换为JSON数据格式
Parm: self(object):对象本身
attrs(table): 指定属性名集合,可选
return: json(string)
]]
AttrNode.__nodeToJSON = function (self, attrs)
typeAssert(attrs, "table", "nil") local cache = self:__getNVPairsofAttrs(":", attrs) -- produce result: name1:value1, name2:value2
local contentStr = table.concat(cache, ",") -- wrap content with bracket, get JSON
local jsonStr = string.format("{%s}", contentStr) return jsonStr
end -- 将此类返回
return AttrNode
--[[----------------------------------------------------------------------------
--@ Descrption: 集合类库
--@ Changes:
-------------------------------------------------------------------------------]] -- 引入面向对象的类机制
local oopclass = require("misc.oopclass")
local class = oopclass.class
local instanceof = oopclass.instanceof -- 引入属性节点类
local AttrNode = require("misc.attrnodeclass") -- 引入断言库
local assertlib = require("misc.assertlib")
local typeAssert = assertlib.typeAssert -- 集合节点
local CollectionNode = class(AttrNode) --[[
Function: CollectionNode.__init__
Description:实例初始化
Parm: self(object):对象本身。
itemProtoDesc(table): 集合成员原型描述,包括
{
class -- 集合成员的类
keyName -- 集合成员的主键
}
return: 无
]]
CollectionNode.__init__ = function ( self, itemProtoDesc )
typeAssert(itemProtoDesc, "table")
-- 集合成员的类
typeAssert(itemProtoDesc.class, "table")
-- 集合成员主键,用户查找、添加、删除等
typeAssert(itemProtoDesc.keyName, "string") -- 集合成员的描述
self.__itemProtoDesc = itemProtoDesc -- 集合成员的存储表
self.__itemSet = {} -- 集合成员静态修改器表
self.__staticModFuncs = {} -- 集合成员动态修改器表
self.__dynamicModFuncs = {}
end --[[
Function: CollectionNode.findItem
Description:按照主键值查集合成员
Parm: self(object):对象本身。
keyValue(string): 主键值
return: targetObj, targetIndex : 目标对象, 目标对象下标
]]
CollectionNode.findItem = function ( self, keyValue )
typeAssert(keyValue, "string") -- 查找
local targetObj = nil
local targetIndex = nil
local keyName = self.__itemProtoDesc.keyName
self:searchCollection(self.__itemSet, function ( item, index )
if keyValue == item:getAttribute(keyName) then
targetObj = item
targetIndex = index
return false
end
end) return targetObj, targetIndex
end --[[
Function: CollectionNode.addItem
Description:添加集合成员
Parm: self(object):对象本身。
itemTable(table): 集合成员原始数据表
return: self
]]
CollectionNode.addItem = function ( self, itemTable )
typeAssert(itemTable, "table") -- 类型要与原型一致
local itemClass = self.__itemProtoDesc.class
local itemObj = itemClass(itemTable)
if not instanceof(itemObj, itemClass) then
return self
end -- key值异常保护
local keyName = self.__itemProtoDesc.keyName
local keyValue = itemObj:getAttribute(keyName)
if not keyValue then
return self
end -- 将key属性设置对只读
itemObj:defineAttrReadOnly(keyName) -- 新添加项的key值,不允许与现有表中项的key值重复!
-- 在表空间中, key表示的对象是唯一的, 在新添加表项时候, 需要检查冲突,
-- 只有在没有冲突的情况下, 才能添加成功。
-- 这种做法的考虑是,代码包化的背景下,addItem 分散在不同目录中,
-- 如果支持覆盖, 后添加者会将已有项覆盖掉,造成故障!!!
-- 对于正常的覆盖情况, 请先 调用 removeItem 然后 调用 addItem
local sameKeyObj, sameKeyIndex = self:findItem(keyValue)
-- 如果有重复,则报错
if sameKeyObj then
error("addItem keyName("..keyName..")'s keyValue("..keyValue..") conflict!")
end -- 将新类型添加进去
table.insert(self.__itemSet, itemObj) -- 返回集合对象本身,支持链式写法
return self
end --[[
Function: CollectionNode.removeItem
Description:删除指定集合成员
Parm: self(object):对象本身。
keyValue(string): 集合主键值
return: self
]]
CollectionNode.removeItem = function ( self, keyValue )
typeAssert(keyValue, "string") -- 按照主键,查找到集合成员,删除
local targetObj, targetIndex = self:findItem(keyValue)
if targetObj then
table.remove(self.__itemSet, targetIndex)
end -- 返回集合对象本身,支持链式写法
return self
end --[[
Function: CollectionNode.clearItem
Description:清空集合中所有成员
Parm: self(object):对象本身。
return: self
]]
CollectionNode.clearItem = function ( self, keyValue )
typeAssert(keyValue, "string") -- 重新设置为空表
self.__itemSet = {} -- 返回集合对象本身,支持链式写法
return self
end --[[
Function: CollectionNode.searchItem
Description: 遍历集合成员对象
Parm: self(object):对象本身
func(function): 对于集合成员执行的操作
return: self
]]
CollectionNode.searchItem = function (self, func)
typeAssert(func, "function") -- 遍历
self:searchCollection(self.__itemSet, func) -- 返回集合对象本身,支持链式写法
return self
end --[[
Function: CollectionNode.loadConfig
Description: 以配置表形式加载规则
Parm: self(object):对象本身
configTable(table):配置表
return: self
]]
CollectionNode.loadConfig = function (self, configTable)
typeAssert(configTable, "table") -- 遍历configTable,设置到管理表中
self:searchCollection(configTable, function ( item, index )
self:addItem(item)
end) -- 返回集合对象本身,支持链式写法
return self
end --[[
Function: CollectionNode.addModifier
Description: 添加加载器。
加载器就是一个匿名函数,函数体中定义规则的修改语句(CRUD)。
与loadConfig形成互补,支持分散注册规则(模块化要求),和修改已有规则(定制要求)。
同一表对象,所有addModifier语句所属文件,在编译阶段拼接为一个文件 xxx_modifier.lua。
Parm: self(object):对象本身
modFunc(function):修改规则函数,无入参,无返回值
return: self
]]
CollectionNode.addModifier = function (self, modFunc)
typeAssert(modFunc, "function") table.insert(self.__staticModFuncs, modFunc) -- 返回集合对象本身,支持链式写法
return self
end --[[
Function: CollectionNode.loadModifier
Description: 执行所有的加载器函数。
与addModifier接口逻辑配套,
在require("xxx_modifier.lua")之后,调用此函数,完成规则修改功能。
Parm: self(object):对象本身
return: self
]]
CollectionNode.loadModifier = function (self)
-- 执行所有加载器函数
for _,modFunc in ipairs(self.__staticModFuncs) do
modFunc()
end -- 返回集合对象本身,支持链式写法
return self
end --[[
Function: CollectionNode.runModifier
Description: 运行加载器,加载器定义与addModifier相同。
与addModifier不同的是,此函数会将加载器函数,立刻执行,完成动态修改规则。
说明:
1、loadConfig/addModifier&loadModifier 是为静态配置设计(第一次加载模块时),
2、runModifier为动态配置设计,在任意文件中插入此语句,在将来运行到此文件,才加载规则。
Parm: self(object):对象本身
modFunc(function):修改规则函数,无入参,无返回值
return: self
]]
CollectionNode.runModifier = function (self, modFunc)
typeAssert(modFunc, "function") -- 遍历 已经执行过的 动态配置的修改器函数
for _,modFuncCache in ipairs(self.__dynamicModFuncs) do
-- 如果已经执行过,则不再执行, 避免 addItem 执行多次的情况
if modFuncCache == modFunc then
return self
end
end modFunc() table.insert(self.__dynamicModFuncs, modFunc) -- 返回集合对象本身,支持链式写法
return self
end -- 将此类返回
return CollectionNode