object: Add support for the legacy accessors as r/w methods.

Many legacy Awesome APIs such as `client:tags()`, `root.buttons()`,
`client:keys()`, `drawin:geometry()`, etc used functions for both the getter
and setter. This contrast with just about everything else that came after
it and is an artifact of an earlier time before we had "good" Lua object
support.

Because both consistency and backward compatibility are important, this
table wrapper allows to support both the legacy method based accessors
and key/value based accessors.

It isn't part of the public API, has a sledgehammer function prototype
and is intended for internal use only.

It's ugly, but backward compatibility is more important than anything
else.
This commit is contained in:
Emmanuel Lepage Vallee 2018-12-26 17:09:02 -05:00
parent 141aca2432
commit 78c3496770
1 changed files with 123 additions and 0 deletions

View File

@ -7,7 +7,10 @@
-- @submodule gears.object
---------------------------------------------------------------------------
local gtable = require("gears.table")
-- local gdebug = require("gears.debug")
local object = {}
local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1)
--- Add the missing properties handler to a CAPI object such as client/tag/screen.
@ -84,6 +87,126 @@ function object.capi_index_fallback(class, args)
class.set_newindex_miss_handler(setter)
end
-- (private api)
-- Many legacy Awesome APIs such as `client:tags()`, `root.buttons()`,
-- `client:keys()`, `drawin:geometry()`, etc used functions for both the getter
-- and setter. This contrast with just about everything else that came after
-- it and is an artifact of an earlier time before we had "good" Lua object
-- support.
--
-- Because both consistency and backward compatibility are important, this
-- table wrapper allows to support both the legacy method based accessors
-- and key/value based accessors.
--
-- TO BE USED FOR DEPRECATION ONLY.
local function copy_object(obj, to_set, name, capi_name, is_object, join_if, set_empty)
local ret = gtable.clone(to_set, false)
-- .buttons used to be a function taking the result of `gears.table.join`.
-- For compatibility, support this, but from now on, it's a property.
return setmetatable(ret, {
__call = function(_, self, new_objs)
--TODO uncomment
-- gdebug.deprecate("`"..name.."` is no longer a function, it is a property. "..
-- "Remove the `gears.table.join` and use a brace enclosed table",
-- {deprecated_in=5}
-- )
new_objs, self = is_object and new_objs or self, is_object and self or obj
-- Setter
if new_objs and #new_objs > 0 then
if (not set_empty) and not next(new_objs) then return end
local is_formatted = join_if(new_objs)
-- Because modules may rely on :buttons taking a list of
-- `capi.buttons`/`capi.key` and now the user passes a list of
-- `awful.button`/`awful.key` convert this.
local result = is_formatted and
new_objs or gtable.join(unpack(new_objs))
if capi_name and is_object then
return self[capi_name](self, result)
elseif capi_name then
return self[capi_name](result)
else
self._private[name.."_formatted"] = result
return self._private[name.."_formatted"]
end
end
-- Getter
if capi_name and is_object then
return self[capi_name](self)
elseif capi_name then
return self[capi_name]()
else
return self._private[name.."_formatted"] or {}
end
end
})
end
function object._legacy_accessors(obj, name, capi_name, is_object, join_if, set_empty)
-- Some objects have a special "object" property to add more properties, but
-- not all.
local magic_obj = obj.object and obj.object or obj
magic_obj["get_"..name] = function(self)
self = is_object and self or obj
self._private[name] = self._private[name] or copy_object(
obj, {}, name, capi_name, is_object, join_if, set_empty
)
assert(self._private[name])
return self._private[name]
end
magic_obj["set_"..name] = function(self, objs)
if (not set_empty) and not next(objs) then return end
if not is_object then
objs, self = self, obj
end
assert(objs)
-- When called from a declarative property list, "buttons" will be set
-- using the result of gears.table.join, detect this
local is_formatted = join_if(objs)
-- if is_formatted then
--TODO uncomment
-- gdebug.deprecate("Remove the `gears.table.join` and replace it with braces",
-- {deprecated_in=5}
-- )
-- end
--TODO v6 Use the original directly and drop this legacy copy
local result = is_formatted and objs
or gtable.join(unpack(objs))
if is_object and capi_name then
self[capi_name](self, result)
elseif capi_name then
obj[capi_name](result)
else
self._private[name.."_formatted"] = result
end
self._private[name] = copy_object(
obj, objs, name, capi_name, is_object, join_if, set_empty
)
end
end
return setmetatable( object, {__call = function(_,...) object.capi_index_fallback(...) end})
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80