1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
--[[
Copyright (c) 2012-2014 Kaarle Ritvanen
See LICENSE file for license details
--]]
local M = {}
local object = require('aconf.object')
local class = object.class
local util = require('aconf.util')
local json = require('cjson')
local ErrorTable = class()
function ErrorTable:init() self.errors = {} end
function ErrorTable:success() return not next(self.errors) end
function ErrorTable:raise()
if not self:success() then error(json.encode(self.errors)) end
end
local ErrorList = class(ErrorTable)
function ErrorList:init(label)
object.super(self, ErrorList):init()
self.label = label
end
function ErrorList:insert(msg)
table.insert(util.setdefault(self.errors, self.label, {}), msg)
end
M.ErrorDict = class(ErrorTable)
function M.ErrorDict:collect(func, ...)
local function pack(success, ...)
local arg = {...}
return success, success and arg or arg[1]
end
local arg = {...}
local success, res = pack(
xpcall(
function() return func(unpack(arg)) end,
function(err)
local _, _, data = err:find('.-: (.+)')
local success, res = pcall(json.decode, data)
if success and type(res) == 'table' then return res end
return data..'\n'..debug.traceback()
end
)
)
if success then return unpack(res) end
if type(res) == 'table' then
for label, errors in pairs(res) do
for _, err in ipairs(errors) do
table.insert(util.setdefault(self.errors, label, {}), err)
end
end
else error(res) end
end
function M.raise(label, msg)
local err = ErrorList(label)
err:insert(msg)
err:raise()
end
function M.relabel(label, ...)
local err = M.ErrorDict()
local res = {err:collect(...)}
if err:success() then return unpack(res) end
elist = ErrorList(label)
for lbl, el in pairs(err.errors) do
for _, e in ipairs(el) do elist:insert(lbl..': '..e) end
end
elist:raise()
end
function M.call(...)
local err = M.ErrorDict()
local res = {err:collect(...)}
if err:success() then return true, unpack(res) end
if err.errors.system then error(err.errors.system[1]) end
return false, err.errors
end
return M
|