--[[ 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(table.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 table.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 table.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, table.unpack(res) end if err.errors.system then error(err.errors.system[1]) end return false, err.errors end return M