aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2019-11-03 13:05:11 +0000
committers-ol <s-ol@users.noreply.github.com>2019-11-03 16:01:13 +0000
commite2dbd96aa0cd362fbd9410a49aa415459a1c1b98 (patch)
tree241feebc82230681504fa41eaaa1d7692c44db8c
parentmake things work (diff)
downloadwatch-cad-e2dbd96aa0cd362fbd9410a49aa415459a1c1b98.tar.gz
watch-cad-e2dbd96aa0cd362fbd9410a49aa415459a1c1b98.zip
new state attempt
-rw-r--r--spec/state_spec.moon113
-rw-r--r--state.moon81
2 files changed, 142 insertions, 52 deletions
diff --git a/spec/state_spec.moon b/spec/state_spec.moon
index b2085c5..5826067 100644
--- a/spec/state_spec.moon
+++ b/spec/state_spec.moon
@@ -18,45 +18,100 @@ describe "Once", ->
assert.is_falsy Once.is_once { a: 3 }
describe "State", ->
- local S
+ local state
before_each ->
state = State!
- S = state.state
- it "can be indexed infinitely", ->
- assert.is_table S.a.b.c.d
+ it "stores values", ->
+ assert.is_nil state.values['my key']
+ state.values['my key'] = 'my val'
+ assert.is_equal 'my val', state.values['my key']
- describe ":init", ->
- it "stores default until changed", ->
- S\init 'test', 2
- assert.is.equal 2, S.test
+ state.values['more'] = 4
+ assert.is_equal 4, state.values['more']
+ assert.is_equal 'my val', state.values['my key']
- S.test = 4
- assert.is.equal 4, S.test
+ it "can be reset", ->
+ state.values['my key'] = 'my val'
+ state.values['more'] = 4
- S\init 'test', 2
- assert.is.equal 4, S.test
+ state\reset!
+ assert.is_nil state.values['my key']
+ assert.is_nil state.values['more']
- describe ":store", ->
- it "stores defaults until changed", ->
- S\store 'test', nil, 3
- assert.is.equal 3, S.test
+ describe "cursors", ->
+ it "can be nested with :get_nested()", ->
+ assert.is_table state.root\get_nested 'a'
+ assert.is_table state.root\get_nested('a')\get_nested 'b'
- S\store 'test', nil, 4
- assert.is.equal 3, S.test
+ it "delegate __index to :get_nested", ->
+ assert.is_table state.root
+ assert.is_table state.root.a
+ assert.is_table state.root.a.b.c.d
- it "follows live inputs", ->
- S\store 'test', 3, 'nope'
- assert.is.equal 3, S.test
+ it "stringify to a key", ->
+ assert.is_equal '', tostring state.root
+ assert.is_equal 'a.b.c.d', tostring state.root.a.b.c.d
- S\store 'test', 4, 'nope'
- assert.is.equal 4, S.test
+ it ":set() sets the value", ->
+ cursor = state.root.test
+ cursor\set 'the val'
+ assert.is_equal 'the val', state.values[cursor]
- it "lets Once() inputs override defaults", ->
- S\store 'test', (Once 3), 'nope'
- assert.is.equal 3, S.test
+ it ":set() returns the new value", ->
+ assert.is_equal 'val', state.root.test\set 'val'
- S\store 'test', 'changed'
+ it ":get() gets the value", ->
+ cursor = state.root.test
+ cursor\set 'the val'
+ assert.is_equal 'the val', cursor\get!
+
+ it ":init() sets the value unless already set", ->
+ cursor = state.root.test
+ cursor\init 'initial value'
+ assert.is_equal 'initial value', cursor!
+
+ cursor\init 'other value'
+ assert.is_equal 'initial value', cursor!
+
+ it ":init() returns the current value", ->
+ cursor = state.root.test
+ assert.is_equal 'initial value', cursor\init 'initial value'
+ assert.is_equal 'initial value', cursor\init 'other value'
+
+ it "can be called to get the value", ->
+ cursor = state.root.test
+ assert.is_nil cursor!
+ cursor\set 'the val'
+ assert.is_equal 'the val', cursor!
+
+ it "delegate __eq to string key", ->
+ assert.is_true state.root.a == state.root.a
+ assert.is_true state.root.a.b == state.root.a.b
+ assert.is_false state.root.a == state.root.b
+ assert.is_false state.root.a.b == state.root.a.c
+ assert.is_false state.root.a.b == state.root.c.b
+
+ describe ":drive()", ->
+ it "follows live inputs", ->
+ cursor = state.root.test
+ cursor\drive 3
+ assert.is_equal 3, cursor!
+
+ cursor\drive 'test'
+ assert.is_equal 'test', cursor!
+
+ it "initializes with Once() inputs", ->
+ cursor = state.root.test
+ cursor\drive Once 'initial'
+ assert.is_equal 'initial', cursor!
+
+ cursor\drive Once 'other'
+ assert.is_equal 'initial', cursor!
+
+ it "returns the current value", ->
+ cursor = state.root.test
+ assert.is_equal 'initial', cursor\drive Once 'initial'
+ assert.is_equal 'initial', cursor\drive Once 'other'
+ assert.is_equal 'live in', cursor\drive 'live in'
- S\store 'test', (Once 4), 'nope'
- assert.is.equal 'changed', S.test
diff --git a/state.moon b/state.moon
index 6916171..5a3170c 100644
--- a/state.moon
+++ b/state.moon
@@ -22,6 +22,53 @@ is_live = (val) -> (not is_once val) and val
are_once = all is_once
are_live = all is_live
+class Cursor
+ @__base.__index = do
+ old_index = @__base.__index
+ (k) =>
+ if v = old_index[k]
+ return v
+
+ if 'string' == type k
+ return @get_nested k
+
+ new: (@state, @path='') =>
+
+ set: (value) =>
+ @state.values[@path] = value
+ value
+
+ get: (value) =>
+ @state.values[@path]
+
+ init: (value) =>
+ old = @get!
+ if old != nil
+ old
+ else
+ @set value
+
+ drive: (live_or_once) =>
+ if val = is_once live_or_once
+ @init val
+ else
+ @set live_or_once
+
+ get_nested: (name) =>
+ if #@path > 0
+ name = "#{@path}.#{name}"
+
+ Cursor @state, name
+
+ __call: => @get!
+ __tostring: => @path
+ __eq: (other) => @path == other.path
+
+ @is_cursor: (val) ->
+ return unless val
+ return unless 'table' == type val
+ val.__class == @@
+
class State
@mt: {
__index: (t, k) ->
@@ -38,33 +85,21 @@ class State
default = val
rawset @, key, (rawget @, key) or default
- -- store and return a piece of state under 'key'.
- -- the current and stored value is the first of the following:
- -- * 'fixed', if it is a 'live' value
- -- * current state, if set
- -- * 'fixed', if it is a 'once' value
- -- * 'default'
- store: (key, fixed, default) =>
- state = rawget @, key
- once = Once.is_once fixed
-
- next_state = if is_live fixed
- fixed
- elseif state
- state
- elseif once
- fixed.value
- else
- default
-
- with next_state
- rawset @, key, next_state
-
new: =>
@reset!
reset: =>
- @state = setmetatable {}, @@mt
+ @values = setmetatable {}, {
+ __index: (k) =>
+ if Cursor.is_cursor k
+ k = tostring k
+ rawget @, k
+ __newindex: (k, v) =>
+ if Cursor.is_cursor k
+ k = tostring k
+ rawset @, k, v
+ }
+ @root = Cursor @
{
:is_once, :are_once