From 4ea8daeb7478487ff32a03d97d5ded16785018d8 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Thu, 13 Jan 2022 20:04:26 +0100 Subject: feat(utils) add 'kpairs' iterator Iterates over all non-integer keys (inverse of 'ipairs' --- CHANGELOG.md | 3 +++ lua/pl/utils.lua | 43 +++++++++++++++++++++++++++++++++++++++++++ spec/utils-kpairs_spec.lua | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 spec/utils-kpairs_spec.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index b3385f0..8a4f1a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ see [CONTRIBUTING.md](CONTRIBUTING.md#release-instructions-for-a-new-version) fo [#414](https://github.com/lunarmodules/Penlight/pull/414) ======= - feat: `utils.enum` now accepts hash tables, to enable better error handling + [#413](https://github.com/lunarmodules/Penlight/pull/413) + - feat: `utils.kpairs` new iterator over all non-integer keys + [#413](https://github.com/lunarmodules/Penlight/pull/413) >>>>>>> b38c390 (feat(utils) enum to accept hash tables as well) diff --git a/lua/pl/utils.lua b/lua/pl/utils.lua index d56a6ef..fed880c 100644 --- a/lua/pl/utils.lua +++ b/lua/pl/utils.lua @@ -13,6 +13,8 @@ local concat = table.concat local _unpack = table.unpack -- always injected by 'compat' local find = string.find local sub = string.sub +local next = next +local floor = math.floor local is_windows = compat.is_windows local err_mode = 'default' @@ -223,6 +225,47 @@ end +--- an iterator over all non-integer keys (inverse of `ipairs`). +-- It will skip any key that is an integer number, so negative indices or an +-- array with holes will not return those either (so it returns slightly less than +-- 'the inverse of `ipairs`'). +-- +-- This uses `pairs` under the hood, so any value that is iterable using `pairs` +-- will work with this function. +-- @tparam table t the table to iterate over +-- @treturn key +-- @treturn value +-- @usage +-- local t = { +-- "hello", +-- "world", +-- hello = "hallo", +-- world = "Welt", +-- } +-- +-- for k, v in utils.kpairs(t) do +-- print("German: ", v) +-- end +-- +-- -- output; +-- -- German: hallo +-- -- German: Welt +function utils.kpairs(t) + local index + return function() + local value + while true do + index, value = next(t, index) + if type(index) ~= "number" or floor(index) ~= index then + break + end + end + return index, value + end +end + + + --- Error handling -- @section Error-handling diff --git a/spec/utils-kpairs_spec.lua b/spec/utils-kpairs_spec.lua new file mode 100644 index 0000000..7fac079 --- /dev/null +++ b/spec/utils-kpairs_spec.lua @@ -0,0 +1,38 @@ +local utils = require("pl.utils") + +describe("pl.utils", function () + + describe("kpairs", function () + local kpairs + + before_each(function() + kpairs = utils.kpairs + end) + + + it("iterates over non-integers", function() + local func = function() end + local bool = true + local string = "a string" + local float = 123.45 + local r = {} + for k, v in kpairs { + [func] = 1, + [bool] = 2, + [string] = 3, + [float] = 4, + 5, 6, 7, + } do + r[k] = v + end + + assert.same({ + [func] = 1, + [bool] = 2, + [string] = 3, + [float] = 4 }, r) + end) + + end) + +end) -- cgit v1.2.3