aboutsummaryrefslogtreecommitdiffstats
path: root/state.moon
blob: 7630fb129812c6c378952487f70a37583c0f0136 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
unpack = unpack or table.unpack

class Once
  new: (@value) =>

  @is_once: (val) ->
    return false unless val
    return false unless 'table' == type val
    val.__class == @@

is_once = (val) -> (Once.is_once val) and val.value
is_live = (val) -> (not Once.is_once val) and val

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 false unless val
    return false unless 'table' == type val
    val.__class == @@

class State
  @mt: {
    __index: (t, k) ->
      if v = @[k]
        return v

      with v = setmetatable {}, @@mt
        rawset t, k, v
  }

  -- initialize state under 'key' with 'default' unless already set
  init: (key, default) =>
    if val = is_once default
      default = val
    rawset @, key, (rawget @, key) or default

  new: =>
    @reset!

  reset: =>
    @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
  :is_live
  :Once
  :Cursor
  :State
}