Initial commit 🎉

* Extracted core module and default loaders from Restia
* Set up luarocks
* Set up busted, luacheck and luacov
This commit is contained in:
Talia 2022-08-09 21:23:21 +02:00
commit 66e459225f
15 changed files with 284 additions and 0 deletions

5
.busted Normal file
View file

@ -0,0 +1,5 @@
return {
_all = {
lpath = "?.lua;?/init.lua"
}
}

3
config.ld Normal file
View file

@ -0,0 +1,3 @@
readme = 'readme.md'
format = 'discount'
file = { 'glass.lua', 'glass' }

27
glass-dev-1.rockspec Normal file
View file

@ -0,0 +1,27 @@
package = "glass"
version = "dev-1"
source = {
url = "git+https://github.com/darkwiiplayer/glass"
}
description = {
homepage = "https://github.com/darkwiiplayer/glass",
license = "Unlicense"
}
dependencies = {
"lfs"
}
build = {
type = "builtin",
modules = {
glass = "glass.lua",
["glass.cosmo"] = "glass/cosmo.lua",
["glass.discount"] = "glass/discount.lua",
["glass.json"] = "glass/json.lua",
["glass.lua"] = "glass/lua.lua",
["glass.moonhtml"] = "glass/moonhtml.lua",
["glass.moonhtml_cosmo"] = "glass/moonhtml_cosmo.lua",
["glass.raw"] = "glass/raw.lua",
["glass.skooma"] = "glass/skooma.lua",
["glass.yaml"] = "glass/yaml.lua"
}
}

51
glass.lua Normal file
View file

@ -0,0 +1,51 @@
--- Loads configurations from files on demand.
-- @author DarkWiiPlayer
-- @license Unlicense
local lfs = require 'lfs'
local config = {}
local __metatable = {}
function __metatable:__index(index)
if type(index)~="string" then return nil end
local path = self.__dir..'/'..index
local attributes = lfs.attributes(path)
if attributes and attributes.mode=='directory' then
return config.bind(path, self.__loaders)
else
for _, loader in ipairs(self.__loaders) do
local result = loader(path)
if result then
rawset(self, index, result)
return result
end
end
return nil, "Could not load: "..tostring(index)
end
end
--- Binds a table to a config directory.
-- The returned table maps keys to configurations, which are handled by
-- different "loaders". loaders are handlers that try loading a config entry in
-- a certain format and are tried sequentially until one succeeds. If no
-- loader matches, nil is returned.
-- @tparam string dir Path to the directory to look in.
-- @tparam table loaders A table of loaders to use when attempting to load a configuration entry.
-- @treturn table config A table that maps to the config directory
-- @usage
-- local config = glass.bind 'configurations'
-- main_config.foo.bar
-- -- Loads some file like foo.json or foo.yaml
-- -- in the configurations directory
function config.bind(dir, loaders)
if type(dir)~="string" then
error(string.format("bad argument #1 to '%s' (string expected, got %s)", debug.getinfo(1).name, type(loaders)), 2)
end
if type(loaders)~="table" then
error(string.format("bad argument #2 to '%s' (table expected, got %s)", debug.getinfo(1).name, type(loaders)), 2)
end
return setmetatable({__dir=dir, __loaders=loaders}, __metatable)
end
return config

19
glass/cosmo.lua Normal file
View file

@ -0,0 +1,19 @@
--- Loader for cosmo templates.
-- @module restia.config.cosmo
local cosmo = require 'cosmo'
local readfile = require 'restia.config.readfile'
--- Loads a cosmo template from a file and returns the compiled template.
-- Returns nil if no template can be found.
-- @treturn function Template
-- @function load
return function(name)
name = tostring(name) .. '.cosmo'
local text = readfile(name)
if text then
return assert(cosmo.compile(text, name))
else
return nil
end
end

23
glass/discount.lua Normal file
View file

@ -0,0 +1,23 @@
--- Loader for markdown files using lua-discount
-- @module restia.config.discount
local discount = require 'discount'
--- Loads a markdown file and converts it into HTML.
-- Returns a function that returns a static string
-- to keep compatible with restia template semantics.
-- HTML-Conversion only happens once during loading.
-- @treturn function Template
-- @function load
return function(name)
name = tostring(name) .. '.md'
local file = io.open(name)
if file then
local html = discount(file:read("*a"))
return function()
return html
end
else
return nil
end
end

18
glass/json.lua Normal file
View file

