Compare commits

...

4 Commits

Author SHA1 Message Date
perro tuerto d8e6f97cb6 Autoformat 2023-07-01 10:05:59 -07:00
perro tuerto 8584ecb992 Come on, versioning! 2023-06-16 19:54:05 -07:00
perro tuerto 6680e253c9 Ups 2023-06-16 19:49:12 -07:00
perro tuerto cad8807753 Finally a more reliable way to extend functions 2023-06-16 19:39:17 -07:00
3 changed files with 126 additions and 102 deletions

View File

@ -1,11 +1,30 @@
# Lua Dog
Adds functions to Lua Standard Libraries.
Adds functions to Lua Standard Libraries and Pandoc Library.
## Install
luarocks install lua-dog
## Usage
You can use Lua Dog in 2 ways.
The laziest way is:
local dog = require("dog")
dog.import()
-- Lua Dog 'dog.os.uname()' function was imported as 'os.uname()'
os.uname()
This will import all Lua Dog functions to the Lua Standard Libraries and Pandoc Library.
If you prefer not to import, the way is:
require "dog"
-- Lua Dog 'dog.os.uname()' function was NOT imported as 'os.uname()'
dog.os.uname()
## Functions
Check `src`.

View File

@ -1,12 +1,13 @@
package = "lua-dog"
version = "1.0-0"
version = "1.1.0-1"
source = {
url = "https://gitlab.com/perritotuerto/codigo/lua-dog/-/archive/v1.0.0/lua-dog-v1.0.0.tar.gz",
url = "https://gitlab.com/perritotuerto/codigo/lua-dog/-/archive/v" ..
version .. "/lua-dog-v" .. version .. ".tar.gz",
}
description = {
summary = "Lua extensions for lazy dogs",
detailed = [[
Adds functions to Lua Standard Libraries.
Extends Lua Standard Libraries and Pandoc Library.
]],
homepage = "https://gitlab.com/perritotuerto/codigo/lua-dog/",
license = "GPLv3",

View File

@ -1,8 +1,39 @@
-- Variable for storing all the functions
local dog = {}
-- Functions are divided according to the standard library to extend
dog.io = {}
dog.os = {}
dog.string = {}
dog.utf8 = {}
-- Imports dog functions to _G
-- Allows using the other functions without a prefix, i.e.:
-- dog.os.uname() => os.uname()
function dog.import()
local msg = "[WARNING] [DOG] "
msg = msg .. "Ignoring import: '@1' already exists; use '@2' instead"
for libkey, dogfns in pairs(dog) do
local lib = _G[libkey]
if type(dogfns) == "table" then
for fnkey, fn in pairs(dogfns) do
if not lib[fnkey] then
lib[fnkey] = fn
else
local name = libkey .. "." .. fnkey .. "()"
msg = msg:gsub("@1", name):gsub("@2", "dog." .. name)
print(msg)
end
end
end
end
end
-- Tries popen
-- @param ... string: Chunks for popen
-- @return boolean, string: Status and output of popen
function io.try(...)
local cmd = table.concat({...}, " ") .. " 2>&1"
function dog.io.try(...)
local cmd = table.concat({ ... }, " ") .. " 2>&1"
local handle = io.popen(cmd)
local output = handle:read("*a")
local status = (handle:close() ~= nil and true or false)
@ -12,13 +43,13 @@ end
-- Gets OS short name
-- It is just intented to know if it is Linux, macOS or Windows.
-- @return string: "linux" or "bsd" or "macos" or "windows"
function os.uname()
local status, output = io.try("uname")
function dog.os.uname()
local status, output = dog.io.try("uname")
if status then
output = output:gsub(" .*", ""):lower()
if output ~= "linux" and output:match("bsd") ~= nil then
return "bsd"
elseif out ~= "linux" then
elseif output ~= "linux" then
return "macos"
end
return "linux"
@ -28,84 +59,60 @@ end
-- Checks if OS is windows
-- @return boolean: Windows or not
function os.iswin()
return os.uname() == "windows"
end
function dog.os.iswin() return dog.os.uname() == "windows" end
-- Checks if OS is Unix
-- @return boolean: Unix or not
function os.isunix()
return os.uname() ~= "windows"
end
function dog.os.isunix() return dog.os.uname() ~= "windows" end
-- Gets OS language
-- @return string, string, string: Language, locale and encoding
function os.lang()
function dog.os.lang()
local lang = os.getenv("LANG")
if lang ~= nil then
return lang:match("(%w%w)_?(%w?%w?)%.?(.*)")
end
if lang ~= nil then return lang:match("(%w%w)_?(%w?%w?)%.?(.*)") end
return "en", "US", "UTF-8"
end
-- Gets an equivalency table between ASCII and Unicode
-- Note: filled on demand.
-- @return table: ASCII-Unicode table equivalency
function utf8.table()
return {
["a"] = {"á", "à", "ä"},
["e"] = {"é", "è", "ë"},
["i"] = {"í", "ì", "ï"},
["o"] = {"ó", "ò", "ö"},
["u"] = {"ú", "ù", "ü"},
["n"] = {"ñ"},
}
end
-- Checks if string is empty
-- @return boolean: Empty or not
function string:isempty()
return self == ''
end
function dog.string.isempty(str) return str == "" end
-- Changes newlines so everything is in one line
-- @return string: String with formatted newlines as literal "\n"
function string:linearize()
return self:gsub("\n", "\\n")
end
function dog.string.linearize(str) return str:gsub("\n", "\\n") end
-- Normalizes string
-- @return string: Normalized string
function string:normalize()
self = self:lower()
for newchar, chars in pairs(utf8.table()) do
function dog.string.normalize(str)
str = str:lower()
for newchar, chars in pairs(dog.utf8.table()) do
for _, oldchar in ipairs(chars) do
self = self:gsub(oldchar, newchar)
str = str:gsub(oldchar, newchar)
end
end
return self
return str
end
-- Adds indent
-- @param num number: Indent size, 2 by default
-- @param char string: Indent character, space by default
-- @return strin: Indented string
function string:indent(num, char)
function dog.string.indent(str, num, char)
num = num or 2
char = char or " "
char = string.rep(char, num)
return char .. self:gsub("\n", "\n" .. char)
return char .. str:gsub("\n", "\n" .. char)
end
-- Splits the string
-- Note: only support splitting by one character.
-- Could be solved by slicing with find.
-- Could be solved by slicing with find.
-- @param sep string: String separator, space by default
-- @return table: String matches
function string:split(sep)
function dog.string.split(str, sep)
sep = sep or "%s+"
local parts = {}
for part in self:gmatch("([^" .. sep .. "]+)") do
for part in str:gmatch("([^" .. sep .. "]+)") do
table.insert(parts, part)
end
return parts
@ -113,52 +120,42 @@ end
-- Removes spaces at the beginning of the string
-- @return string: Left stripped string
function string:lstrip()
return self:gsub("^%s+", "")
end
function dog.string.lstrip(str) return str:gsub("^%s+", "") end
-- Removes spaces at the end of the string
-- @return string: Right stripped string
function string:rstrip()
return self:gsub("%s+$", "")
end
function dog.string.rstrip(str) return str:gsub("%s+$", "") end
-- Removes spaces at the beginning and at the end of the string
-- @return string: Stripped string
function string:strip()
self = self:lstrip():rstrip()
return self
function dog.string.strip(str)
str = dog.string.lstrip(str)
return dog.string.rstrip(str)
end
-- Alias of strip
function string:trim()
return self:strip()
end
function dog.string.trim(str) return dog.string.strip(str) end
-- The following are heavily influenced by Python pathlib
-- Check: https://docs.python.org/3/library/pathlib.html
-- Checks if string is a file or a directory
-- @return boolean: Exists or not
function string:exists()
return os.rename(self, self) ~= nil
end
function dog.string.exists(str) return os.rename(str, str) ~= nil end
-- Checks if string is a file
-- @return boolean: File or not
function string:isfile()
if self:exists() then
return io.open(self, "a+") ~= nil
end
function dog.string.isfile(str)
if dog.string.exists(str) then return io.open(str, "a+") ~= nil end
return false
end
-- Checks if string is a directory
-- @return boolean: Directory or not
function string:isdir()
if self:exists() then
return io.open(self, "a+") == nil
elseif self == "." or self == ".." then
function dog.string.isdir(str)
if dog.string.exists(str) then
return io.open(str, "a+") == nil
elseif str == "." or str == ".." then
return true
end
return false
@ -166,18 +163,16 @@ end
-- Reads file content as string
-- @return string or nil: File as string or nil
function string:readtext()
if self:exists() then
return io.open(self):read("*a")
end
function dog.string.readtext(str)
if dog.string.exists(str) then return io.open(str):read("*a") end
end
-- Read file content as lines
-- @return table: Table of file lines or nil
function string:readlines()
function dog.string.readlines(str)
local lines = {}
if self:exists() then
for line in io.open(self):lines() do
if dog.string.exists(str) then
for line in io.open(str):lines() do
table.insert(lines, line)
end
end
@ -186,15 +181,13 @@ end
-- Gets file without suffix
-- @return string: File wihtout suffix
function string:stem()
return self:gsub("%.%a+$", "")
end
function dog.string.stem(str) return str:gsub("%.%a+$", "") end
-- Gets file extensions
-- @return table: List of file extensions
function string:suffixes()
function dog.string.suffixes(str)
local suffixes = {}
for suffix in self:gmatch("%.%a+") do
for suffix in str:gmatch("%.%a+") do
table.insert(suffixes, suffix)
end
return suffixes
@ -202,19 +195,30 @@ end
-- Gets file final extension
-- @return string: Final file extension
function string:suffix()
local suffixes = self:suffixes()
if suffixes[#suffixes] then
return suffixes[#suffixes]
end
function dog.string.suffix(str)
local suffixes = str:suffixes()
if suffixes[#suffixes] then return suffixes[#suffixes] end
return ""
end
-- Requires Pandoc
-- Gets an equivalency table between ASCII and Unicode
-- Note: filled on demand.
-- @return table: ASCII-Unicode table equivalency
function dog.utf8.table()
return {
["a"] = { "á", "à", "ä" },
["e"] = { "é", "è", "ë" },
["i"] = { "í", "ì", "ï" },
["o"] = { "ó", "ò", "ö" },
["u"] = { "ú", "ù", "ü" },
["n"] = { "ñ" },
}
end
-- Extends Pandoc Library
-- Check: https://pandoc.org/lua-filters.html#module-pandoc
if pandoc ~= nil then
-- Gets file extension namespace
-- Check: https://pandoc.org/MANUAL.html#general-options
-- If suffix is 'md' or empty, the default is markdown.
@ -222,8 +226,8 @@ if pandoc ~= nil then
-- @param file string: File name
-- @return string: File extension according to Pandoc format namespaces
function pandoc.getext(file)
local ext = file:suffix():gsub("^.", "")
return ((ext == "md" or ext:isempty()) and "markdown" or ext)
local ext = dog.string.suffix(file):gsub("^.", "")
return ((ext == "md" or dog.string.isempty(ext)) and "markdown" or ext)
end
-- Pandoc converter
@ -237,9 +241,10 @@ if pandoc ~= nil then
-- @return string: Output file content
function pandoc.convert(ifile, oformat, ofile, iformat)
iformat = (iformat == nil and pandoc.getext(ifile) or iformat)
local doc = pandoc.write(pandoc.read(ifile:readtext(), iformat), oformat)
local itext = pandoc.read(dog.string.readtext(ifile), iformat)
local doc = pandoc.write(itext, oformat)
if ofile ~= nil then
local eol = (os:isunix() and "\n" or "\r\n")
local eol = (dog.os:isunix() and "\n" or "\r\n")
io.open(ofile, "w"):write(doc, eol):close()
end
return doc
@ -248,10 +253,10 @@ if pandoc ~= nil then
-- Stringifies Pandoc content
-- Avoids undesired behavios of pandoc.utils.stringify, such as quotes and
-- backslashes conversions.
-- @param content pandoc.MetaValue: Pandoc content value
-- @param content pandoc.MetaValue: Pandoc content value
-- @return string: Pandoc stringified value
function pandoc.utils.rawstringify(content)
return pandoc.utils.stringify(content:walk {
return pandoc.utils.stringify(content:walk({
Plain = function(plain)
table.insert(plain.content, pandoc.Space())
return plain
@ -263,11 +268,9 @@ if pandoc ~= nil then
RawInline = function(rawinline)
return pandoc.Str(rawinline.text:gsub("\\n", "\n"):gsub("\\t", "\t"))
end,
SoftBreak = function(softbreak)
return pandoc.Str("\n")
end,
SoftBreak = function(_) return pandoc.Str("\n") end,
Inline = function(inline) return pandoc.utils.stringify(inline) end,
})
}))
end
-- Converts pandoc.Meta to table
@ -293,5 +296,6 @@ if pandoc ~= nil then
end
return newmeta
end
end
return dog