-
Notifications
You must be signed in to change notification settings - Fork 0
/
magicindex.lua
82 lines (63 loc) · 1.62 KB
/
magicindex.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
--[[
MagicIndexing
-------------
(Ab)uses metatables to achieve **magic** indexing of table values, so that you
can run some code to determine what value to return.
Can also be used to compute table values that don't really exist on the table.
--]]
-------------------
-- Utility --
-------------------
-- Finds the indexer function for a key
local function get_indexer(table, key)
-- match the specific word getkey with arbitrary case on each letter, optionally with underscore
local pattern = "^[gG][eE][tT]_?"
for i = 1,#key do
local letter = string.sub(key, i, i)
local letter_upper = string.upper(letter)
pattern = pattern .. "[" .. letter .. letter_upper .. "]"
end
pattern = pattern .. "$"
for k,v in pairs(table) do
if string.match(k, pattern) then
if v then
return v
end
end
end
return nil
end
-------------------
-- Wrapper meta --
-------------------
local MI_META = {}
MI_META.real_table = nil
function MI_META:__index(key)
local real = rawget(self, "real_table")
-- Pass off indexing to the custom indexing function
local indexer = get_indexer(real, key)
if indexer then
return indexer(real)
end
-- Default table behavior
return real[key]
end
function MI_META:__newindex(key, value)
local real = rawget(self, "real_table")
-- Metatable was applied without the wrapper function
if not real then
real = {}
rawset(self, "real_table", real)
end
real[key] = value
end
-------------------
-- Wrapping --
-------------------
local mi = {}
function mi.wrap(table)
local wrapper = setmetatable({}, MI_META)
rawset(wrapper, "real_table", table)
return wrapper
end
return mi