decider 0.10.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of decider might be problematic. Click here for more details.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +14 -0
- data/Rakefile +52 -6
- data/VERSION +1 -0
- data/bin/8ball +29 -0
- data/bin/decider +5 -0
- data/lib/decider.rb +5 -390
- data/test/decider_test.rb +12 -0
- data/test/test_helper.rb +10 -0
- metadata +57 -97
- checksums.yaml +0 -7
- data/.standard.yml +0 -3
- data/CHANGELOG.md +0 -381
- data/LICENSE.txt +0 -21
- data/README.md +0 -152
- data/Steepfile +0 -26
- data/examples/decide.md +0 -180
- data/examples/evolve.md +0 -150
- data/examples/infra.md +0 -15
- data/examples/state.md +0 -55
- data/lib/decider/event_sourcing.rb +0 -25
- data/lib/decider/in_memory.rb +0 -26
- data/lib/decider/reactor.rb +0 -142
- data/lib/decider/state.rb +0 -25
- data/lib/decider/version.rb +0 -5
- data/lib/decider/view.rb +0 -169
- data/mise.toml +0 -17
- data/sig/decider.rbs +0 -16
data/lib/decider/reactor.rb
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Decider
|
|
4
|
-
module Reactor
|
|
5
|
-
class Module < ::Module
|
|
6
|
-
REACT_FALLBACK = proc { [nil, proc {}] }
|
|
7
|
-
|
|
8
|
-
React = Data.define(:action_result, :_actions) do
|
|
9
|
-
def issue(*actions)
|
|
10
|
-
_actions.push(*actions)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def initialize(reactions:)
|
|
15
|
-
define_method(:react) do |action_result|
|
|
16
|
-
context = React.new(action_result: action_result, _actions: [])
|
|
17
|
-
|
|
18
|
-
reactions.find(REACT_FALLBACK) do |arg, _|
|
|
19
|
-
case arg
|
|
20
|
-
in Proc => fn
|
|
21
|
-
context.instance_exec(&fn)
|
|
22
|
-
in artype
|
|
23
|
-
action_result in ^artype
|
|
24
|
-
else
|
|
25
|
-
false
|
|
26
|
-
end
|
|
27
|
-
end => [_, handler]
|
|
28
|
-
|
|
29
|
-
context.instance_exec(&handler)
|
|
30
|
-
context._actions
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
define_method(:lmap_on_action_result) do |fn|
|
|
34
|
-
Decider::Reactor.lmap_on_action_result(fn, self)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
define_method(:rmap_on_action) do |fn|
|
|
38
|
-
Decider::Reactor.rmap_on_action(fn, self)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
define_method(:map_on_action) do |fn|
|
|
42
|
-
Decider::Reactor.rmap_on_action(fn, self)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
define_method(:combine_with_decider) do |decider|
|
|
46
|
-
Decider::Reactor.combine_with_decider(self, decider)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
class Builder
|
|
52
|
-
DEFAULT = Object.new
|
|
53
|
-
|
|
54
|
-
def initialize
|
|
55
|
-
@reactions = {}
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def build(&block)
|
|
59
|
-
instance_exec(&block) if block_given?
|
|
60
|
-
|
|
61
|
-
reactor = Class.new
|
|
62
|
-
|
|
63
|
-
mod = Module.new(
|
|
64
|
-
reactions: reactions
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
reactor.extend(mod)
|
|
68
|
-
|
|
69
|
-
reactor
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
attr_reader :reactions
|
|
75
|
-
|
|
76
|
-
def react(arg, &block)
|
|
77
|
-
reactions[arg] = block
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
private_constant :Builder
|
|
81
|
-
|
|
82
|
-
def self.define(&block)
|
|
83
|
-
builder = Builder.new
|
|
84
|
-
builder.build(&block)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def self.lmap_on_action_result(fn, reactor)
|
|
88
|
-
define do
|
|
89
|
-
react proc { true } do
|
|
90
|
-
reactor.react(fn.call(action_result)).each do |action|
|
|
91
|
-
issue action
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def self.rmap_on_action(fn, reactor)
|
|
98
|
-
define do
|
|
99
|
-
react proc { true } do
|
|
100
|
-
reactor.react(action_result).each do |action|
|
|
101
|
-
issue fn.call(action)
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def self.map_on_action(fn, reactor)
|
|
108
|
-
rmap_on_action(fn, reactor)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def self.combine_with_decider(reactor, decider)
|
|
112
|
-
Decider.define do
|
|
113
|
-
initial_state decider.initial_state
|
|
114
|
-
|
|
115
|
-
decide proc { true } do
|
|
116
|
-
fn = ->(commands, events, ds) {
|
|
117
|
-
case commands
|
|
118
|
-
in []
|
|
119
|
-
events
|
|
120
|
-
in [head, *tail]
|
|
121
|
-
new_events = decider.decide(head, ds)
|
|
122
|
-
new_commands = new_events.flat_map { |action_result| reactor.react(action_result) }
|
|
123
|
-
new_state = new_events.reduce(ds, &decider.evolve)
|
|
124
|
-
|
|
125
|
-
fn.call(tail + new_commands, events + new_events, new_state)
|
|
126
|
-
end
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
fn.call([command], [], state).each { |event| emit event }
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
evolve proc { true } do
|
|
133
|
-
decider.evolve(state, event)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
terminal? do
|
|
137
|
-
decider.terminal?(state)
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
data/lib/decider/state.rb
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Decider
|
|
4
|
-
class State
|
|
5
|
-
def initialize(decider:, repository:)
|
|
6
|
-
@decider = decider
|
|
7
|
-
@repository = repository
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def call(command, key:, etag: nil)
|
|
11
|
-
state, etag = repository.try_load(key: key, etag: etag)
|
|
12
|
-
|
|
13
|
-
events = decider.decide(command, state)
|
|
14
|
-
new_state = events.reduce(state, &decider.method(:evolve))
|
|
15
|
-
|
|
16
|
-
new_etag = repository.save(new_state, key: key, etag: etag)
|
|
17
|
-
|
|
18
|
-
[events, new_etag]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
attr_reader :decider, :repository
|
|
24
|
-
end
|
|
25
|
-
end
|
data/lib/decider/version.rb
DELETED
data/lib/decider/view.rb
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Decider::View
|
|
4
|
-
StateAlreadyDefined = Class.new(StandardError)
|
|
5
|
-
StateNotDefined = Class.new(StandardError)
|
|
6
|
-
|
|
7
|
-
class Module < ::Module
|
|
8
|
-
EVOLVE_FALLBACK = proc { [nil, proc { state }] }
|
|
9
|
-
|
|
10
|
-
Evolve = Data.define(:state, :event) do
|
|
11
|
-
def self.build(state, event)
|
|
12
|
-
new(state: state, event: event)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def initialize(initial_state:, evolutions:)
|
|
17
|
-
case initial_state
|
|
18
|
-
in Proc
|
|
19
|
-
define_method(:initial_state) do
|
|
20
|
-
initial_state.call
|
|
21
|
-
end
|
|
22
|
-
else
|
|
23
|
-
define_method(:initial_state) do
|
|
24
|
-
initial_state
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
define_method(:evolve) do |*args|
|
|
29
|
-
if args.empty?
|
|
30
|
-
->(state, event) { evolve(state, event) }
|
|
31
|
-
else
|
|
32
|
-
context = Evolve.build(*args)
|
|
33
|
-
|
|
34
|
-
evolutions.find(EVOLVE_FALLBACK) do |args, _|
|
|
35
|
-
case args
|
|
36
|
-
in [Proc => fn]
|
|
37
|
-
context.instance_exec(&fn)
|
|
38
|
-
in [etype]
|
|
39
|
-
context_event = context.event
|
|
40
|
-
context_event in ^etype
|
|
41
|
-
in [stype, etype]
|
|
42
|
-
context_state = context.state
|
|
43
|
-
context_event = context.event
|
|
44
|
-
[context_state, context_event] in [^stype, ^etype]
|
|
45
|
-
else
|
|
46
|
-
false
|
|
47
|
-
end
|
|
48
|
-
end => [_, handler]
|
|
49
|
-
|
|
50
|
-
context.instance_exec(&handler)
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
define_method(:lmap_on_event) do |fn|
|
|
55
|
-
Decider::View.lmap_on_event(fn, self)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
define_method(:lmap_on_state) do |fn|
|
|
59
|
-
Decider::View.lmap_on_state(fn, self)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
define_method(:rmap_on_state) do |fn|
|
|
63
|
-
Decider::View.rmap_on_state(fn, self)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
define_method(:dimap_on_state) do |fl:, fr:|
|
|
67
|
-
Decider::View.dimap_on_state(fl, fr, self)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
define_method(:many) do
|
|
71
|
-
Decider::View.many(self)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
class Builder
|
|
77
|
-
DEFAULT = Object.new
|
|
78
|
-
|
|
79
|
-
def initialize
|
|
80
|
-
@initial_state = DEFAULT
|
|
81
|
-
@evolutions = {}
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def build(&block)
|
|
85
|
-
instance_exec(&block) if block_given?
|
|
86
|
-
|
|
87
|
-
raise StateNotDefined if @initial_state == DEFAULT
|
|
88
|
-
|
|
89
|
-
view = Class.new
|
|
90
|
-
|
|
91
|
-
mod = Module.new(
|
|
92
|
-
initial_state: @initial_state,
|
|
93
|
-
evolutions: evolutions
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
view.extend(mod)
|
|
97
|
-
|
|
98
|
-
view
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
private
|
|
102
|
-
|
|
103
|
-
attr_reader :evolutions
|
|
104
|
-
|
|
105
|
-
def initial_state(state = DEFAULT, &block)
|
|
106
|
-
raise StateAlreadyDefined if @initial_state != DEFAULT
|
|
107
|
-
|
|
108
|
-
@initial_state =
|
|
109
|
-
if block_given?
|
|
110
|
-
block
|
|
111
|
-
else
|
|
112
|
-
state
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def evolve(*args, &block)
|
|
117
|
-
evolutions[args] = block
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
private_constant :Builder
|
|
121
|
-
|
|
122
|
-
def self.define(&block)
|
|
123
|
-
builder = Builder.new
|
|
124
|
-
builder.build(&block)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def self.lmap_on_event(fn, view)
|
|
128
|
-
define do
|
|
129
|
-
initial_state view.initial_state
|
|
130
|
-
|
|
131
|
-
evolve proc { true } do
|
|
132
|
-
view.evolve(state, fn.call(event))
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def self.lmap_on_state(fn, view)
|
|
138
|
-
dimap_on_state(fn, ->(state) { state }, view)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def self.rmap_on_state(fn, view)
|
|
142
|
-
dimap_on_state(->(state) { state }, fn, view)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def self.dimap_on_state(fl, fr, view)
|
|
146
|
-
define do
|
|
147
|
-
initial_state fr.call(view.initial_state)
|
|
148
|
-
|
|
149
|
-
evolve proc { true } do
|
|
150
|
-
fr.call(view.evolve(fl.call(state), event))
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def self.many(view)
|
|
156
|
-
define do
|
|
157
|
-
initial_state({})
|
|
158
|
-
|
|
159
|
-
evolve proc { [state, event] in [Hash, [_id, _]] } do
|
|
160
|
-
event => [id, event]
|
|
161
|
-
|
|
162
|
-
vs = state.fetch(id) { view.initial_state }
|
|
163
|
-
vs = view.evolve(vs, event)
|
|
164
|
-
|
|
165
|
-
state.merge(id => vs)
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
data/mise.toml
DELETED
data/sig/decider.rbs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module Decider
|
|
2
|
-
VERSION: String
|
|
3
|
-
|
|
4
|
-
interface _Decider[C, S, E]
|
|
5
|
-
def decide: (C, S) -> Array[E]
|
|
6
|
-
|
|
7
|
-
def evolve: (S, E) -> S
|
|
8
|
-
|
|
9
|
-
def initial_state: () -> S
|
|
10
|
-
|
|
11
|
-
def terminal?: (S) -> bool
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def self.compose: [C1, S1, E1, C2, S2, E2] (_Decider[C1, S1, E1], _Decider[C2, S2, E2]) -> _Decider[C1 | C2, S1 & S2, E1 | E2]
|
|
15
|
-
def self.define: [C, S, E] () -> _Decider[C, S, E]
|
|
16
|
-
end
|