-
Notifications
You must be signed in to change notification settings - Fork 4
/
ncmd.py
73 lines (60 loc) · 2.21 KB
/
ncmd.py
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
import inspect
"""
An immutable class representing a command, which is anything that has a side
effect or is asynchronous.
"""
class Cmd:
def __init__(self, performer_getter, map_functions=None, dependent=None):
# A non-async function that, when given the result from `dependent`,
# returns a function (can be async or not) that performs the side
# effect. The function-returning function should ideally should be
# pure.
self.performer_getter = performer_getter
# Transform functions to perform on the resulting value
self.map_functions = map_functions or []
# A Cmd that should be performed first before performing this command.
# The result from this Cmd will be passed to `performer_getter` for this
# Cmd's command.
self.dependent = dependent
def map(self, function):
return type(self)(
self.performer_getter,
map_functions=[*self.map_functions, function],
dependent=self.dependent,
)
def then(self, then_command_getter):
return type(self)(then_command_getter, dependent=self)
async def eval(self):
if self.dependent:
result = await self.dependent.eval()
else:
result = ()
for function in self.map_functions:
result = function(result)
performer = self.performer_getter(result)
maybe_awaitable = performer()
if inspect.isawaitable(maybe_awaitable):
return await maybe_awaitable
else:
return maybe_awaitable
def __repr__(self):
return "Cmd(%s, map_functions=%s, dependent=%s)" % (
repr(self.performer_getter),
repr(self.map_functions),
repr(self.dependent),
)
@classmethod
def from_value(Cls, value):
"""
Create a Cmd that simply returns the given value.
"""
return Cls(lambda _: lambda: value)
@classmethod
def wrap(Cls, maybe_cmd):
"""
Ensures that `maybe_cmd` is a Cmd by wrapping it in one if it's not.
"""
if isinstance(maybe_cmd, Cls):
return maybe_cmd
else:
return Cls.from_value(maybe_cmd)