模块:Schema/doc
这是模块:Schema的文档页面
此模块用于验证数据结构。契机是去年的棒球赛契机是模块:IconLink/data被填错了,过了一个多月才发现,便想弄点校验。
基础
local schema = require('Module:Schema') -- 随便起个名,再比如scm,再比如s
local valid, msg = schema.Number:test(1)
--> true, nil
local valid, msg = schema.Number:test('啊啊啊啊啊啊啊啊啊啊可爱的字符串')
--> false, '报错信息,我忘了是啥了,等它出来了自己看'
schema.Number:assert(1) --> true
schema.Number:assert('OwO') --> 抛出错误
-- 后面讲的几个类型都有test、assert这两个方法。
Any
schema.Any -- 任何值都能通过测试,是很随性的孩子
-- 约束选项有validator:
schema.Any{validator=func}
schema.Any{validator={func1, func2, ...}}
-- validator的函数为(any) -> truthy | falsy,比如判断是否为非字符串:
local function is_string(v)
return type(v) == 'string'
end
local function is_not_empty_string(v)
return v ~= ''
end
local NonEmptyString = schema.Any{validator={is_string, is_not_empty_string}}
NonEmptyString:test('只有非空字符串能通过') --> true
-- 仅作示例,实际使用String更便捷。
-- 可以在已有schema的基础上继续增加约束,这对于Number、String等其他支持约束的类型也适用。
-- 还是拿NonEmptyString举例
local String = schema.Any{validator=is_string}
local NonEmptyString = String{validator=is_not_empty_string}
Nil、Boolean
schema.Nil -- nil类型的值可以通过
schema.Boolean -- boolean类型的值可以通过
-- 这两个无约束选项,因为Nil只能是nil,Boolean只能是true或false。
-- 如果需要“只能是true”或“只能是false”,请看Const。
Number
schema.Number:test(0721) --> true
-- 约束选项:
-- gt(大于)、lt(小于)、ge/min(大于等于)、le/max(小于等于)、ne(不等于),
-- 以及validator(自定义约束)
-- 例如:
schema.Number{gt=0, le=100}:test(22/7) --> true
String
schema.String:test('Ciallo ~') --> true
-- 约束选项:
-- min_len(最短长度)、max_len(最长长度)、pattern(正则),
-- 以及validator(自定义约束)。
-- 例如,Any中的例子可以改为:
local NonEmptyString = schema.String{min_len=1}
-- 例二:
local HttpUrl = schema.String{pattern='^https?://'}
Function
schema.Function:test(function() return 42 end)
-- 约束选项只有validator
Table
schema.Table -- table类型的值可以通过
-- 示例
local CharacterInfo = schema.Table{
name = schema.String{min_len=1},
age = schema.Number{min=0},
sex = 'female', -- 等同于 sex = schema.Const('female')
}
local info1 = {
name = '缠流子',
age = '17',
sex = 'female',
}
local info2 = {
name = '满舰饰真子',
age = 16,
sex = 'female',
}
CharacterInfo:test(info1) --> false, '好像会说什么age应该是数字而不是字符串'
CharacterInfo:test(info2) --> true
-- 'validator'字段被自定义校验器占用了,
-- 若你的结构中包含这两个字段,请使用schema.Const('validator')代替。
-- 作用对比如下:
local function check_children_num(t)
return #t > 5
end
local array_with_6_children = {1, 2, 3, 4, 5, 6}
local table_with_validator_field = {
validator = check_children_num
}
-- 这是为表格添加自定义校验:
schema.Table{
validator = check_children_num
}:test(array_with_6_children) --> true
-- 而这是设定表格validator字段的类型:
schema.Table{
[schema.Const('validator')] = schema.Function,
}:test(table_with_validator_field) --> true
-- 可以使用schema作为键来匹配多个字段:
local hanzi_number_conversion = {
'一', '二', '三',
['一'] = 1, ['二'] = 2, ['三'] = 3,
}
schema.Table{
[schema.String] = schema.Number,
[schema.Number] = schema.String,
}:test(hanzi_number_conversion) --> true
-- 这个例子中,只有数字键对应的值为字符串、字符串键对应的值为数字的表才能通过测试。
Const
schema.Const(val)
-- Const是一个函数,本身不可以用作校验,它接收一个参数并返回一个schema,
-- 只有等于这个参数的值才能通过校验。
schema.Const('?'):test('!') --> false, '好像是说这个不等于那个'
schema.Const('?'):test('?') --> true
-- 当你传入相同的对象时,返回的schema也是同一个对象
local t = {}
local A, B = schema.Const(t), schema.Const(t)
rawequal(A, B) --> true
Union
schema.Union(scm1, scm2, ...)
-- 这个并集,被测值符合参数的其中一种就行。
-- 与Const一样,Union本身不可以用作校验,调用后返回的对象才可。
local QAQ = schema.Union('来测', '求你了,来测吧', schema.Boolean)
QAQ:test('来测') --> true
QAQ:test('求你了,来测吧') --> true
QAQ:test(false) --> true
QAQ:test(6) --> false, '说是union里的类型都不符合'
-- 有更方便的写法:
local WhatName = schema.String / schema.Number / nil
-- 等同于schema.Union(schema.String, schema.Number, nil)。
其他
schema.Integer -- 用法同schema.Number,只不过这个只有整数能通过测试
schema.Callable -- 可以调用的值,包含function和设置了__call元方法的表
schema.Truthy -- 所有不是nil或false的值
schema.Falsy -- nil或false