├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── rockspecs ├── valua-0.2.1-1.rockspec ├── valua-0.2.1-2.rockspec ├── valua-0.2.2-1.rockspec ├── valua-0.2.2-2.rockspec ├── valua-0.2.2-3.rockspec ├── valua-0.3-1.rockspec └── valua-current-1.rockspec ├── valua-test.lua └── valua.lua /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-pro 2 | repo_token: GmAUEIWICvwIaQh2aHQSuIhnZO4wJ81Kb 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | luacov.report.out 2 | luacov.stats.out 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | 4 | env: 5 | - LUA="lua 5.1" COMPAT=default 6 | - LUA="lua 5.2" COMPAT=default 7 | - LUA="lua 5.2" COMPAT=none 8 | - LUA="lua 5.3" COMPAT=default 9 | - LUA="lua 5.3" COMPAT=none 10 | - LUA="lua 5.3" COMPAT=default CFLAGS="-DLUA_NOCVTN2S -DLUA_NOCVTS2N" 11 | - LUA="luajit 2.0" COMPAT=none 12 | - LUA="luajit 2.0" COMPAT=all 13 | - LUA="luajit 2.1" COMPAT=none 14 | - LUA="luajit 2.1" COMPAT=all 15 | 16 | before_install: 17 | - pip install hererocks 18 | - hererocks HERE --$LUA --compat $COMPAT --cflags="$CFLAGS" --no-readline --luarocks latest --verbose 19 | - hererocks HERE --show 20 | - source HERE/bin/activate 21 | 22 | install: 23 | - luarocks install luacheck 24 | - luarocks install luacov-coveralls 25 | 26 | script: 27 | - luacheck --codes --std=max *.lua --ignore 211/_ENV 28 | - lua valua-test.lua 29 | 30 | after_success: 31 | - lua -lluacov valua-test.lua 32 | - luacov-coveralls 33 | 34 | notifications: 35 | email: 36 | on_success: change 37 | on_failure: always 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Etiene Dalcol 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Valua - Validation for Lua 2 | 3 | [![Build Status](https://travis-ci.org/sailorproject/valua.svg?branch=master)](https://travis-ci.org/sailorproject/valua) 4 | [![Coverage Status](https://coveralls.io/repos/github/sailorproject/valua/badge.svg?branch=master)](https://coveralls.io/github/sailorproject/valua?branch=master) 5 | 6 | A module for making chained validations. Create your objects, append your tests, use and reuse it! 7 | 8 | Originally bundled with Sailor MVC Web Framework, now released as a separated module. 9 | https://github.com/Etiene/sailor 10 | 11 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. If your value fails a test, it breaks the chain and does not evaluate the rest of it. It returns a boolean and an error string (nil when tests succeeded). 12 | 13 | Valua is also available through luarocks 14 | ```` 15 | luarocks install valua 16 | ```` 17 | 18 | #### Usage 19 | Example 1 - Just create, chain and use: 20 | ```lua 21 | valua:new().type("string").len(3,5)("test string!") -- false, "should have 3-5 characters" 22 | ``` 23 | Example 2 - Create, chain and later use it multiple times: 24 | ```lua 25 | local reusable_validation = valua:new().type("string").len(3,5) 26 | reusable_validation("test string!") -- false, "should have 3-5 characters" 27 | reusable_validation("test!") -- true 28 | ``` 29 | 30 | #### Current validation functions 31 | 32 | * alnum() - 33 | Checks if string is alphanumeric. 34 | * boolean() - 35 | Checks if value is a boolean. 36 | * compare(another_value) - 37 | Checks if value is equal to another value. 38 | * contains(substr) - 39 | Checks if a string contains a substring. 40 | * date() or date(format) - 41 | Checks if a string is a valid date. Default format is UK (dd/mm/yyyy). Also checks for US and ISO formats. 42 | * email() - 43 | Checks if a string is a valid email address. 44 | * empty() - 45 | Checks if a value is empty. 46 | * integer() - 47 | Checks if a number is an integer; 48 | * in_list(list) - 49 | Checks if a value is inside an array. 50 | * len(min,max) - 51 | Checks if a string's length is between min and max. 52 | * match(pattern) - 53 | Checks if a string matches a given pattern. 54 | * max(n) - 55 | Checks if a number is equal or less than n. 56 | * min(n) - 57 | Checks if a number is equal or greater than n. 58 | * not_empty() - 59 | Checks if a value is not empty. 60 | * no_white() - 61 | Checks if a string contains no white spaces. 62 | * number() - 63 | Checks if a value is a number. 64 | * string() - 65 | Checks if a value is a string. 66 | * type(t) - 67 | Checks if a value is of type t. 68 | * optional(t) - 69 | If value is `nil` it would be accepted. If it's not `nil` it would be processed with other chained validation functions as usually done. 70 | 71 | 72 | Copyright (c) 2014 Etiene Dalcol 73 | 74 | http://etiene.net 75 | 76 | http://twitter.com/etiene_d 77 | 78 | License: MIT 79 | 80 | 81 | 82 | Inspired by Respect Validation for PHP 83 | 84 | https://github.com/Respect/Validation 85 | -------------------------------------------------------------------------------- /rockspecs/valua-0.2.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "Valua" 2 | version = "0.2.1-1" 3 | source = { 4 | url = "git://github.com/Etiene/valua", 5 | tag = "v0.2.1" 6 | } 7 | description = { 8 | summary = "Validation for Lua!", 9 | detailed = [[ 10 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. 11 | ]], 12 | homepage = "https://github.com/Etiene/valua", 13 | license = "MIT" 14 | } 15 | dependencies = { 16 | "lua >= 5.1, < 5.3" 17 | } 18 | build = { 19 | type = "builtin", 20 | modules = { 21 | ["valua"] = "valua.lua", 22 | } 23 | } -------------------------------------------------------------------------------- /rockspecs/valua-0.2.1-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "Valua" 2 | version = "0.2.1-1" 3 | source = { 4 | url = "git://github.com/Etiene/valua", 5 | tag = "v0.2.1" 6 | } 7 | description = { 8 | summary = "Validation for Lua!", 9 | detailed = [[ 10 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. 11 | ]], 12 | homepage = "https://github.com/Etiene/valua", 13 | license = "MIT" 14 | } 15 | dependencies = { 16 | "lua >= 5.1, < 5.4" 17 | } 18 | build = { 19 | type = "builtin", 20 | modules = { 21 | ["valua"] = "valua.lua", 22 | } 23 | } -------------------------------------------------------------------------------- /rockspecs/valua-0.2.2-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "valua" 2 | version = "0.2.2-1" 3 | source = { 4 | url = "https://github.com/Etiene/valua/releases/download/0.2.2/valua-0.2.2.tar.gz", 5 | tag = "valua-0.2.2" 6 | } 7 | description = { 8 | summary = "Validation for Lua!", 9 | detailed = [[ 10 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. 11 | ]], 12 | homepage = "https://github.com/Etiene/valua", 13 | license = "MIT" 14 | } 15 | dependencies = { 16 | "lua >= 5.1, < 5.3" 17 | } 18 | build = { 19 | type = "none", 20 | install ={ 21 | lua ={ 22 | valua = "valua.lua" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rockspecs/valua-0.2.2-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "valua" 2 | version = "0.2.2-2" 3 | source = { 4 | url = "git://github.com/Etiene/valua", 5 | tag = "0.2.2" 6 | } 7 | description = { 8 | summary = "Validation for Lua!", 9 | detailed = [[ 10 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. 11 | ]], 12 | homepage = "https://github.com/Etiene/valua", 13 | license = "MIT" 14 | } 15 | dependencies = { 16 | "lua >= 5.1, < 5.4" 17 | } 18 | build = { 19 | type = "none", 20 | install ={ 21 | lua ={ 22 | valua = "valua.lua" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /rockspecs/valua-0.2.2-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "valua" 2 | version = "0.2.2-3" 3 | source = { 4 | url = "https://github.com/sailorproject/valua/releases/download/0.2.2/valua-0.2.2.tar.gz", 5 | tag = "0.2.2" 6 | } 7 | description = { 8 | summary = "Validation for Lua!", 9 | detailed = [[ 10 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. 11 | ]], 12 | homepage = "https://github.com/sailorproject/valua", 13 | license = "MIT" 14 | } 15 | dependencies = { 16 | "lua >= 5.1, < 5.4" 17 | } 18 | build = { 19 | type = "none", 20 | install ={ 21 | lua ={ 22 | valua = "valua.lua" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rockspecs/valua-0.3-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "valua" 2 | version = "0.3-1" 3 | source = { 4 | url = "git://github.com/sailorproject/valua", 5 | tag = "0.3" 6 | } 7 | description = { 8 | summary = "Validation for Lua!", 9 | detailed = [[ 10 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. 11 | ]], 12 | homepage = "https://github.com/sailorproject/valua", 13 | license = "MIT" 14 | } 15 | dependencies = { 16 | "lua >= 5.1, < 5.4" 17 | } 18 | build = { 19 | type = "none", 20 | install ={ 21 | lua ={ 22 | valua = "valua.lua" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rockspecs/valua-current-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "valua" 2 | version = "current-1" 3 | source = { 4 | url = "git://github.com/sailorproject/sailor", 5 | } 6 | description = { 7 | summary = "Validation for Lua!", 8 | detailed = [[ 9 | This module provides tools for validating values, very useful in forms, but also usable elsewhere. It works in appended chains. Create a new validation object and start chaining your test functions. 10 | ]], 11 | homepage = "https://github.com/sailorproject/valua", 12 | license = "MIT" 13 | } 14 | dependencies = { 15 | "lua >= 5.1, < 5.5", 16 | "busted >= 2.0.rc10", 17 | } 18 | build = { 19 | type = "builtin", 20 | modules = { 21 | valua = "valua.lua" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /valua-test.lua: -------------------------------------------------------------------------------- 1 | local v = require "valua" 2 | local passing = true 3 | 4 | local function check(val_test, test_value, expected, n) 5 | local res,err = val_test(test_value) 6 | local msg = "Validation "..tostring(n).." " 7 | 8 | if res == expected then 9 | msg = msg.. "succeeded" 10 | else 11 | passing = false 12 | msg = msg.. " \27[31m FAILED \27[0m" 13 | end 14 | msg = msg.." on '"..(tostring(test_value)).."'. Expected: "..tostring(expected)..", result: "..tostring(res)..". " 15 | print(msg) 16 | if err then print("\tTest Msg: value "..(err or "")) end 17 | end 18 | 19 | local test_values = { 20 | [1] = "test string!", 21 | [2] = "hey", 22 | [3] = "", 23 | [4] = nil, 24 | [5] = true, 25 | [6] = 42, 26 | [7] = 1337, 27 | [8] = '26/10/1980', 28 | [9] = '10-26-1980', 29 | [10] = '29.02.2014', 30 | [11] = '29/02/2016', 31 | [12] = 'a@a.com', 32 | [13] = 'asd123', 33 | [14] = 5.7, 34 | [15] = {}, 35 | [16] = {3,46}, 36 | [17] = "", 37 | [18] = "test-123_maria.2@newdomain.wow.movie", 38 | [19] = "10/06/1980 10:32:10" 39 | } 40 | 41 | local tests = { 42 | {v:new().type("string").len(3,5), {1,false}}, 43 | {v:new().type("number").len(3,5), {1,false}}, 44 | {v:new().type("table").empty(), {15,true, 16,false, 1,false}}, 45 | -- require('mobdebug').start('127.0.0.1') 46 | {v:new().not_empty(), {2,true, 3,false, 4,false, 16,true, 5,true, 6,true}}, 47 | {v:new().len(2,10), {2,true}}, 48 | {v:new().type("number"), {2,false}}, 49 | {v:new().empty(), {3,true, 4,true, 5,false, 6,false}}, 50 | {v:new().boolean(), {1,false, 5,true}}, 51 | {v:new().compare("hey"), {1,false, 2,true}}, 52 | {v:new().number().min(45), {2,false, 6,false, 7,true, 4,false}}, 53 | {v:new().number().max(1009), {7,false, 6,true}}, 54 | {v:new().date(), {9,false, 10,false, 11,true, 8,true}}, 55 | {v:new().date('us'), {8,false, 9,true}}, 56 | {v:new().email(), {13,false, 12,true, 17,false, 18,true}}, 57 | {v:new().in_list({"hey",42}), {12,false, 6,true, 2,true}}, 58 | {v:new().match("^%d+%p%d+%p%d%d%d%d$"), {1,false, 8,true}}, 59 | {v:new().alnum(), {8,false, 13,true}}, 60 | {v:new().integer(), {14,false, 6,true,}}, 61 | {v:new().string(), {14,false, 1,true, 4,false}}, 62 | {v:new().string().alnum(), {6,false}}, 63 | {v:new().contains(" "), {2,false, 1,true}}, 64 | {v:new().no_white(), {1,false, 2,true}}, 65 | {v:new().datetime(), {19,true, 9,false}}, 66 | {v:new().number().min(45).optional(), {2,false, 6,false, 7,true, 4,true}}, 67 | {v:new().number().optional().min(45), {2,false, 6,false, 7,true, 4,true}}, 68 | {v:new().string().optional(), {14,false, 1,true, 4,true}}, 69 | } 70 | 71 | for n,t in ipairs(tests) do 72 | for i = 1, #t[2], 2 do 73 | check(t[1],test_values[t[2][i]],t[2][i+1],n) 74 | end 75 | end 76 | 77 | if not passing then 78 | error('Tests are failing') 79 | end 80 | -------------------------------------------------------------------------------- /valua.lua: -------------------------------------------------------------------------------- 1 | -- Valua 0.2.1 2 | -- Copyright (c) 2014 Etiene Dalcol 3 | -- License: MIT 4 | -- 5 | -- Originally bundled with Sailor MVC Web Framework, now released as a separated module. 6 | -- http://sailorproject.org 7 | -- 8 | -- This module provides tools for validating values, very useful in forms, but also usable elsewhere. 9 | -- It works in appended chains. Create a new validation object and start chaining your test functions. 10 | -- If your value fails a test, it breaks the chain and does not evaluate the rest of it. 11 | -- It returns a boolean and an error string (nil when tests succeeded) 12 | -- 13 | -- Example 1 - Just create, chain and use: 14 | -- valua:new().type("string").len(3,5)("test string!") -- false, "should have 3-5 characters" 15 | -- 16 | -- Example 2 - Create, chain and later use it multiple times: 17 | -- local reusable_validation = valua:new().type("string").len(3,5) 18 | -- reusable_validation("test string!") -- false, "should have 3-5 characters" 19 | -- reusable_validation("test!") -- true 20 | -- 21 | 22 | local tinsert,setmetatable,len,match = table.insert,setmetatable,string.len,string.match 23 | local tonumber,tostring = tonumber,tostring 24 | local next,type,floor,ipairs = next,type,math.floor, ipairs 25 | local unpack = unpack or table.unpack 26 | local pack = table.pack or function(...) return { n = select('#', ...), ... } end 27 | 28 | local _ENV = nil 29 | 30 | local valua = {} 31 | 32 | -- CORE 33 | -- Caution, this is confusing 34 | 35 | -- creates a new validation object, useful for reusable stuff and creating many validation tests at a time 36 | function valua:new(obj) 37 | obj = obj or {} 38 | setmetatable(obj,self) 39 | -- __index will be called always when chaining validation functions 40 | self.__index = function(t,k) 41 | --saves a function named _ with its args in a funcs table, to be used later when validating 42 | return function(...) 43 | local args = pack(...) 44 | if k == 'optional' then 45 | obj.allow_nil = true 46 | else 47 | local f = function(value) return valua['_'..k](value, unpack(args, 1, args.n)) end 48 | tinsert(t.funcs,f) 49 | end 50 | return t 51 | end 52 | end 53 | 54 | -- __call will run only when the value is validated 55 | self.__call = function(t,value) 56 | local res = true 57 | local err = nil 58 | local fres 59 | 60 | if value == nil and t.allow_nil then 61 | return res, err 62 | end 63 | 64 | -- iterates through all chained validations funcs that were packed, passing the value to be validated 65 | for _,f in ipairs(t.funcs) do 66 | fres,err = f(value) 67 | res = res and fres 68 | -- breaks the chain if a test fails 69 | if err then 70 | break 71 | end 72 | end 73 | -- boolean, error message or nil 74 | return res,err 75 | end 76 | obj.funcs = {} 77 | obj.allow_nil = false 78 | return obj 79 | end 80 | -- 81 | 82 | -- VALIDATION FUNCS 83 | -- Add new funcs at will, they all should have the value to be validated as first parameter 84 | -- and their names must be preceded by '_'. 85 | -- For example, if you want to use .custom_val(42) on your validation chain, you need to create a 86 | -- function valua._custom_val(,). Just remember the value var will be known 87 | -- at the end of the chain and the other var, in this case, will receive '42'. You can add multiple other vars. 88 | -- These functions can be called directly (valua._len("test",2,5))in a non-chained and isolated way of life 89 | -- for quick stuff, but chaining is much cooler! 90 | -- Return false,'' if the value fails the test and simply true if it succeeds. 91 | 92 | -- aux funcs 93 | local function empty(v) 94 | return not v or (type(v)=='string' and len(v) == 0) or (type(v)=='table' and not next(v)) 95 | end 96 | -- 97 | 98 | -- String 99 | function valua._len(value,min,max) 100 | local l = len(value or '') 101 | if l < min or l > max then return false,"should have "..tostring(min).."-"..tostring(max).." characters" end 102 | return true 103 | end 104 | 105 | function valua._compare(value,another_value) 106 | if value ~= another_value then return false, "values are not equal" end 107 | return true 108 | end 109 | 110 | function valua._email(value) 111 | if not empty(value) and not value:match("^[%w+%.%-_]+@[%w+%.%-_]+%.%a%a+$") then 112 | return false, "is not a valid email address" 113 | end 114 | return true 115 | end 116 | 117 | function valua._match(value,pattern) 118 | if not empty(value) and not value:match(pattern) then return false, "does not match pattern" end 119 | return true 120 | end 121 | 122 | function valua._alnum(value) 123 | if not empty(value) and value:match("%W") then return false, "constains improper characters" end 124 | return true 125 | end 126 | 127 | function valua._contains(value,substr) 128 | if not empty(value) and not value:find(substr) then return false, "does not contain '"..substr.."'" end 129 | return true 130 | end 131 | 132 | function valua._no_white(value) 133 | if not empty(value) and value:find("%s") then return false, "must not contain white spaces" end 134 | return true 135 | end 136 | -- 137 | 138 | -- Numbers 139 | function valua._min(value,n) 140 | if not empty(value) and value < n then return false,"must be greater than "..tostring(n) end 141 | return true 142 | end 143 | 144 | function valua._max(value,n) 145 | if not empty(value) and value > n then return false,"must not be greater than "..tostring(n) end 146 | return true 147 | end 148 | 149 | function valua._integer(value) 150 | if not empty(value) and floor(tonumber(value)) ~= tonumber(value) then return false, "must be an integer" end 151 | return true 152 | end 153 | -- 154 | 155 | -- Date 156 | 157 | -- Check for a UK date pattern dd/mm/yyyy , dd-mm-yyyy, dd.mm.yyyy 158 | -- or US pattern mm/dd/yyyy, mm-dd-yyyy, mm.dd.yyyy 159 | -- or ISO pattern yyyy/mm/dd, yyyy-mm-dd, yyyy.mm.dd 160 | -- Default is UK 161 | function valua._date(value,format) 162 | local valid = true 163 | if (match(value, "^%d+%p%d+%p%d%d%d%d$")) then 164 | local d, m, y 165 | if format and format:lower() == 'us' then 166 | m, d, y = match(value, "(%d+)%p(%d+)%p(%d+)") 167 | elseif format and format:lower() == 'iso' then 168 | y, m, d = match(value, "(%d+)%p(%d+)%p(%d+)") 169 | else 170 | d, m, y = match(value, "(%d+)%p(%d+)%p(%d+)") 171 | end 172 | d, m, y = tonumber(d), tonumber(m), tonumber(y) 173 | 174 | local dm2 = d*m*m 175 | if d>31 or m>12 or dm2==116 or dm2==120 or dm2==124 or dm2==496 or dm2==1116 or dm2==2511 or dm2==3751 then 176 | -- invalid unless leap year 177 | if not (dm2==116 and (y%400 == 0 or (y%100 ~= 0 and y%4 == 0))) then 178 | valid = false 179 | end 180 | end 181 | else 182 | valid = false 183 | end 184 | if not valid then return false, "is not a valid date" end 185 | return true 186 | end 187 | -- 188 | 189 | -- Datetime 190 | 191 | -- Check for a UK date pattern dd/mm/yyyy hh:mi:ss, dd-mm-yyyy, dd.mm.yyyy 192 | -- or US pattern mm/dd/yyyy, mm-dd-yyyy, mm.dd.yyyy 193 | -- or ISO pattern yyyy/mm/dd, yyyy-mm-dd, yyyy.mm.dd 194 | -- Default is UK 195 | function valua._datetime(value,format) 196 | local valid = true 197 | if (match(value, "^%d+%p%d+%p%d%d%d%d %d%d%p%d%d%p%d%d$")) then 198 | local d, m, y, hh, mm, ss 199 | if format and format:lower() == 'us' then 200 | m, d, y, hh, mm, ss = match(value, "(%d+)%p(%d+)%p(%d+) (%d%d)%p(%d%d)%p(%d%d)") 201 | elseif format and format:lower() == 'iso' then 202 | y, m, d, hh, mm, ss = match(value, "(%d+)%p(%d+)%p(%d+) (%d%d)%p(%d%d)%p(%d%d)") 203 | else 204 | d, m, y, hh, mm, ss = match(value, "(%d+)%p(%d+)%p(%d+) (%d%d)%p(%d%d)%p(%d%d)") 205 | end 206 | d, m, y, hh, mm, ss = tonumber(d), tonumber(m), tonumber(y), tonumber(hh), tonumber(mm), tonumber(ss) 207 | 208 | local dm2 = d*m*m 209 | if d>31 or m>12 or dm2==116 or dm2==120 or dm2==124 or dm2==496 or dm2==1116 or dm2==2511 or dm2==3751 then 210 | -- invalid unless leap year 211 | if not (dm2==116 and (y%400 == 0 or (y%100 ~= 0 and y%4 == 0))) then 212 | valid = false 213 | end 214 | end 215 | 216 | -- time validation 217 | if not (hh >= 0 and hh <= 24) then 218 | valid = false 219 | end 220 | 221 | if not (mm >= 0 and mm <= 60) then 222 | valid = false 223 | end 224 | 225 | if not (ss >= 0 and ss <= 60) then 226 | valid = false 227 | end 228 | 229 | else 230 | valid = false 231 | end 232 | if not valid then return false, "is not a valid datetime" end 233 | return true 234 | end 235 | -- 236 | 237 | -- Abstract 238 | function valua._empty(value) 239 | if not empty(value) then return false,"must be empty" end 240 | return true 241 | end 242 | 243 | function valua._not_empty(value) 244 | if empty(value) then return false,"must not be empty" end 245 | return true 246 | end 247 | 248 | function valua._type(value,value_type) 249 | if type(value) ~= value_type then return false,"must be a "..value_type end 250 | return true 251 | end 252 | 253 | function valua._boolean(value) 254 | if type(value) ~= 'boolean' then return false,"must be a boolean" end 255 | return true 256 | end 257 | 258 | function valua._number(value) 259 | if type(value) ~= 'number' then return false,"must be a number" end 260 | return true 261 | end 262 | 263 | function valua._string(value) 264 | if type(value) ~= 'string' then return false,"must be a string" end 265 | return true 266 | end 267 | 268 | function valua._in_list(value,list) 269 | local valid = false 270 | for _,v in ipairs(list) do 271 | if value == v then 272 | valid = true 273 | break 274 | end 275 | end 276 | if not valid then return false,"is not in the list" end 277 | return true 278 | end 279 | -- 280 | 281 | -- 282 | return valua 283 | --------------------------------------------------------------------------------