Browse Source

Merge commit 'a9dc73a682' as 'utility'

Paul Liverman III 4 years ago
parent
commit
35e8bb85f7

+ 1
- 0
utility/.gitignore View File

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

+ 21
- 0
utility/LICENSE View File

@@ -0,0 +1,21 @@
1
+MIT License
2
+
3
+Copyright (c) 2018 Paul Liverman III
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.

+ 30
- 0
utility/calc.moon View File

@@ -0,0 +1,30 @@
1
+import bytes from require "resty.random"
2
+import byte from string
3
+import floor from math
4
+
5
+-- return a random number between min/max
6
+random = (min, max) ->
7
+  unless max
8
+    max = min or 1
9
+    min = 0
10
+
11
+  a, b = byte bytes(2), 1, 2
12
+  c, d = byte bytes(2), 1, 2
13
+  value = a + b * 256 + c * 65536 + d * 16777216 -- 0 to 4294967296
14
+  range = max - min
15
+
16
+  if max == floor(max) and min == floor(min)
17
+    return floor value * range / 4294967296 + min
18
+  else
19
+    return value * range / 4294967296 + min
20
+
21
+-- map a value within a range of numbers to another range
22
+map = (min1, max1, value, min2, max2) ->
23
+  range1 = max1 - min1
24
+  range2 = max2 - min2
25
+  return ((value - min1) * range2 / range1) + min2
26
+
27
+{
28
+  :random
29
+  :map
30
+}

+ 36
- 0
utility/datetime.moon View File

@@ -0,0 +1,36 @@
1
+import date, time from os
2
+
3
+-- for database
4
+now = ->
5
+  return date "!%Y-%m-%d %X"
6
+
7
+-- database date -> display
8
+pretty_date = (str) ->
9
+  year, month, day = str\match "(%d%d%d%d)-(%d%d)-(%d%d)"
10
+  return date "%B %d, %Y", time :year, :month, :day
11
+
12
+-- from database
13
+to_seconds = (str) ->
14
+  year, month, day, hour, min, sec = str\match "(%d%d%d%d)-(%d%d)-(%d%d) (%d%d):(%d%d):(%d%d)"
15
+  return time :year, :month, :day, :hour, :min, :sec
16
+
17
+-- seconds -> for database
18
+for_db = (seconds) ->
19
+  return date "!%Y-%m-%d %X", seconds
20
+
21
+gmt_date = ->
22
+  return date "!*t"
23
+
24
+gmt_time = ->
25
+  return time date "!*t"
26
+
27
+{
28
+  none: "1970-01-01 00:00:00" -- TODO deprecate
29
+  zero: "1970-01-01 00:00:00" -- for use in database
30
+  :now
31
+  :pretty_date
32
+  :to_seconds
33
+  :for_db
34
+  :gmt_date
35
+  :gmt_time
36
+}

+ 9
- 0
utility/db.moon View File

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

+ 23
- 0
utility/fs.moon View File

@@ -0,0 +1,23 @@
1
+exists = (file_path) ->
2
+  if file = io.open file_path, "r"
3
+    file\close!
4
+    return true
5
+  else
6
+    return false
7
+
8
+size = (file_or_path) ->
9
+  if "string" == type file_or_path
10
+    file = io.open file_or_path, "r"
11
+    size = file\seek "end"
12
+    file\close!
13
+    return size
14
+  else
15
+    current = file\seek!
16
+    size = file\seek "end"
17
+    file\seek "set", current
18
+    return size
19
+
20
+{
21
+  :exists
22
+  :size
23
+}

+ 59
- 0
utility/gstring.moon View File

@@ -0,0 +1,59 @@
1
+import insert, sort, concat from table
2
+import sub, len from string
3
+
4
+-- splits string by newline into array of strings
5
+lines = (str) ->
6
+  tab = {}
7
+  for line in str\gmatch "[^\n]+"
8
+    insert tab, line
9
+  return tab
10
+
11
+-- splits string by spaces into a table of strings
12
+--  (handles bad spacing and duplicate substrings)
13
+split = (str) ->
14
+  tab1, tab2 = {}, {}
15
+  for word in str\gmatch "%S+"
16
+    tab1[word] = true
17
+  for word in pairs tab1
18
+    insert tab2, word
19
+  return tab2
20
+
21
+-- splits string by commas into a table of strings
22
+--  (expects a well-formated string!)
23
+comma_split = (str) ->
24
+  tab = {}
25
+  for word in str\gmatch "[^,]+"
26
+    insert tab, word
27
+  return tab
28
+
29
+-- bool: does str1 start with str2
30
+starts = (str1, str2) ->
31
+  return str2 == sub str1, 1, len str2
32
+
33
+-- takes space-separated string and puts it in alphabetical order
34
+--  (handles weird spacing, returns with single-spacing)
35
+alphabetize = (str) ->
36
+  tab = split str
37
+  sort tab
38
+  return concat tab, " "
39
+
40
+-- takes space-separated string and removes duplicate entries from it
41
+remove_duplicates = (str) ->
42
+  strings = split str
43
+  tab, result = {}, {}
44
+
45
+  for str in *strings
46
+    tab[str] = true
47
+  for str in pairs tab
48
+    insert result, str
49
+
50
+  return concat result, " "
51
+
52
+{
53
+  :lines
54
+  :split
55
+  :comma_split
56
+  :starts
57
+  :alphabetize
58
+  :remove_duplicates
59
+}

+ 33
- 0
utility/gtable.moon View File

