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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# writing `alive` plugins
Plugins for `alive` are implemented in [Lua][lua] or [MoonScript][moonscript]
(which runs as Lua). When an `alive` module is [require][]d, alive looks for a
Lua module `lib.[module]`. You can simply add a new file with extension `.lua`
or `.moon` in the `lib` directory of your alive installation or somewhere else
in your `LUA_PATH`.
To write plugins, a number of classes and utilities are required. All of these
are exported in the `base` module.
## documentation metadata
The lua module should return a `Scope` or a table that will be converted using
`Scope.from_table`. All exports should be documented using `Value.meta`, which
attaches a `meta` table to the value that is used for error messages,
documentation generation and [`(doc)`][builtins-doc].
import Value from require 'core.base'
two = Value.meta
meta:
name: 'two'
summary: "the number two"
value: 2
{
:two
}
In the `meta` table `summary` is the only required key, but all of the
information that applies should be provided.
- `name`: the name of this export (for error reporting).
- `summary`: a one-line plain-text description of this entry. Should be
capitalized and end with a period.
- `examples`: a table of strings, each of which is a short one-line code
example illustrating the argument names for an Op.
- `description`: a longer markdown-formatted description of the functionality
of this entry.
## defining `Op`s
Most plugins will want to define a number of *Op*s to be used by the user. They
are implemented by deriving from the `Op` class and implementing at least the
`Op:setup` and `Op:tick` methods.
import Value, Op, Input, match from require 'core.base'
my_add = Value.meta
meta:
name: 'my-add'
summary: "Add two numbers."
examples: { '(my-add a b)' }
description: "Add two numbers, plugin-style."
value: class extends Op
new: => super 'num'
setup: (inputs, scope) =>
{ a, b } = match 'num num', inputs
super
a: Inputs.value a
b: Inputs.value b
tick: =>
@out\set @inputs.a! + @inputs.b!
{
'my-add': my_add
}
### Op:setup
`Op:setup` is called once every *eval cycle* to parse the Op's arguments, check
their types, choose the updating behaviour and define the output type.
The arguments to `:setup` are a list of inputs (each is a `Result` instance),
and the `Scope` the evaluation happened in. Ops generally shouldn't use the
scope, but might look up 'magic' dynamic symbols like `\*clock\*`.
#### argument parsing
Arguments should be parsed using `match`. It takes a string that describes the
argument types and matches them against the provided arguments:
import match from require 'core.base'
{ str, numbers, optional } = match 'str *num any?', inputs
`match` matches arguments greedily from left to right. Each part of the string
is the type-name of a Value. Parts can be optional (`num?`), multiple (`*num` -
one or more numbers) or both (`*num?` - zero or more numbers). If there is an
equals sign in front of a part, the corresponding `Result` has to be
*evaltime constant*. The special typename `any` can be used for generic Ops.
If there are more complex dependencies between arguments, it is recommended to
do as much of the parsing as possible using `match`, and then continue
manually. For invalid or missing arguments, `Error` instances should be thrown
using `error` or `assert`.
#### input setup
(section wip since changes are anticipated)
#### output setup
When `Op:setup` finishes, `@out` has to be set to a `Value` instance. The
instance can be created in `Op:setup`, or by overriding the constructor and
delegating to the original one using `super`. In general this way of creating
the output value is preferred, and it is only moved to `Op:setup` if the output
type depends on the arguments received.
### Op:tick
`Op:tick` is called whenever any of the inputs are *dirty*. This is where the
Op's main logic will go. Generally here it should be checked which input(s)
changed, and then internal state and the output value may be updated.
## defining `Action`s
`Action`s are more powerful than `Op`s, because they control whether, which and
how their arguments are evaluated. They roughly correspond to *macros* in Lisps.
Since it is rarely necessary to implement `Action`s, there is currently no
documentation on implementing them, but the `Action` class documentation and the
examples in `core/builtin.moon` should be enough to get started.
## `IO`s
(wip)
[lua]: https://www.lua.org/
[moonscript]: http://moonscript.org/
[builtins-doc]: ../../reference/index.html#doc
|