diff --git a/fnl/conjure-spec/dynamic_spec.fnl b/fnl/conjure-spec/dynamic_spec.fnl new file mode 100644 index 00000000..4b46c375 --- /dev/null +++ b/fnl/conjure-spec/dynamic_spec.fnl @@ -0,0 +1,98 @@ +(local {: describe : it} (require :plenary.busted)) +(local assert (require :luassert.assert)) + +(local dyn (require :conjure.dynamic)) + +(describe "conjure.dynamic" + (fn [] + (describe "new-and-unbox" + (fn [] + (let [foo (dyn.new #(do :bar))] + (it "new returns a function" + (fn [] + (assert.are.equals :function (type foo)))) + (it "function is wrapped" + (fn [] + (assert.are.equals :bar (foo))))))) + + (describe "bind" + (fn [] + (let [foo (dyn.new #(do 1))] + (it "one level deep" + (fn [] + (assert.are.equals 1 (foo)))) + (it "two levels deep" + (fn [] + (dyn.bind + {foo #(do 2)} + (fn [expected] + (assert.are.equals expected (foo))) + 2))) + (it "no more than two levels deep" + (fn [] + (dyn.bind + {foo #(do 2)} + (fn [] + (assert.are.equals 2 (foo)) + (dyn.bind + {foo #(do 3)} + (fn [] + (assert.are.equals 3 (foo)))) + (dyn.bind + {foo #(error "OHNO")} + (fn [] + (let [(ok? result) (pcall foo)] + (assert.are.equals false ok?) + (assert.are.equals result "OHNO")))) + (assert.are.equals 2 (foo))))))))) + + (describe "set!" + (fn [] + (let [foo (dyn.new #(do 1))] + (it "one level deep" + (fn [] + (assert.are.equals (foo) 1))) + (it "more than two levels deep" + (fn [] + (dyn.bind + {foo #(do 2)} + (fn [] + (assert.are.equals (foo) 2) + (assert.are.equals nil (dyn.set! foo #(do 3))) + (assert.are.equals (foo) 3)))))))) + + (describe "set-root!" + (fn [] + (let [foo (dyn.new #(do 1))] + (it "one level deep" + (fn [] + (assert.are.equals (foo) 1))) + (it "three levels deep" + (fn [] + (dyn.bind + {foo #(do 2)} + (fn [] + (assert.are.equals (foo) 2) + (assert.are.equals nil (dyn.set-root! foo #(do 3))) + (assert.are.equals (foo) 2))))) + (it "remembers binding from three levels deep" + (fn [] + (assert.are.equals (foo) 3))) + (it "four levels deep" + (fn [] + (dyn.set-root! foo #(do 4)))) + (it "remembers binding from four levels deep" + (fn [] + (assert.are.equals (foo) 4)))))) + + (describe "type-guard" + (fn [] + (let [(ok? result) (pcall dyn.new :foo)] + (it "direct call of conjure.dynamic value fails" + (fn [] + (assert.are.equals false ok?) + )) + (it "returns why failed" + (fn [] + (assert.is_not_nil (string.match result "conjure.dynamic values must always be wrapped in a function")) + nil))))))) diff --git a/fnl/conjure/dynamic.fnl b/fnl/conjure/dynamic.fnl index 2264905c..67e65bd1 100644 --- a/fnl/conjure/dynamic.fnl +++ b/fnl/conjure/dynamic.fnl @@ -1,29 +1,27 @@ -(import-macros {: module : def : defn : defonce : def- : defn- : defonce- : wrap-last-expr : wrap-module-body : deftest} :nfnl.macros.aniseed) +(local {: autoload} (require :nfnl.module)) +(local a (autoload :conjure.aniseed.core)) -(module conjure.dynamic - {autoload {a conjure.aniseed.core}}) +(local get-stack-key :conjure.dynamic/get-stack) -(def- get-stack-key :conjure.dynamic/get-stack) - -(defn- assert-value-function! [value] +(fn assert-value-function! [value] (when (not= :function (type value)) (error "conjure.dynamic values must always be wrapped in a function"))) -(defn new [base-value] +(fn new [base-value] (assert-value-function! base-value) (var stack [base-value]) (fn [x ...] (if (= get-stack-key x) stack ((a.last stack) x ...)))) -(defn- run-binds! [f binds] +(fn run-binds! [f binds] (a.map-indexed (fn [[dyn new-value]] (assert-value-function! new-value) (f (dyn get-stack-key) new-value)) binds)) -(defn bind [binds f ...] +(fn bind [binds f ...] (run-binds! table.insert binds) (let [(ok? result) (pcall f ...)] (run-binds! #(table.remove $1) binds) @@ -31,16 +29,19 @@ result (error result)))) -(defn set! [dyn new-value] +(fn set! [dyn new-value] (assert-value-function! new-value) (let [stack (dyn get-stack-key) depth (a.count stack)] (a.assoc stack depth new-value)) nil) -(defn set-root! [dyn new-value] +(fn set-root! [dyn new-value] (assert-value-function! new-value) (a.assoc (dyn get-stack-key) 1 new-value) nil) -*module* +{: new + : bind + : set! + : set-root!} diff --git a/lua/conjure-spec/dynamic_spec.lua b/lua/conjure-spec/dynamic_spec.lua new file mode 100644 index 00000000..7586f7d9 --- /dev/null +++ b/lua/conjure-spec/dynamic_spec.lua @@ -0,0 +1,156 @@ +-- [nfnl] Compiled from fnl/conjure-spec/dynamic_spec.fnl by https://github.com/Olical/nfnl, do not edit. +local _local_1_ = require("plenary.busted") +local describe = _local_1_["describe"] +local it = _local_1_["it"] +local assert = require("luassert.assert") +local dyn = require("conjure.dynamic") +local function _2_() + local function _3_() + local foo + local function _4_() + return "bar" + end + foo = dyn.new(_4_) + local function _5_() + return assert.are.equals("function", type(foo)) + end + it("new returns a function", _5_) + local function _6_() + return assert.are.equals("bar", foo()) + end + return it("function is wrapped", _6_) + end + describe("new-and-unbox", _3_) + local function _7_() + local foo + local function _8_() + return 1 + end + foo = dyn.new(_8_) + local function _9_() + return assert.are.equals(1, foo()) + end + it("one level deep", _9_) + local function _10_() + local function _11_() + return 2 + end + local function _12_(expected) + return assert.are.equals(expected, foo()) + end + return dyn.bind({[foo] = _11_}, _12_, 2) + end + it("two levels deep", _10_) + local function _13_() + local function _14_() + return 2 + end + local function _15_() + assert.are.equals(2, foo()) + local function _16_() + return 3 + end + local function _17_() + return assert.are.equals(3, foo()) + end + dyn.bind({[foo] = _16_}, _17_) + local function _18_() + return error("OHNO") + end + local function _19_() + local ok_3f, result = pcall(foo) + assert.are.equals(false, ok_3f) + return assert.are.equals(result, "OHNO") + end + dyn.bind({[foo] = _18_}, _19_) + return assert.are.equals(2, foo()) + end + return dyn.bind({[foo] = _14_}, _15_) + end + return it("no more than two levels deep", _13_) + end + describe("bind", _7_) + local function _20_() + local foo + local function _21_() + return 1 + end + foo = dyn.new(_21_) + local function _22_() + return assert.are.equals(foo(), 1) + end + it("one level deep", _22_) + local function _23_() + local function _24_() + return 2 + end + local function _25_() + assert.are.equals(foo(), 2) + local function _26_() + return 3 + end + assert.are.equals(nil, dyn["set!"](foo, _26_)) + return assert.are.equals(foo(), 3) + end + return dyn.bind({[foo] = _24_}, _25_) + end + return it("more than two levels deep", _23_) + end + describe("set!", _20_) + local function _27_() + local foo + local function _28_() + return 1 + end + foo = dyn.new(_28_) + local function _29_() + return assert.are.equals(foo(), 1) + end + it("one level deep", _29_) + local function _30_() + local function _31_() + return 2 + end + local function _32_() + assert.are.equals(foo(), 2) + local function _33_() + return 3 + end + assert.are.equals(nil, dyn["set-root!"](foo, _33_)) + return assert.are.equals(foo(), 2) + end + return dyn.bind({[foo] = _31_}, _32_) + end + it("three levels deep", _30_) + local function _34_() + return assert.are.equals(foo(), 3) + end + it("remembers binding from three levels deep", _34_) + local function _35_() + local function _36_() + return 4 + end + return dyn["set-root!"](foo, _36_) + end + it("four levels deep", _35_) + local function _37_() + return assert.are.equals(foo(), 4) + end + return it("remembers binding from four levels deep", _37_) + end + describe("set-root!", _27_) + local function _38_() + local ok_3f, result = pcall(dyn.new, "foo") + local function _39_() + return assert.are.equals(false, ok_3f) + end + it("direct call of conjure.dynamic value fails", _39_) + local function _40_() + assert.is_not_nil(string.match(result, "conjure.dynamic values must always be wrapped in a function")) + return nil + end + return it("returns why failed", _40_) + end + return describe("type-guard", _38_) +end +return describe("conjure.dynamic", _2_) diff --git a/lua/conjure/dynamic.lua b/lua/conjure/dynamic.lua index 86eb509a..3dd010a1 100644 --- a/lua/conjure/dynamic.lua +++ b/lua/conjure/dynamic.lua @@ -1,22 +1,8 @@ -- [nfnl] Compiled from fnl/conjure/dynamic.fnl by https://github.com/Olical/nfnl, do not edit. -local _2amodule_name_2a = "conjure.dynamic" -local _2amodule_2a -do - _G.package.loaded[_2amodule_name_2a] = {} - _2amodule_2a = _G.package.loaded[_2amodule_name_2a] -end -local _2amodule_locals_2a -do - _2amodule_2a["aniseed/locals"] = {} - _2amodule_locals_2a = (_2amodule_2a)["aniseed/locals"] -end -local autoload = (require("aniseed.autoload")).autoload +local _local_1_ = require("nfnl.module") +local autoload = _local_1_["autoload"] local a = autoload("conjure.aniseed.core") -do end (_2amodule_locals_2a)["a"] = a -do local _ = {nil, nil, nil, nil, nil, nil} end local get_stack_key = "conjure.dynamic/get-stack" -_2amodule_locals_2a["get-stack-key"] = get_stack_key -do local _ = {nil, nil} end local function assert_value_function_21(value) if ("function" ~= type(value)) then return error("conjure.dynamic values must always be wrapped in a function") @@ -24,34 +10,27 @@ local function assert_value_function_21(value) return nil end end -_2amodule_locals_2a["assert-value-function!"] = assert_value_function_21 -do local _ = {assert_value_function_21, nil} end local function new(base_value) assert_value_function_21(base_value) local stack = {base_value} - local function _2_(x, ...) + local function _3_(x, ...) if (get_stack_key == x) then return stack else return a.last(stack)(x, ...) end end - return _2_ + return _3_ end -_2amodule_2a["new"] = new -do local _ = {new, nil} end local function run_binds_21(f, binds) - local function _6_(_4_) - local _arg_5_ = _4_ - local dyn = _arg_5_[1] - local new_value = _arg_5_[2] + local function _6_(_5_) + local dyn = _5_[1] + local new_value = _5_[2] assert_value_function_21(new_value) return f(dyn(get_stack_key), new_value) end return a["map-indexed"](_6_, binds) end -_2amodule_locals_2a["run-binds!"] = run_binds_21 -do local _ = {run_binds_21, nil} end local function bind(binds, f, ...) run_binds_21(table.insert, binds) local ok_3f, result = pcall(f, ...) @@ -65,8 +44,6 @@ local function bind(binds, f, ...) return error(result) end end -_2amodule_2a["bind"] = bind -do local _ = {bind, nil} end local function set_21(dyn, new_value) assert_value_function_21(new_value) do @@ -76,13 +53,9 @@ local function set_21(dyn, new_value) end return nil end -_2amodule_2a["set!"] = set_21 -do local _ = {set_21, nil} end local function set_root_21(dyn, new_value) assert_value_function_21(new_value) a.assoc(dyn(get_stack_key), 1, new_value) return nil end -_2amodule_2a["set-root!"] = set_root_21 -do local _ = {set_root_21, nil} end -return _2amodule_2a +return {new = new, bind = bind, ["set!"] = set_21, ["set-root!"] = set_root_21}