@@ -0,0 +1,33 @@
1
+-- appends n arrays to the end of the first array
2
+append = (tab1, ...) ->
3
+  for n = 1, select "#", ...
4
+    tab2 = select n, ...
5
+    for i = 1, #tab2
6
+      tab1[#tab1+1] = tab2[i]
7
+  return tab1
8
+
9
+-- returns a new table shallow copying data from all arguments
10
+--  later arguments overwrite any keys in earlier arguments
11
+--  ignores non-table arguments (skipping them)
12
+shallow_copy = (...) ->
13
+  new = {}
14
+  for n = 1, select "#", ...
15
+    tab = select n, ...
16
+    if "table" == type tab
17
+      for k,v in pairs tab
18
+        new[k] = v
19
+  return new
20
+
21
+-- returns a new table with flipped keys and values
22
+invert = (tab) ->
23
+  new = {}
24
+  for key, value in pairs tab
25
+    new[value] = key
26
+  return new
27
+
28
+{
29
+  :append
30
+  :shallow_copy
31
+  shallow_merge: shallow_copy -- TODO deprecate
32
+  :invert
33
+}

+ 13
- 0
utility/migrations.moon View File

@@ -0,0 +1,13 @@
1
+import create_table, types, create_index from require "lapis.db.schema"
2
+
3
+{
4
+  [1518948992]: =>
5
+    create_table "settings", {
6
+      {"name", types.varchar primary_key: true, unique: true}
7
+      {"value", types.text null: true}
8
+
9
+      {"created_at", types.time}
10
+      {"updated_at", types.time}
11
+    }
12
+    create_index "settings", "name", unique: true
13
+}

+ 5
- 0
utility/models/Settings.moon View File

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

+ 110
- 0
utility/settings.moon View File

@@ -0,0 +1,110 @@
1
+import Settings from require "models"
2
+
3
+totype = (str) ->
4
+  if value = tonumber str
5
+    return value
6
+  if str == "true"
7
+    return true
8
+  if str == "false"
9
+    return false
10
+  if str == "nil"
11
+    return nil
12
+  return str
13
+
14
+cache = {}
15
+
16
+get = (name, create=true) ->
17
+  setting = cache[name]
18
+  unless setting
19
+    setting = Settings\find :name
20
+    if (not setting) and create
21
+      setting = Settings\create :name
22
+    cache[name] = setting
23
+
24
+  if setting
25
+    return setting
26
+  else
27
+    return nil, "failed to load '#{name}' setting"
28
+
29
+local settings
30
+settings = {
31
+  get: (name, skip_index) ->
32
+    unless name
33
+      return settings.load!
34
+
35
+    unless skip_index -- for metamethods to not loop endlessly
36
+      return settings[name] if settings[name]
37
+
38
+    setting, err = get name
39
+    if setting
40
+      value = totype setting.value
41
+      settings[name] = value
42
+      return value
43
+    else
44
+      return nil, err
45
+
46
+  set: (name, value) ->
47
+    unless name
48
+      return settings.save!
49
+
50
+    setting, err = get name
51
+    if setting
52
+      settings[name] = value
53
+      return setting\update value: tostring value
54
+    else
55
+      return nil, err
56
+
57
+  save: (name) ->
58
+    if name
59
+      setting, err = get name
60
+      if setting
61
+        return setting\update value: tostring settings[name]
62
+      else
63
+        return nil, err
64
+
65
+    else
66
+      for name, value in pairs settings
67
+        switch name
68
+          when "get", "set", "save", "load", "delete"
69
+            nil
70
+          else
71
+            t = type value
72
+            if t == "function" or t == "table"
73
+              return nil, "cannot save '#{name}' setting, type '#{t}' not supported"
74
+            else
75
+              unless cache[name]
76
+                cache[name] = Settings\find :name
77
+                unless cache[name]
78
+                  cache[name] = Settings\create :name
79
+
80
+    for name, setting in pairs cache
81
+      _, err = setting\update value: tostring settings[name]
82
+      return nil, err if err
83
+    return true
84
+
85
+  load: (name) ->
86
+    return settings.get name if name
87
+
88
+    all_settings = Settings\select "WHERE true"
89
+    for setting in *all_settings
90
+      name = setting.name
91
+      cache[name] = setting
92
+      settings[name] = totype setting.value
93
+    return settings
94
+
95
+  delete: (name) ->
96
+    if setting = get name, false
97
+      if setting\delete!
98
+        cache[name] = nil
99
+        settings[name] = nil
100
+      else
101
+        return nil, "failed to delete '#{name}' setting"
102
+    return true
103
+}
104
+
105
+return setmetatable settings, {
106
+    __call: (t, name) ->
107
+      return settings.get name, true
108
+    __index: (t, name) ->
109
+      return settings.get name, true
110
+  }

+ 23
- 0
utility/shell.moon View File

@@ -0,0 +1,23 @@
1
+quote = (str) ->
2
+  escaped = str\gsub "'", [['"'"']]
3
+  return "'#{escaped}'"
4
+
5
+execute = (cmd, capture_exit_code=true) ->
6
+  local handle
7
+  if capture_exit_code
8
+    handle = io.popen "#{cmd}\necho $?"
9
+  else
10
+    handle = io.popen cmd
11
+  result = handle\read "*a"
12
+  handle\close!
13
+
14
+  exit_start, exit_end = result\find "(%d*)[%c]$"
15
+  exit_code = tonumber result\sub(exit_start, exit_end)\sub 1, -2
16
+  output = result\sub 1, exit_start - 1
17
+
18
+  return exit_code, output
19
+
20
+{
21
+  :quote
22
+  :execute
23
+}