Skip to content

Commit

Permalink
feat(compat) add a 5.4 compatible "warn" function
Browse files Browse the repository at this point in the history
also updates the derpecation warnings to use the warn function
  • Loading branch information
Tieske committed Jan 6, 2021
1 parent 94693b1 commit a7b6a5e
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 68 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ see [CONTRIBUTING.md](CONTRIBUTING.md#release-instructions-for-a-new-version) fo
[#360](https://github.com/lunarmodules/Penlight/pull/360)
- feat: `permute.list_table` generate table with different sets of values
[#360](https://github.com/lunarmodules/Penlight/pull/360)
- feat: Lua 5.4 'warn' compatibility function
[#366](https://github.com/lunarmodules/Penlight/pull/366)
- feat: deprecation functionality `utils.raise_deprecation`
[#361](https://github.com/lunarmodules/Penlight/pull/361)
- fix: `dir.rmtree` failed to remove symlinks to directories
Expand Down
29 changes: 29 additions & 0 deletions lua/pl/compat.lua
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,33 @@ if not package.searchpath then
end
end

--- Global exported functions (for Lua < 5.4)
-- @section lua54

--- raise a warning message.
-- This functions mimics the `warn` function added in Lua 5.4.
-- @function warn
-- @param ... any arguments
if not warn then -- luacheck: ignore
local enabled = false
function warn(arg1, ...) -- luacheck: ignore
if type(arg1) == "string" and arg1:sub(1, 1) == "@" then
-- control message
if arg1 == "@on" then
enabled = true
return
end
if arg1 == "@off" then
enabled = false
return
end
return -- ignore unknown control messages
end
if enabled then
io.stderr:write("Lua warning: ", arg1, ...)
io.stderr:write("\n")
end
end
end

return compat
8 changes: 4 additions & 4 deletions lua/pl/permute.lua
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ end
-- @param ...
-- @see permute.order_iter
function permute.iter(...)
utils.deprecation_warning {
utils.raise_deprecation {
source = "Penlight " .. utils._VERSION,
message = "function 'iter' was renamed to 'order_iter'",
version_removed = "2.0.0",
version_deprecated = "1.9.2",
deprecated_after = "1.9.2",
}

return permute.order_iter(...)
Expand All @@ -180,11 +180,11 @@ end
-- @param ...
-- @see permute.order_iter
function permute.table(...)
utils.deprecation_warning {
utils.raise_deprecation {
source = "Penlight " .. utils._VERSION,
message = "function 'table' was renamed to 'order_table'",
version_removed = "2.0.0",
version_deprecated = "1.9.2",
deprecated_after = "1.9.2",
}

return permute.order_table(...)
Expand Down
138 changes: 81 additions & 57 deletions lua/pl/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -613,72 +613,96 @@ end
--- Deprecation
-- @section deprecation

do
-- the default implementation
local deprecation_func = function(msg, trace)
warn(msg, "\n", trace) -- luacheck: ignore
end

--- A deprecation warning function, to be overridden.
-- An application can override this function to support proper output of
-- deprecation warnings. The warnings can be generated from libraries or
-- functions by calling `utils.raise_deprecation`. By default this function
-- doesn't do anything.
--
-- Note: only applications should override this function, libraries should not.
-- @string msg the message to display/log
-- @string trace the traceback from where the deprecated element was invoked
-- @usage
-- function utils.deprecation_warning(msg, trace)
-- io.stderr:write(msg .. "\n" .. trace .."\n")
-- end
function utils.deprecation_warning(msg, trace)
-- this does nothing by default
end
--- Sets a deprecation warning function.
-- An application can override this function to support proper output of
-- deprecation warnings. The warnings can be generated from libraries or
-- functions by calling `utils.raise_deprecation`. The default function
-- will write to the 'warn' system (introduced in Lua 5.4, or the compatibility
-- function from the `compat` module for earlier versions).
--
-- Note: only applications should set/change this function, libraries should not.
-- @function a callback with signature: `function(msg, trace)` both arguments are strings.
-- @see utils.raise_deprecation
-- @usage
-- -- write to the Nginx logs with OpenResty
-- utils.set_deprecation_func(function(msg, trace)
-- ngx.log(ngx.WARN, msg, " ", trace)
-- end)
--
-- -- disable deprecation warnings
-- utils.deprecation_warning()
function utils.set_deprecation_func(func)
if func == nil then
deprecation_func = function() end
else
utils.assert_arg(1, func, "function")
deprecation_func = func
end
end

--- raises a deprecation warning.
-- For options see the usage example below.
--
-- Note: the `opts.deprecated_after` field is the last version in which
-- a feature or option was NOT YET deprecated! Because when writing the code it
-- is quite often not known in what version the code will land. But the last
-- released version is usually known.
-- @param opts options table
-- @see utils.set_deprecation_func
-- @usage
-- warn("@on") -- enable Lua warnings, they are usually off by default
--
-- function stringx.islower(str)
-- raise_deprecation {
-- source = "Penlight " .. utils._VERSION, -- optional
-- message = "function 'islower' was renamed to 'is_lower'" -- required
-- version_removed = "2.0.0", -- optional
-- deprecated_after = "1.2.3", -- optional
-- }
-- return stringx.is_lower(str)
-- end
-- -- output: "[Penlight 1.9.2] function 'islower' was renamed to 'is_lower' (deprecated after 1.2.3, scheduled for removal in 2.0.0)"
function utils.raise_deprecation(opts)
utils.assert_arg(1, opts, "table")
if type(opts.message) ~= "string" then
error("field 'message' of the options table must be a string", 2)
end
local trace = debug.traceback("", 2):match("[\n%s]*(.-)$")
local msg
if opts.deprecated_after and opts.version_removed then
msg = (" (deprecated after %s, scheduled for removal in %s)"):format(
tostring(opts.deprecated_after), tostring(opts.version_removed))
elseif opts.deprecated_after then
msg = (" (deprecated after %s)"):format(tostring(opts.deprecated_after))
elseif opts.version_removed then
msg = (" (scheduled for removal in %s)"):format(tostring(opts.version_removed))
else
msg = ""
end

--- raises a deprecation warning.
-- For options see the usage example below.
--
-- Note: the `opts.version_deprecated` field is the last version in which
-- a feature or option was NOT YET deprecated! Because when writing the code it
-- is quite often not known in what version the code will land. But the last
-- released version is usually known.
-- @param opts options table
-- @see utils.deprecation_warning
-- @usage
-- function stringx.islower(str)
-- deprecation_warning {
-- source = "Penlight " .. utils._VERSION, -- optional
-- message = "function 'islower' was renamed to 'is_lower'" -- required
-- version_removed = "2.0.0", -- optional
-- version_deprecated = "1.2.3", -- optional
-- }
-- return stringx.is_lower(str)
-- end
-- -- output: "[Penlight 1.9.2] function 'islower' was renamed to 'is_lower' (deprecated after 1.2.3, scheduled for removal in 2.0.0)"
function utils.raise_deprecation(opts)
utils.assert_arg(1, opts, "table")
if type(opts.message) ~= "string" then
error("field 'message' of the options table must be a string", 2)
end
local trace = debug.traceback("", 2):match("[\n%s]*(.-)$")
local msg
if opts.version_deprecated and opts.version_removed then
msg = (" (deprecated after %s, scheduled for removal in %s)"):format(
tostring(opts.version_deprecated), tostring(opts.version_removed))
elseif opts.version_deprecated then
msg = (" (deprecated after %s)"):format(tostring(opts.version_deprecated))
elseif opts.version_removed then
msg = (" (scheduled for removal in %s)"):format(tostring(opts.version_removed))
else
msg = ""
end
msg = opts.message .. msg

msg = opts.message .. msg
if opts.source then
msg = "[" .. opts.source .."] " .. msg
else
if msg:sub(1,1) == "@" then
-- in Lua 5.4 "@" prefixed messages are control messages to the warn system
error("message cannot start with '@'", 2)
end
end

if opts.source then
msg = "[" .. opts.source .."] " .. msg
deprecation_func(msg, trace)
end

utils.deprecation_warning(msg, trace)
end


return utils


40 changes: 33 additions & 7 deletions spec/utils-deprecate_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ describe("pl.utils", function ()
local old_fn, last_msg, last_trace

before_each(function()
old_fn = utils.deprecation_warning
old_fn = function() end
last_msg = nil
last_trace = nil
utils.deprecation_warning = function(msg, trace)
utils.set_deprecation_func(function(msg, trace)
last_msg = msg
last_trace = trace
end
end)
end)


Expand All @@ -21,6 +21,32 @@ describe("pl.utils", function ()



describe("set_deprecation_func", function ()

it("accepts nil as callback", function()
assert.has.no.error(function()
utils.set_deprecation_func()
end)
end)


it("accepts function as callback", function()
assert.has.no.error(function()
utils.set_deprecation_func(function() end)
end)
end)


it("fails on non-functions", function()
assert.has.error(function()
utils.set_deprecation_func("not a function")
end, "argument 1 expected a 'function', got a 'string'")
end)

end)



describe("raise_deprecation", function ()

it("requires the opts table", function()
Expand All @@ -46,7 +72,7 @@ describe("pl.utils", function ()
it("should output the deprecated version", function ()
utils.raise_deprecation {
message = "hello world",
version_deprecated = "2.0.0",
deprecated_after = "2.0.0",
}
assert.equal("hello world (deprecated after 2.0.0)", last_msg)
end)
Expand All @@ -64,7 +90,7 @@ describe("pl.utils", function ()
it("should output the deprecated and removal versions", function ()
utils.raise_deprecation {
message = "hello world",
version_deprecated = "2.0.0",
deprecated_after = "2.0.0",
version_removed = "3.0.0",
}
assert.equal("hello world (deprecated after 2.0.0, scheduled for removal in 3.0.0)", last_msg)
Expand All @@ -75,7 +101,7 @@ describe("pl.utils", function ()
utils.raise_deprecation {
source = "MyApp 1.2.3",
message = "hello world",
version_deprecated = "2.0.0",
deprecated_after = "2.0.0",
version_removed = "3.0.0",
}
assert.equal("[MyApp 1.2.3] hello world (deprecated after 2.0.0, scheduled for removal in 3.0.0)", last_msg)
Expand All @@ -87,7 +113,7 @@ describe("pl.utils", function ()
utils.raise_deprecation {
source = "MyApp 1.2.3",
message = "hello world",
version_deprecated = "2.0.0",
deprecated_after = "2.0.0",
version_removed = "3.0.0",
}
end
Expand Down
1 change: 1 addition & 0 deletions tests/test-strict.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
warn = warn or true-- declare 'warn' as a global, to be added in compat module
local strict = require 'pl.strict'
local test = require 'pl.test'
local app = require 'pl.app'
Expand Down

0 comments on commit a7b6a5e

Please sign in to comment.