From 311e43ecc1b436465ea56bfc2c31799a42f3214d Mon Sep 17 00:00:00 2001 From: Paul Liverman III Date: Tue, 13 Mar 2018 02:10:39 -0700 Subject: [PATCH] Squashed 'utility/' content from commit 3616fc8 git-subtree-dir: utility git-subtree-split: 3616fc80e5a6f6a0739d931118b7f5f3b0efa28e --- .gitignore | 1 + LICENSE | 21 +++++++++ calc.moon | 30 ++++++++++++ datetime.moon | 36 ++++++++++++++ db.moon | 9 ++++ fs.moon | 10 ++++ gstring.moon | 59 +++++++++++++++++++++++ gtable.moon | 33 +++++++++++++ migrations.moon | 13 +++++ models/Settings.moon | 5 ++ settings.moon | 110 +++++++++++++++++++++++++++++++++++++++++++ shell.moon | 23 +++++++++ 12 files changed, 350 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 calc.moon create mode 100644 datetime.moon create mode 100644 db.moon create mode 100644 fs.moon create mode 100644 gstring.moon create mode 100644 gtable.moon create mode 100644 migrations.moon create mode 100644 models/Settings.moon create mode 100644 settings.moon create mode 100644 shell.moon diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d907c43 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.lua diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..29fad8e --- /dev/null +++ b/LICENSE @@ -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. diff --git a/calc.moon b/calc.moon new file mode 100644 index 0000000..4dbc5a3 --- /dev/null +++ b/calc.moon @@ -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 +} diff --git a/datetime.moon b/datetime.moon new file mode 100644 index 0000000..c256061 --- /dev/null +++ b/datetime.moon @@ -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 +} diff --git a/db.moon b/db.moon new file mode 100644 index 0000000..7342b2e --- /dev/null +++ b/db.moon @@ -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 +} diff --git a/fs.moon b/fs.moon new file mode 100644 index 0000000..0901125 --- /dev/null +++ b/fs.moon @@ -0,0 +1,10 @@ +exists = (file_path) -> + handle = io.open file_path, "r" + if handle + handle\close! + return true + return false + +{ + :exists +} diff --git a/gstring.moon b/gstring.moon new file mode 100644 index 0000000..a8f0a6c --- /dev/null +++ b/gstring.moon @@ -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 +} diff --git a/gtable.moon b/gtable.moon new file mode 100644 index 0000000..f9b9505 --- /dev/null +++ b/gtable.moon @@ -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 +} diff --git a/migrations.moon b/migrations.moon new file mode 100644 index 0000000..21cad91 --- /dev/null +++ b/migrations.moon @@ -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 +} diff --git a/models/Settings.moon b/models/Settings.moon new file mode 100644 index 0000000..25ae17b --- /dev/null +++ b/models/Settings.moon @@ -0,0 +1,5 @@ +import Model from require "lapis.db.model" + +class Settings extends Model + @timestamp: true + @primary_key: "name" diff --git a/settings.moon b/settings.moon new file mode 100644 index 0000000..d2ff831 --- /dev/null +++ b/settings.moon @@ -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 + } diff --git a/shell.moon b/shell.moon new file mode 100644 index 0000000..07a8e16 --- /dev/null +++ b/shell.moon @@ -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 +}