Lua

Tables

Sorting

Create an iterator


function utils.spairs(t, order)
  -- collect the keys
  local keys = {}
  for k in pairs(t) do keys[#keys + 1] = k end

  -- if order function given, sort by it by passing the table and keys a, b,
  -- otherwise just sort the keys
  if order then
    table.sort(keys, function(a, b) return order(t, a, b) end)
  else
    table.sort(keys)
  end

  -- return the iterator function
  local i = 0
  return function()
    i = i + 1
    if keys![](i) then
      return keys![t[keys[i](i])]
    end
  end
end

Example usage (from {mmx}):


local function make_sorted_entry_iterator(entries)
  return utils.spairs(entries, function(es, name_a, name_b)
    local entry_a = es![](name_a)
    local entry_b = es![](name_b)
    if entry_a.date or entry_b.date then
      return (entry_a.date or MIN_DATE) > (entry_b.date or MIN_DATE)
    else
      return name_a < name_b
    end
  end)
end

utils.lua


local utils = {}

-- file io
function utils.file_exists(path)
    local file = io.open(path, "r")
    if file ~= nil then
        file:close()
        return true
    else
        return false
    end
end

function utils.read_file(path)
    local file = io.open(path, "rb") -- r read mode and b binary mode
    if not file then
        error("unable to open file for reading at " .. path)
    end
    local content = file:read "*a" -- *a or *all reads the whole file
    file:close()
    return content
end

function utils.write_file(path, content)
    local file = io.open(path, "w")
    if not file then
        error("unable to open file for writing at " .. path)
    end
    file:write(content)
    file:close()
end

function utils.delete_file(path)
    assert(os.remove(path))
end

function utils.list_folders(directory)
    local pfile = io.popen('cd ' .. directory .. ' && find ' .. directory .. ' -type d')
    if not pfile then
        error("unable to list folders in directory " .. directory)
    end

    local folder_names = {}
    for folder_name in pfile:lines() do
        folder_name = folder_name:sub(#directory + 1)
        if not utils.starts_with(folder_name, '.') and #folder_name > 0 then
            table.insert(folder_names, folder_name)
        end
    end

    pfile:close()
    return folder_names
end

function utils.list_files(directory, extension)
    -- resulting command is:
    -- find [dir] -type f -name "*.[ext]"
    local pfile = io.popen('find -L ' .. directory .. ' -type f -name "*' .. (extension or "") .. '"')
    if not pfile then
        error("unable to list files in directory " .. directory .. " with extension " .. extension)
    end

    local file_names = {}
    for file_name in pfile:lines() do
        file_name = file_name:sub(#directory + 1)
        table.insert(file_names, file_name)
    end

    pfile:close()
    return file_names
end

-- strings

function utils.starts_with(str, start)
    return str:sub(1, #start) == start
end

function utils.ends_with(str, ending)
    return ending == "" or str:sub(-#ending) == ending
end

function utils.lines(str)
    if str:sub(-1) ~= "\n" then
        str = str .. "\n"
    end
    return str:gmatch("(.-)\n")
end

function utils.split(input, sep)
    if sep == nil then
        sep = "%s"
    end
    local t = {}
    for str in string.gmatch(input, "([^" .. sep .. "]+)") do
        table.insert(t, str)
    end
    return t
end

function utils.capitalize(str)
    return (str:gsub("^%l", string.upper))
end

function utils.title_case(str)
    return utils.capitalize(str:gsub(" %l", string.upper))
end

function utils.slugify(str)
    return (str:gsub("[%s%p]", "_")):lower()
end

-- tables

function utils.has_keys(table, keys)
    for _, key in pairs(keys) do
        if table[key] == nil then
            return false
        end
    end

    return true
end

function utils.get_key_case_insensitive(table, key)
    return table[key] or table[utils.capitalize(key)] or table[key:lower()] or table[key:upper()] or
               table[utils.title_case(key)]
end

function utils.spairs(t, order)
    -- collect the keys
    local keys = {}
    for k in pairs(t) do
        keys[#keys + 1] = k
    end

    -- if order function given, sort by it by passing the table and keys a, b,
    -- otherwise just sort the keys
    if order then
        table.sort(keys, function(a, b)
            return order(t, a, b)
        end)
    else
        table.sort(keys)
    end

    -- return the iterator function
    local i = 0
    return function()
        i = i + 1
        if keys[i] then
            return keys[i], t[keys[i]]
        end
    end
end

function utils.dump(o)
    if type(o) == 'table' then
        local s = '{ '
        for k, v in pairs(o) do
            if type(k) ~= 'number' then
                k = '"' .. k .. '"'
            end
            s = s .. '[' .. k .. '] = ' .. utils.dump(v) .. ','
        end
        return s .. '} '
    else
        return tostring(o)
    end
end

-- dates
function utils.today()
    local date_table = os.date("*t")
    local year, month, day = date_table.year, date_table.month, date_table.day -- date_table.wday to date_table.day
    return string.format("%d-%d-%d", year, month, day)
end

function utils.rss_date(date_str)
    local handle = io.popen("date -R -d " .. date_str)
    if not handle then
        error("unable to run command in rss_date")
    end
    local result = handle:read("*a")
    handle:close()
    return result
end

return utils

Compiled 2024-04-21