Eine kleines Modul, zum fetchen und submitten von Coding Challenges von The Morpheus Tutorials
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

166 lines
3.9 KiB

-- Lua module for coding challenges from Morpheus Tutorials
local time = require('chronos')
local curl = require('lcurl')
-- try to load json.lua or dkjson
local json do
for _, mod in ipairs({ 'json', 'dkjson' }) do
local ok, j = pcall(require, mod)
if ok then
json = j
break
end
end
assert(json, 'json.lua or dkjson is required')
end
local cc = {
_VERSION = '1.2.1',
_DESCRIPTION = 'Lua module for fetching and submitting challenges from The Morpheus coding challenge',
_URL = 'https://git.kokolor.es/imo/coding_challenge_loesung',
_LICENCE = 'The Unlicense'
}
local USERAGENT = ('cc.lua/%s libcurl/%s (%s)')
:format(cc._VERSION, curl.version_info('version'), cc._URL)
local URL = 'https://cc.the-morpheus.de/%s/%d/'
-- private functions
--- build url string
-- url (string)
-- args (string)
local function _build_url(url, args)
if type(args) == 'string' then
return url .. args .. '/'
else
return url
end
end
--- build headers for post request
-- headers (table)
local function _build_headers(headers)
local new_headers = { 'Content-Type: application/json' }
if not headers then return new_headers end
for k, v in pairs(headers) do
table.insert(new_headers, string.format('%s: %s', k, v))
end
return new_headers
end
--- GET request function
-- url (string)
-- nojson (bool)
local function _get(url, nojson)
local queue = {}
curl.easy()
:setopt_url(url)
:setopt(curl.OPT_USERAGENT, USERAGENT)
:setopt_writefunction(function(buf)
table.insert(queue, buf)
end)
:perform()
:close()
if not nojson then
return json.decode(table.concat(queue))
else
return table.concat(queue)
end
end
--- POST request function
-- url (string)
-- data (table)
-- headers (table)
local function _post(url, data, headers)
local jdata = json.encode(data)
local queue = {}
local req = curl.easy()
:setopt_url(url)
:setopt(curl.OPT_USERAGENT, USERAGENT)
:setopt_httpheader(_build_headers(headers))
:setopt_postfields(jdata, #jdata)
:setopt_writefunction(function(buf)
table.insert(queue, buf)
end)
:perform()
local status = req:getinfo(curl.INFO_RESPONSE_CODE)
req:close()
return table.concat(queue), status
end
-- private methods
local CC = {}
--- fetches the challenge
function CC:fetch()
return _get(self.challenges_url, self.nojson)
end
--- coding challenge solve method
-- fn (function) = callback function which solves the challenge
-- submt (bool) = submit the challenge after solving it
-- Returns JSON data as table or plain data if nojson is true
function CC:solve(fn, sbmt)
local challenge = self:fetch()
local start = time.nanotime()
local result = fn(challenge)
table.insert(self.duration, time.nanotime() - start)
if sbmt then return self:submit(result) end
return result
end
--- coding challenge post method
-- data (table) = the solutions data
-- headers (table) = table of custom headers if needed
-- Returns text and status code
function CC:submit(data, headers)
return _post(self.solutions_url, data, headers)
end
--- returns the average time of all runs
function CC:runtime_avg()
local t = 0
for _, v in ipairs(self.duration) do
t = t + v
end
return string.format('%f', t / #self.duration)
end
-- public methods
--- create new coding challenge instance
-- cn (number) = challenge number
-- opts (table) = options
-- opts.nojson (bool) = expects the challenge as plain text if true
-- opts.get_path (string) = path is added to the get url
-- opts.post_path (string) = path is added to the post url
function cc.new(cn, opts)
opts = opts or {}
local obj = {
duration = {},
solutions_url = _build_url(URL:format('solutions', cn), opts.post_path),
challenges_url = _build_url(URL:format('challenges', cn), opts.get_path),
nojson = opts.nojson or false
}
return setmetatable(obj, { __index = CC })
end
return cc