Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add expr module #775

Merged
merged 1 commit into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions lua/mason-core/installer/registry/expr.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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 filter = setfenv(
assert(
loadstring("return " .. filter_expr),
("Failed to parse filter: %q."):format(filter_expr)
),
string_funs
)()
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
57 changes: 57 additions & 0 deletions tests/mason-core/installer/registry/expr_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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 ",
})
)

assert.same(
Result.success "Hello, Sir MR. John!",
expr.eval("Hello, {{prefix|to_upper | format 'Sir %s'}} {{ 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)