decide.rb 0.7.1 → 0.8.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ac9878aee3455667ca2fa5e7b4226af3588387e8f42a5a67e102b96c9b2e74d
4
- data.tar.gz: 3f168429cc20342dca21ab57ad82ab498e3ee2d83623713c3f730966d05e7032
3
+ metadata.gz: 4030eca80006638366697ffbe43f1881fa15229903086103d64416f704c8c431
4
+ data.tar.gz: c8896b205ef5d24b098a7fb61bae4a287980a01508a1c4ce94ec602d7ee6fc08
5
5
  SHA512:
6
- metadata.gz: b8b3240f864d16a1c31eb2575ec700a0bd5674feee8818fe2e6342e2c0807cc8f0c6ac9fc780699d6ccc0c896ce615f829b7d121c7d059c2f3dad1aef192e321
7
- data.tar.gz: 3098b0a090dbe5b71eb90cefa2e57127632d40b333aa678c0a0ee6a09bc26e351b3005554bf259ad2011cc4745aef32a158f57cd8d93980efe2c0df33edf3c53
6
+ metadata.gz: 4a64615c3f4ad63a0501ca740dfd8368a28004e1f76239c60b583e835c5a61dce095ee424f80d802df7058306b49d4ff7a59030cff1417a76991e9ee08275abd
7
+ data.tar.gz: 763ffe70ba2be9a55f8d51c6176632e63fe1bc3138c2f95dbe747d28b73eb8039894364a5cef3449b0adc79365569dee6eb01bbac761cee9813f5551cc469cb1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ # 0.8.1
2
+
3
+ * Fix support for Ruby > 3.4.5
4
+
5
+ # 0.8.0
6
+
7
+ * Add view that can evolve from initial state
8
+
9
+ ```ruby
10
+ view = Decider::View.define do
11
+ initial_state 0
12
+
13
+ evolve :increased do
14
+ state + 1
15
+ end
16
+
17
+ evolve :decreased do
18
+ state - 1
19
+ end
20
+ end
21
+ ```
22
+
23
+ * Add `lmap_on_event`, `dimap_on_state`, `lmap_on_state` and `rmap_on_state` extensions for view
24
+
1
25
  # 0.7.0
2
26
 
3
27
  * Add reactor that can react to action results and issue actions
@@ -6,7 +30,7 @@
6
30
  ActionResult = Data.define(:value)
7
31
  Action = Data.define(:value)
8
32
 
9
- reactor = Reactor.define do
33
+ reactor = Decider::Reactor.define do
10
34
  react :action_result do
11
35
  issue :action
12
36
  issue :another_action
@@ -82,7 +106,7 @@ deciders.evolve(state, [id, event])
82
106
 
