Module utils.magic
Meta-programming utilities.
Functions
enable_table_gc(t) | Make __gc for tables work for old Lua engines too. |
memoize(f) | Caches the results of a function call. |
once([lock_name,] fn) | Protects a function against being called recursively. |
setup_autoload(t) | Enables autoloading for missing variables. |
setup_strict(t, protect_read, protect_write) | Protects a namespace against referencing missing variables. |
vbfy(meta) | Enables “syntactic sugar” for properties. |
vbfy_singleton(module) | Enables “syntactic sugar” for properties, on modules. |
Functions
- enable_table_gc(t)
-
Make __gc for tables work for old Lua engines too.
Lua 5.2+ supports __gc for table. Older Lua engines don’t. To make older Lua engines support it, add a call to enable_table_gc:
Let’s first look at a Lua 5.2+ compatible code:
do local t = setmetatable({},{ __gc = function() print("works") end }) end collectgarbage()
To make it work under older Lua engines (Lua 5.1 and LuaJIT), do:
do local t = setmetatable({},{ __gc = function() print("works") end }) utils.magic.enable_table_gc(t) end collectgarbage()
- memoize(f)
-
Caches the results of a function call.
local function heavy(x) return x^(1/3) end local light = utils.magic.memoize(heavy) -- The following calculates the result just once. print(light(27), light(27), light(27))
The memoized function may receive several arguments, but as the caching key will serve only the first argument. Thus
light(3, 5)
andlight(3, "whatever")
will give the same result. - once([lock_name,] fn)
-
Protects a function against being called recursively.
It wraps the function fn inside a function that uses locking to ensure that the function is invoked only once in the calling stack.
See example at <<load>>.
- setup_autoload(t)
-
Enables autoloading for missing variables.
You then use
autoload()
to describe how to load the missing values.local t = { one = 1, two = 2, } utils.magic.setup_autoload(t) print(t.m) -- prints 'nil' -- Autoload a module: t.autoload('m', 'math') print(t.m.cos(0)) -- ok -- Autoload a function (of a module): t.autoload('cosine', { 'math', 'cos' }) print(t.cosine(0)) -- ok -- Autoload a custom value: t.autoload('banner', function() return fs.read('/etc/issue', '*l') end) print(t.banner) -- ok
- setup_strict(t, protect_read, protect_write)
-
Protects a namespace against referencing missing variables.
The user may then use
declare()
to allow referencing certain missing variables.local t = { one = 1, two = 2, } utils.magic.setup_strict(t, true, true) print(t.one) -- ok print(t.three) -- raises exception! t.three = 3 -- raises exception! t.declare('three') print(t.three) -- ok t.three = 3 -- ok
- vbfy(meta)
-
Enables “syntactic sugar” for properties.
This facility lets you type (for example):
obj.title = "abc" print(obj.title)
instead of:
obj:set_title("abc") print(obj:get_title())
An attempt to read/write a property that don’t have a getter/setter will be regarded as a typo and an exception will be raised:
obj.undeclared_property = -666 -- raises exception!
To allow access to fields without writing getters/setters for them, you need to declare them in the
__allowed_properties
table. Alternatively, use rawget/rawset to access such fields.This facility is used for widgets. We don’t want to encourage its use outside that realm because it’s not very conventional. Therefore we don’t provide a usage example here (but see tests/auto/magic_vbfy.mcs if you want to).
Parameters:
- meta The meta table.
- vbfy_singleton(module)
-
Enables “syntactic sugar” for properties, on modules.
Like vbfy but works on modules (on tables, to be exact).