git.s-ol.nu watch-cad / e2dbd96
new state attempt s-ol 1 year, 10 months ago
2 changed file(s) with 142 addition(s) and 52 deletion(s). Raw diff Collapse all Expand all
1717 assert.is_falsy Once.is_once { a: 3 }
1818
1919 describe "State", ->
20 local S
20 local state
2121 before_each ->
2222 state = State!
23 S = state.state
2423
25 it "can be indexed infinitely", ->
26 assert.is_table S.a.b.c.d
24 it "stores values", ->
25 assert.is_nil state.values['my key']
26 state.values['my key'] = 'my val'
27 assert.is_equal 'my val', state.values['my key']
2728
28 describe ":init", ->
29 it "stores default until changed", ->
30 S\init 'test', 2
31 assert.is.equal 2, S.test
29 state.values['more'] = 4
30 assert.is_equal 4, state.values['more']
31 assert.is_equal 'my val', state.values['my key']
3232
33 S.test = 4
34 assert.is.equal 4, S.test
33 it "can be reset", ->
34 state.values['my key'] = 'my val'
35 state.values['more'] = 4
3536
36 S\init 'test', 2
37 assert.is.equal 4, S.test
37 state\reset!
38 assert.is_nil state.values['my key']
39 assert.is_nil state.values['more']
3840
39 describe ":store", ->
40 it "stores defaults until changed", ->
41 S\store 'test', nil, 3
42 assert.is.equal 3, S.test
41 describe "cursors", ->
42 it "can be nested with :get_nested()", ->
43 assert.is_table state.root\get_nested 'a'
44 assert.is_table state.root\get_nested('a')\get_nested 'b'
4345
44 S\store 'test', nil, 4
45 assert.is.equal 3, S.test
46 it "delegate __index to :get_nested", ->
47 assert.is_table state.root
48 assert.is_table state.root.a
49 assert.is_table state.root.a.b.c.d
4650
47 it "follows live inputs", ->
48 S\store 'test', 3, 'nope'
49 assert.is.equal 3, S.test
51 it "stringify to a key", ->
52 assert.is_equal '', tostring state.root
53 assert.is_equal 'a.b.c.d', tostring state.root.a.b.c.d
5054
51 S\store 'test', 4, 'nope'
52 assert.is.equal 4, S.test
55 it ":set() sets the value", ->
56 cursor = state.root.test
57 cursor\set 'the val'
58 assert.is_equal 'the val', state.values[cursor]
5359
54 it "lets Once() inputs override defaults", ->
55 S\store 'test', (Once 3), 'nope'
56 assert.is.equal 3, S.test
60 it ":set() returns the new value", ->
61 assert.is_equal 'val', state.root.test\set 'val'
5762
58 S\store 'test', 'changed'
63 it ":get() gets the value", ->
64 cursor = state.root.test
65 cursor\set 'the val'
66 assert.is_equal 'the val', cursor\get!
5967
60 S\store 'test', (Once 4), 'nope'
61 assert.is.equal 'changed', S.test
68 it ":init() sets the value unless already set", ->
69 cursor = state.root.test
70 cursor\init 'initial value'
71 assert.is_equal 'initial value', cursor!
72
73 cursor\init 'other value'
74 assert.is_equal 'initial value', cursor!
75
76 it ":init() returns the current value", ->
77 cursor = state.root.test
78 assert.is_equal 'initial value', cursor\init 'initial value'
79 assert.is_equal 'initial value', cursor\init 'other value'
80
81 it "can be called to get the value", ->
82 cursor = state.root.test
83 assert.is_nil cursor!
84 cursor\set 'the val'
85 assert.is_equal 'the val', cursor!
86
87 it "delegate __eq to string key", ->
88 assert.is_true state.root.a == state.root.a
89 assert.is_true state.root.a.b == state.root.a.b
90 assert.is_false state.root.a == state.root.b
91 assert.is_false state.root.a.b == state.root.a.c
92 assert.is_false state.root.a.b == state.root.c.b
93
94 describe ":drive()", ->
95 it "follows live inputs", ->
96 cursor = state.root.test
97 cursor\drive 3
98 assert.is_equal 3, cursor!
99
100 cursor\drive 'test'
101 assert.is_equal 'test', cursor!
102
103 it "initializes with Once() inputs", ->
104 cursor = state.root.test
105 cursor\drive Once 'initial'
106 assert.is_equal 'initial', cursor!
107
108 cursor\drive Once 'other'
109 assert.is_equal 'initial', cursor!
110
111 it "returns the current value", ->
112 cursor = state.root.test
113 assert.is_equal 'initial', cursor\drive Once 'initial'
114 assert.is_equal 'initial', cursor\drive Once 'other'
115 assert.is_equal 'live in', cursor\drive 'live in'
116
2121 are_once = all is_once
2222 are_live = all is_live
2323
24 class Cursor
25 @__base.__index = do
26 old_index = @__base.__index
27 (k) =>
28 if v = old_index[k]
29 return v
30
31 if 'string' == type k
32 return @get_nested k
33
34 new: (@state, @path='') =>
35
36 set: (value) =>
37 @state.values[@path] = value
38 value
39
40 get: (value) =>
41 @state.values[@path]
42
43 init: (value) =>
44 old = @get!
45 if old != nil
46 old
47 else
48 @set value
49
50 drive: (live_or_once) =>
51 if val = is_once live_or_once
52 @init val
53 else
54 @set live_or_once
55
56 get_nested: (name) =>
57 if #@path > 0
58 name = "#{@path}.#{name}"
59
60 Cursor @state, name
61
62 __call: => @get!
63 __tostring: => @path
64 __eq: (other) => @path == other.path
65
66 @is_cursor: (val) ->
67 return unless val
68 return unless 'table' == type val
69 val.__class == @@
70
2471 class State
2572 @mt: {
2673 __index: (t, k) ->
3784 default = val
3885 rawset @, key, (rawget @, key) or default
3986
40 -- store and return a piece of state under 'key'.
41 -- the current and stored value is the first of the following:
42 -- * 'fixed', if it is a 'live' value
43 -- * current state, if set
44 -- * 'fixed', if it is a 'once' value
45 -- * 'default'
46 store: (key, fixed, default) =>
47 state = rawget @, key
48 once = Once.is_once fixed
49
50 next_state = if is_live fixed
51 fixed
52 elseif state
53 state
54 elseif once
55 fixed.value
56 else
57 default
58
59 with next_state
60 rawset @, key, next_state
61
6287 new: =>
6388 @reset!
6489
6590 reset: =>
66 @state = setmetatable {}, @@mt
91 @values = setmetatable {}, {
92 __index: (k) =>
93 if Cursor.is_cursor k
94 k = tostring k
95 rawget @, k
96 __newindex: (k, v) =>
97 if Cursor.is_cursor k
98 k = tostring k
99 rawset @, k, v
100 }
101 @root = Cursor @
67102
68103 {
69104 :is_once, :are_once