@ -0,0 +1,18 @@
--- Loader for JSON-Data using Lua-CJSON
-- @module restia.config.json
local json = require 'cjson'
local readfile = require 'restia.cofnig.readfile'
--- Loads a JSON-File and returns a corresponding Lua table.
-- May return non-table values for invalid JSON,
-- as CJSON supports other types than Object at
-- the top-level of the JSON file.
-- @treturn table JSON-Data
-- @function load
return function(file)
local raw = readfile(file..'.json')
if raw then
return json.decode(raw)
end
end

13
glass/lua.lua Normal file
View file

@ -0,0 +1,13 @@
--- Loader for Lua files
-- @module restia.config.lua
--- Loads and compiles a Lua file and runs it.
-- Returns the result of running the Lua file.
-- If running the code immediately is not desired,
-- it has to be returned as a function.
-- @return The result of the Lua file after running it
-- @function load
return function(name)
local f = loadfile(name..'.lua')
return f and f() or nil
end

18
glass/moonhtml.lua Normal file
View file

@ -0,0 +1,18 @@
--- Loader for MoonHTML files
-- @module restia.config.moonhtml
local template = require 'restia.template'
--- Loads and compiles a moonhtml template.
-- @treturn function template
-- @function load
return function(name)
name = tostring(name) .. '.moonhtml'
local file = io.open(name)
if file then
return assert(template.loadmoon(file:read("*a"), name))
else
return nil
end
end

13
glass/raw.lua Normal file
View file

@ -0,0 +1,13 @@
--- Loader for plain files
-- @module restia.config.readfile
--- Loads a normal file as a string.
-- @treturn string The content of the file
-- @function load
return function(path)
local f = io.open(path)
if not f then return end
local result = f:read("*a")
f:close()
return result
end

18
glass/skooma.lua Normal file
View file

@ -0,0 +1,18 @@
--- Loader for Skooma templates
-- @module restia.config.skooma
local skooma = require 'skooma'
--- Loads a Lua file with the Skooma environment and runs it.
-- Normally, the file should return a function
-- to follow restia template semantics.
-- @return The result of the template file.
-- @function load
return function(name)
name = tostring(name)..'.skooma'
local template = loadfile(name, "tb", skooma.default)
template = template and template()
if template then
return template
end
end

18
glass/yaml.lua Normal file
View file

@ -0,0 +1,18 @@
--- Loader for YAML-Data using Lua-CYAML
-- @module restia.config.yaml
local yaml = require 'lyaml'
local readfile = require 'restia.config.readfile'
--- Loads a YAML-File and returns a corresponding Lua table.
-- May return non-table values for invalid YAML,
-- as CYAML supports other types than Object at
-- the top-level of the YAML file.
-- @treturn table YAML-Data
-- @function load
return function(file)
local raw = readfile(file..'.yml') or readfile(file..'.yaml')
if raw then
return yaml.load(raw)
end
end

22
license Normal file
View file

@ -0,0 +1,22 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

33
readme.md Normal file
View file

@ -0,0 +1,33 @@
# Glass
Makes your configs (almost) see-through.
## About
Glass is a Lua library that makes it easy to lazy-load configuration files into a Lua table at runtime. Its main purpose is to make accessing different configuration files "transparent" to the programmer.
## Example
Assume the file `app/config/settings.json` exists in your project directory with the content `{"user":{"name":"User"}}`
```lua
local glass = require 'glass'
local config = glass.bind('app/config', {
(require 'glass.json');
})
print(config.settings.user.name) -- prints "User"
```
## How it Works
A glass loader is initialised with a list of loaders and will try each of them in order in its `__index` metamethod. The first loader that is able to fetch the wanted configuration will be used.
## Loaders
Glass offers the following loaders out of the box:
* `cosmo` loads cosmo templates
* `discount` loads markdown files\*.
* `json` loads a JSON file as a Lua table.
* `lua` loads and executes a Lua file.
* `moonhtml` loads a MoonHTML template and returns it as a function.
* `readfile` loads a file as a string.
* `skooma` loads a skooma template and returns it as a function.
* `yaml` loads a YAML file as a Lua table.
\* For easier interoperability with other template loaders, the `discount` loader returns a static function which can be called to return the generated HTML. The markdown file is only parsed the first time.

3
spec/core_spec.moon Normal file
View file

@ -0,0 +1,3 @@
describe 'core module', ->
pending 'works as intended', ->
-- TODO: Write some tests