83
107
  ```ruby
84
108
  decider = Decider.map(fn.curry, deciderx)
85
- decider = Decider.apply(decider, decidery)
109
+ decider = Decider.apply(decider, decidery)
86
110
  decider = Decider.apply(decider, deciderz)
87
111
  # or
88
112
  deciderx.map(fn.curry).apply(decidery).apply(deciderz)
@@ -51,8 +51,6 @@ module Decider
51
51
  class Builder
52
52
  DEFAULT = Object.new
53
53
 
54
- attr_reader :module
55
-
56
54
  def initialize
57
55
  @reactions = {}
58
56
  end
@@ -62,11 +60,11 @@ module Decider
62
60
 
63
61
  reactor = Class.new
64
62
 
65
- @module = Module.new(
63
+ mod = Module.new(
66
64
  reactions: reactions
67
65
  )
68
66
 
69
- reactor.extend(@module)
67
+ reactor.extend(mod)
70
68
 
71
69
  reactor
72
70
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Decider
4
- VERSION = "0.7.1"
4
+ VERSION = "0.8.1"
5
5
  end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decider::View
4
+ class Module < ::Module
5
+ EVOLVE_FALLBACK = proc { [nil, proc { state }] }
6
+
7
+ Evolve = Data.define(:state, :event) do
8
+ def self.build(state, event)
9
+ new(state: state, event: event)
10
+ end
11
+ end
12
+
13
+ def initialize(initial_state:, evolutions:)
14
+ define_method(:initial_state) do
15
+ initial_state
16
+ end
17
+
18
+ define_method(:evolve) do |*args|
19
+ if args.empty?
20
+ ->(state, event) { evolve(state, event) }
21
+ else
22
+ context = Evolve.build(*args)
23
+
24
+ evolutions.find(EVOLVE_FALLBACK) do |args, _|
25
+ case args
26
+ in [Proc => fn]
27
+ context.instance_exec(&fn)
28
+ in [etype]
29
+ context_event = context.event
30
+ context_event in ^etype
31
+ in [stype, etype]
32
+ context_state = context.state
33
+ context_event = context.event
34
+ [context_state, context_event] in [^stype, ^etype]
35
+ else
36
+ false
37
+ end
38
+ end => [_, handler]
39
+
40
+ context.instance_exec(&handler)
41
+ end
42
+ end
43
+
44
+ define_method(:lmap_on_event) do |fn|
45
+ Decider::View.lmap_on_event(fn, self)
46
+ end
47
+
48
+ define_method(:lmap_on_state) do |fn|
49
+ Decider::View.lmap_on_state(fn, self)
50
+ end
51
+
52
+ define_method(:rmap_on_state) do |fn|
53
+ Decider::View.rmap_on_state(fn, self)
54
+ end
55
+
56
+ define_method(:dimap_on_state) do |fl:, fr:|
57
+ Decider::View.dimap_on_state(fl, fr, self)
58
+ end
59
+ end
60
+ end
61
+
62
+ class Builder
63
+ DEFAULT = Object.new
64
+
65
+ def initialize
66
+ @initial_state = DEFAULT
67
+ @evolutions = {}
68
+ end
69
+
70
+ def build(&block)
71
+ instance_exec(&block) if block_given?
72
+
73
+ raise StateNotDefined if @initial_state == DEFAULT
74
+
75
+ view = Class.new
76
+
77
+ mod = Module.new(
78
+ initial_state: @initial_state,
79
+ evolutions: evolutions
80
+ )
81
+
82
+ view.extend(mod)
83
+
84
+ view
85
+ end
86
+
87
+ private
88
+
89
+ attr_reader :evolutions
90
+
91
+ def initial_state(state)
92
+ raise StateAlreadyDefined if @initial_state != DEFAULT
93
+
94
+ @initial_state = state
95
+ end
96
+
97
+ def evolve(*args, &block)
98
+ evolutions[args] = block
99
+ end
100
+ end
101
+ private_constant :Builder
102
+
103
+ def self.define(&block)
104
+ builder = Builder.new
105
+ builder.build(&block)
106
+ end
107
+
108
+ def self.lmap_on_event(fn, view)
109
+ define do
110
+ initial_state view.initial_state
111
+
112
+ evolve proc { true } do
113
+ view.evolve(state, fn.call(event))
114
+ end
115
+ end
116
+ end
117
+
118
+ def self.lmap_on_state(fn, view)
119
+ dimap_on_state(fn, ->(state) { state }, view)
120
+ end
121
+
122
+ def self.rmap_on_state(fn, view)
123
+ dimap_on_state(->(state) { state }, fn, view)
124
+ end
125
+
126
+ def self.dimap_on_state(fl, fr, view)
127
+ define do
128
+ initial_state fr.call(view.initial_state)
129
+
130
+ evolve proc { true } do
131
+ fr.call(view.evolve(fl.call(state), event))
132
+ end
133
+ end
134
+ end
135
+ end
data/lib/decider.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "decider/reactor"
3
+ require_relative "decider/reactor"
4
+ require_relative "decider/view"
4
5
 
5
6
  module Decider
6
7
  StateAlreadyDefined = Class.new(StandardError)
@@ -92,9 +93,12 @@ module Decider
92
93
  in [Proc => fn]
93
94
  context.instance_exec(&fn)
94
95
  in [etype]
95
- context.event in ^etype
96
+ context_event = context.event
97
+ context_event in ^etype
96
98
  in [stype, etype]
97
- [context.state, context.event] in [^stype, ^etype]
99
+ context_state = context.state
100
+ context_event = context.event
101
+ [context_state, context_event] in [^stype, ^etype]
98
102
  else
99
103
  false
100
104
  end
@@ -155,8 +159,6 @@ module Decider
155
159
  class Builder
156
160
  DEFAULT = Object.new
157
161
 
158
- attr_reader :module
159
-
160
162
  def initialize
161
163
  @initial_state = DEFAULT
162
164
  @deciders = {}
@@ -171,14 +173,14 @@ module Decider
171
173
 
172
174
  decider = Class.new
173
175
 
174
- @module = Module.new(
176
+ mod = Module.new(
175
177
  initial_state: @initial_state,
176
178
  deciders: deciders,
177
179
  evolutions: evolutions,
178
180
  terminal: terminal
179
181
  )
180
182
 
181
- decider.extend(@module)
183
+ decider.extend(mod)
182
184
 
183
185
  decider
184
186
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decide.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Dudulski
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-07-23 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: concurrent-ruby
@@ -74,6 +74,7 @@ files:
74
74
  - lib/decider/reactor.rb
75
75
  - lib/decider/state.rb
76
76
  - lib/decider/version.rb
77
+ - lib/decider/view.rb
77
78
  - sig/decider.rbs
78
79
  homepage: https://github.com/jandudulski/decide.rb
79
80
  licenses:
@@ -99,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
100
  - !ruby/object:Gem::Version
100
101
  version: '0'
101
102
  requirements: []
102
- rubygems_version: 3.6.2
103
+ rubygems_version: 3.6.9
103
104
  specification_version: 4
104
105
  summary: Functional Event Sourcing Decider in Ruby
105
106
  test_files: []