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