Merge commit '311e43ecc1b436465ea56bfc2c31799a42f3214d' as 'utility'

This commit is contained in:
Paul Liverman III 2018-03-13 02:10:39 -07:00
commit a647b8f501
12 changed files with 350 additions and 0 deletions

1
utility/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.lua

21
utility/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Paul Liverman III
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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 OR COPYRIGHT HOLDERS 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.

30
utility/calc.moon Normal file
View File

@ -0,0 +1,30 @@
import bytes from require "resty.random"
import byte from string
import floor from math
-- return a random number between min/max
random = (min, max) ->
unless max
max = min or 1
min = 0
a, b = byte bytes(2), 1, 2
c, d = byte bytes(2), 1, 2
value = a + b * 256 + c * 65536 + d * 16777216 -- 0 to 4294967296
range = max - min
if max == floor(max) and min == floor(min)
return floor value * range / 4294967296 + min
else
return value * range / 4294967296 + min
-- map a value within a range of numbers to another range
map = (min1, max1, value, min2, max2) ->
range1 = max1 - min1
range2 = max2 - min2
return ((value - min1) * range2 / range1) + min2
{
:random
:map
}

36
utility/datetime.moon Normal file
View File

@ -0,0 +1,36 @@
import date, time from os
-- for database
now = ->
return date "!%Y-%m-%d %X"
-- database date -> display
pretty_date = (str) ->
year, month, day = str\match "(%d%d%d%d)-(%d%d)-(%d%d)"
return date "%B %d, %Y", time :year, :month, :day
-- from database
to_seconds = (str) ->
year, month, day, hour, min, sec = str\match "(%d%d%d%d)-(%d%d)-(%d%d) (%d%d):(%d%d):(%d%d)"
return time :year, :month, :day, :hour, :min, :sec
-- seconds -> for database
for_db = (seconds) ->
return date "!%Y-%m-%d %X", seconds
gmt_date = ->
return date "!*t"
gmt_time = ->
return time date "!*t"
{
none: "1970-01-01 00:00:00" -- TODO deprecate
zero: "1970-01-01 00:00:00" -- for use in database
:now
:pretty_date
:to_seconds
:for_db
:gmt_date
:gmt_time
}

9
utility/db.moon Normal file
View File

@ -0,0 +1,9 @@
escape_similar_to = (str) ->
-- matches any of %_\|*+?{}()[]
-- puts a backslash in front of them
str = str\gsub "[%%_\\|%*%+%?{}%(%)%[%]]", "\\%1"
return str -- return on seperate line to avoid returning 2nd value from gsub
{
:escape_similar_to
}

10
utility/fs.moon Normal file
View File

@ -0,0 +1,10 @@
exists = (file_path) ->
handle = io.open file_path, "r"
if handle
handle\close!
return true
return false
{
:exists
}

59
utility/gstring.moon Normal file
View File

@ -0,0 +1,59 @@
import insert, sort, concat from table
import sub, len from string
-- splits string by newline into array of strings
lines = (str) ->
tab = {}
for line in str\gmatch "[^\n]+"
insert tab, line
return tab
-- splits string by spaces into a table of strings
-- (handles bad spacing and duplicate substrings)
split = (str) ->
tab1, tab2 = {}, {}
for word in str\gmatch "%S+"
tab1[word] = true
for word in pairs tab1
insert tab2, word
return tab2
-- splits string by commas into a table of strings
-- (expects a well-formated string!)
comma_split = (str) ->
tab = {}
for word in str\gmatch "[^,]+"
insert tab, word
return tab
-- bool: does str1 start with str2
starts = (str1, str2) ->
return str2 == sub str1, 1, len str2
-- takes space-separated string and puts it in alphabetical order
-- (handles weird spacing, returns with single-spacing)
alphabetize = (str) ->
tab = split str
sort tab
return concat tab, " "
-- takes space-separated string and removes duplicate entries from it
remove_duplicates = (str) ->
strings = split str
tab, result = {}, {}
for str in *strings
tab[str] = true
for str in pairs tab
insert result, str
return concat result, " "
{
:lines
:split
:comma_split
:starts
:alphabetize
:remove_duplicates
}

