Skip to content

Commit

Permalink
feat: add expr module
Browse files Browse the repository at this point in the history
  • Loading branch information
williamboman committed Dec 19, 2022
1 parent 3ccd16b commit a7db90f
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
45 changes: 45 additions & 0 deletions lua/mason-core/installer/registry/expr.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
local _ = require "mason-core.functional"
local string_funs = require "mason-core.functional.string"
local Result = require "mason-core.result"

local M = {}

local parse_expr = _.compose(
_.apply_spec {
value_expr = _.head,
filters = _.drop(1),
},
_.filter(_.complement(_.equals "")),
_.map(_.trim),
_.split "|"
)

---@param str string
---@param ctx table<string, any>
function M.eval(str, ctx)
return Result.pcall(function()
return _.gsub("{{([^}]+)}}", function(expr)
local components = parse_expr(expr)
local value =
assert(ctx[components.value_expr], ("Unable to interpolate value: %q."):format(components.value_expr))
return _.reduce(
_.apply_to,
value,
_.map(function(filter_expr)
local f = setfenv(
assert(
loadstring("return " .. filter_expr),
("Failed to parse filter: %q."):format(filter_expr)
),
string_funs
)
local filter = f()
assert(type(filter) == "function", ("Invalid filter expression: %q."):format(filter_expr))
return filter
end, components.filters)
)
end, str)
end)
end

return M
9 changes: 9 additions & 0 deletions lua/mason-core/result.lua
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,13 @@ function Result.run_catching(fn)
end
end

function Result.pcall(fn, ...)
local ok, res = pcall(fn, ...)
if ok then
return Result.success(res)
else
return Result.failure(res)
end
end

return Result
49 changes: 49 additions & 0 deletions tests/mason-core/installer/registry/expr_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
local match = require "luassert.match"
local expr = require "mason-core.installer.registry.expr"
local Result = require "mason-core.result"

describe("registry expressions", function()
it("should eval simple expressions", function()
assert.same(Result.success "Hello, world!", expr.eval "Hello, world!")

assert.same(
Result.success "Hello, John Doe!",
expr.eval("Hello, {{firstname}} {{ lastname }}!", {
firstname = "John",
lastname = "Doe",
})
)
end)

it("should eval expressions with filters", function()
assert.same(
Result.success "Hello, MR. John!",
expr.eval("Hello, {{prefix|to_upper}} {{ name | trim }}!", {
prefix = "Mr.",
name = " John ",
})
)
end)

it("should reject invalid values", function()
assert.is_true(
match.matches [[^.*Unable to interpolate value: "non_existent"%.$]](
expr.eval("Hello, {{non_existent}}", {}):err_or_nil()
)
)
end)

it("should reject invalid filters", function()
assert.is_true(
match.matches [[^.*Invalid filter expression: "whut"%.$]](
expr.eval("Hello, {{ value | whut }}", { value = "value" }):err_or_nil()
)
)

assert.is_true(
match.matches [[^.*Failed to parse filter: "wh%-!uut"%.$]](
expr.eval("Hello, {{ value | wh-!uut }}", { value = "value" }):err_or_nil()
)
)
end)
end)
16 changes: 16 additions & 0 deletions tests/mason-core/result_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,20 @@ describe("result", function()
assert.equals("Error", failure:get_or_nil())
assert.spy(chain).was_not_called()
end)

it("should pcall", function()
assert.same(
Result.success "Great success!",
Result.pcall(function()
return "Great success!"
end)
)

assert.same(
Result.failure "Task failed successfully!",
Result.pcall(function()
error("Task failed successfully!", 0)
end)
)
end)
end)

0 comments on commit a7db90f

Please sign in to comment.