--[[---------------------------------------------------------------------------- --@ 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