33
utility/gtable.moon Normal file
View File

@ -0,0 +1,33 @@
-- appends n arrays to the end of the first array
append = (tab1, ...) ->
for n = 1, select "#", ...
tab2 = select n, ...
for i = 1, #tab2
tab1[#tab1+1] = tab2[i]
return tab1
-- returns a new table shallow copying data from all arguments
-- later arguments overwrite any keys in earlier arguments
-- ignores non-table arguments (skipping them)
shallow_copy = (...) ->
new = {}
for n = 1, select "#", ...
tab = select n, ...
if "table" == type tab
for k,v in pairs tab
new[k] = v
return new
-- returns a new table with flipped keys and values
invert = (tab) ->
new = {}
for key, value in pairs tab
new[value] = key
return new
{
:append
:shallow_copy
shallow_merge: shallow_copy -- TODO deprecate
:invert
}

13
utility/migrations.moon Normal file
View File

@ -0,0 +1,13 @@
import create_table, types, create_index from require "lapis.db.schema"
{
[1518948992]: =>
create_table "settings", {
{"name", types.varchar primary_key: true, unique: true}
{"value", types.text null: true}
{"created_at", types.time}
{"updated_at", types.time}
}
create_index "settings", "name", unique: true
}

View File

@ -0,0 +1,5 @@
import Model from require "lapis.db.model"
class Settings extends Model
@timestamp: true
@primary_key: "name"

110
utility/settings.moon Normal file
View File

@ -0,0 +1,110 @@
import Settings from require "models"
totype = (str) ->
if value = tonumber str
return value
if str == "true"
return true
if str == "false"
return false
if str == "nil"
return nil
return str
cache = {}
get = (name, create=true) ->
setting = cache[name]
unless setting
setting = Settings\find :name
if (not setting) and create
setting = Settings\create :name
cache[name] = setting
if setting
return setting
else
return nil, "failed to load '#{name}' setting"
local settings
settings = {
get: (name, skip_index) ->
unless name
return settings.load!
unless skip_index -- for metamethods to not loop endlessly
return settings[name] if settings[name]
setting, err = get name
if setting
value = totype setting.value
settings[name] = value
return value
else
return nil, err
set: (name, value) ->
unless name
return settings.save!
setting, err = get name
if setting
settings[name] = value
return setting\update value: tostring value
else
return nil, err
save: (name) ->
if name
setting, err = get name
if setting
return setting\update value: tostring settings[name]
else
return nil, err
else
for name, value in pairs settings
switch name
when "get", "set", "save", "load", "delete"
nil
else
t = type value
if t == "function" or t == "table"
return nil, "cannot save '#{name}' setting, type '#{t}' not supported"
else
unless cache[name]
cache[name] = Settings\find :name
unless cache[name]
cache[name] = Settings\create :name
for name, setting in pairs cache
_, err = setting\update value: tostring settings[name]
return nil, err if err
return true
load: (name) ->
return settings.get name if name
all_settings = Settings\select "WHERE true"
for setting in *all_settings
name = setting.name
cache[name] = setting
settings[name] = totype setting.value
return settings
delete: (name) ->
if setting = get name, false
if setting\delete!
cache[name] = nil
settings[name] = nil
else
return nil, "failed to delete '#{name}' setting"
return true
}
return setmetatable settings, {
__call: (t, name) ->
return settings.get name, true
__index: (t, name) ->
return settings.get name, true
}

23
utility/shell.moon Normal file
View File

@ -0,0 +1,23 @@
quote = (str) ->
escaped = str\gsub "'", [['"'"']]
return "'#{escaped}'"
execute = (cmd, capture_exit_code=true) ->
local handle
if capture_exit_code
handle = io.popen "#{cmd}\necho $?"
else
handle = io.popen cmd
result = handle\read "*a"
handle\close!
exit_start, exit_end = result\find "(%d*)[%c]$"
exit_code = tonumber result\sub(exit_start, exit_end)\sub 1, -2
output = result\sub 1, exit_start - 1
return exit_code, output
{
:quote
:execute
}