summaryrefslogtreecommitdiffstats
path: root/acf/error.lua
diff options
context:
space:
mode:
Diffstat (limited to 'acf/error.lua')
-rw-r--r--acf/error.lua97
1 files changed, 97 insertions, 0 deletions
diff --git a/acf/error.lua b/acf/error.lua
new file mode 100644
index 0000000..26dfb86
--- /dev/null
+++ b/acf/error.lua
@@ -0,0 +1,97 @@
+--[[
+Copyright (c) 2012-2013 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+module(..., package.seeall)
+
+local object = require('acf.object')
+local class = object.class
+
+local util = require('acf.util')
+
+require 'json'
+
+
+local function pack(...) return arg end
+
+
+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
+
+
+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
+
+
+ErrorDict = class(ErrorTable)
+
+function ErrorDict:collect(func, ...)
+ local function pack(success, ...)
+ return success, success and arg or arg[1]
+ end
+
+ local success, res = pack(
+ xpcall(
+ function() return func(unpack(arg)) end,
+ function(err)
+ local _, _, data = string.find(err, '.-: (.+)')
+ 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 raise(label, msg)
+ local err = ErrorList(label)
+ err:insert(msg)
+ err:raise()
+end
+
+function relabel(label, ...)
+ local err = ErrorDict()
+ local res = pack(err:collect(unpack(arg)))
+ 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 call(...)
+ local err = ErrorDict()
+ local res = pack(err:collect(unpack(arg)))
+ 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