Created
November 4, 2016 14:34
-
-
Save Egor-Skriptunoff/4ae0f2dbda089f368f3df52ef00c7554 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------------------------------------------------------------------------------------------------- | |
-- AUTOMAGIC TABLES | |
---------------------------------------------------------------------------------------------------------------- | |
-- There is a well-known "standard" implementation of automagic tables at http://lua-users.org/wiki/AutomagicTables | |
-- | |
-- Unfortunately, that implementation behaves weirdly in some situations: | |
-- local a = AutomagicTable() | |
-- local x = a.b.c | |
-- local y = a.b.c | |
-- assert(x == y) -- assertion fails ! | |
-- | |
-- This version of "AutomagicTable()" improves this behavior by storing weak references to all created objects. | |
-- | |
-- Please see "usage example" at the end of this file to understand the benefit of new behavior. | |
do | |
local weak, create = {__mode = "kv"} | |
local function get(tab, key) | |
local c = getmetatable(tab).content | |
local v = c[key] | |
if v == nil then | |
v = create(nil, tab, key) | |
c[key] = v | |
end | |
return v | |
end | |
local function set(tab, key, val) | |
if val ~= nil then | |
rawset(tab, key, val) | |
local m = getmetatable(tab) | |
m.content[key] = nil | |
local p = m.parent_tab | |
if p then | |
p[m.parent_key] = tab | |
m.parent_tab, m.parent_key = nil | |
end | |
end | |
end | |
function create(tab, parent_tab, parent_key) | |
return | |
setmetatable(tab or {}, { | |
__index = get, | |
__newindex = set, | |
parent_tab = parent_tab, | |
parent_key = parent_key, | |
content = setmetatable({}, weak) | |
}) | |
end | |
function AutomagicTable(tab) | |
return create(tab) | |
end | |
end | |
----------------------------------------------- | |
--- USAGE EXAMPLE | |
----------------------------------------------- | |
--- This is some sort of DSL config file :-) | |
--- It is actually a Lua script which runs in "automagic" global environment | |
AutomagicTable(_G) | |
----------------------------------------------- | |
----- (beginning of config file) -------------- | |
----------------------------------------------- | |
--- The following options are adjustable by user | |
table.insert(shopping.list, "'Programming in Lua' book") | |
today = weekdays.Friday --<== get a reference to empty object | |
----------------------------------------------- | |
--- User should not change anything below this line | |
weekdays.Monday.beverage = "beer" | |
weekdays.Tuesday.beverage = "beer" | |
weekdays.Wednesday.beverage = "beer" | |
weekdays.Thursday.beverage = "beer" | |
weekdays.Friday.beverage = "vodka" --<== fill the object with some data | |
-- Please note that the following line does not work as expected | |
-- if we are using standard implementation of automagic tables | |
table.insert(shopping.list, today.beverage) --<== access the object using the reference | |
----------------------------------------------- | |
----- (end of config file) -------------------- | |
----------------------------------------------- | |
--- Now let's check the result: | |
print(table.concat(shopping.list, ", ")) | |
----------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment