Skip to content

Instantly share code, notes, and snippets.

@Egor-Skriptunoff
Created November 4, 2016 14:34
Show Gist options
  • Save Egor-Skriptunoff/4ae0f2dbda089f368f3df52ef00c7554 to your computer and use it in GitHub Desktop.
Save Egor-Skriptunoff/4ae0f2dbda089f368f3df52ef00c7554 to your computer and use it in GitHub Desktop.
----------------------------------------------------------------------------------------------------------------
-- 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