decide.rb 0.7.1 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ac9878aee3455667ca2fa5e7b4226af3588387e8f42a5a67e102b96c9b2e74d
4
- data.tar.gz: 3f168429cc20342dca21ab57ad82ab498e3ee2d83623713c3f730966d05e7032
3
+ metadata.gz: ae980af0098467da425746f3d2cb9cf41eb67301dea7b369d36ddbba09357414
4
+ data.tar.gz: 42b2d4110c43de9aa88c33704caf9e53ca9f3bdc346ea0c5108ffe3f34c35d2d
5
5
  SHA512:
6
- metadata.gz: b8b3240f864d16a1c31eb2575ec700a0bd5674feee8818fe2e6342e2c0807cc8f0c6ac9fc780699d6ccc0c896ce615f829b7d121c7d059c2f3dad1aef192e321
7
- data.tar.gz: 3098b0a090dbe5b71eb90cefa2e57127632d40b333aa678c0a0ee6a09bc26e351b3005554bf259ad2011cc4745aef32a158f57cd8d93980efe2c0df33edf3c53
6
+ metadata.gz: 3d49815edc97d5d4ae52b6c46b320f2b560bb137f7c45cd87b52855d6e420c3bd342985f423c42c9283d4ef3adfa218b14605e409362e5c8ffb81c6ea1803c2d
7
+ data.tar.gz: 3e36c74937ce1bbf65df117fa541f1ca9a51d6ff859db7ee8ab5d941a14b34f7ec61a643384f58e28c920b7368f15bd855f578d4ca53e2471a46c0452b88125a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ # 0.8.0
2
+
3
+ * Add view that can evolve from initial state
4
+
5
+ ```ruby
6
+ view = Decider::View.define do
7
+ initial_state 0
8
+
9
+ evolve :increased do
10
+ state + 1
11
+ end
12
+
13
+ evolve :decreased do
14
+ state - 1
15
+ end
16
+ end
17
+ ```
18
+
19
+ * Add `lmap_on_event`, `dimap_on_state`, `lmap_on_state` and `rmap_on_state` extensions for view
20
+
1
21
  # 0.7.0
2
22
 
3
23
  * Add reactor that can react to action results and issue actions
@@ -6,7 +26,7 @@
6
26
  ActionResult = Data.define(:value)
7
27
  Action = Data.define(:value)
8
28
 
9
- reactor = Reactor.define do
29
+ reactor = Decider::Reactor.define do
10
30
  react :action_result do
11
31
  issue :action
12
32
  issue :another_action
@@ -82,7 +102,7 @@ deciders.evolve(state, [id, event])
82
102
 
83
103
  ```ruby
84
104
  decider = Decider.map(fn.curry, deciderx)
85
- decider = Decider.apply(decider, decidery)
105
+ decider = Decider.apply(decider, decidery)
86
106
  decider = Decider.apply(decider, deciderz)
87
107
  # or
88
108
  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.0"
5
5
  end
@@ -0,0 +1,132 @@
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 in ^etype
30
+ in [stype, etype]
31
+ [context.state, context.event] in [^stype, ^etype]
32
+ else
33
+ false
34
+ end
35
+ end => [_, handler]
36
+
37
+ context.instance_exec(&handler)
38
+ end
39
+ end
40
+
41
+ define_method(:lmap_on_event) do |fn|
42
+ Decider::View.lmap_on_event(fn, self)
43
+ end
44
+
45
+ define_method(:lmap_on_state) do |fn|
46
+ Decider::View.lmap_on_state(fn, self)
47
+ end
48
+
49
+ define_method(:rmap_on_state) do |fn|
50
+ Decider::View.rmap_on_state(fn, self)
51
+ end
52
+
53
+ define_method(:dimap_on_state) do |fl:, fr:|
54
+ Decider::View.dimap_on_state(fl, fr, self)
55
+ end
56
+ end
57
+ end
58
+
59
+ class Builder
60
+ DEFAULT = Object.new
61
+
62
+ def initialize
63
+ @initial_state = DEFAULT
64
+ @evolutions = {}
65
+ end
66
+
67
+ def build(&block)
68
+ instance_exec(&block) if block_given?
69
+
70
+ raise StateNotDefined if @initial_state == DEFAULT
71
+
72
+ view = Class.new
73
+
74
+ mod = Module.new(
75
+ initial_state: @initial_state,
76
+ evolutions: evolutions
77
+ )
78
+
79
+ view.extend(mod)
80
+
81
+ view
82
+ end
83
+
84
+ private
85
+
86
+ attr_reader :evolutions
87
+
88
+ def initial_state(state)
89
+ raise StateAlreadyDefined if @initial_state != DEFAULT
90
+
91
+ @initial_state = state
92
+ end
93
+
94
+ def evolve(*args, &block)
95
+ evolutions[args] = block
96
+ end
97
+ end
98
+ private_constant :Builder
99
+
100
+ def self.define(&block)
101
+ builder = Builder.new
102
+ builder.build(&block)
103
+ end
104
+
105
+ def self.lmap_on_event(fn, view)
106
+ define do
107
+ initial_state view.initial_state
108
+
109
+ evolve proc { true } do
110
+ view.evolve(state, fn.call(event))
111
+ end
112
+ end
113
+ end
114
+
115
+ def self.lmap_on_state(fn, view)
116
+ dimap_on_state(fn, ->(state) { state }, view)
117
+ end
118
+
119
+ def self.rmap_on_state(fn, view)
120
+ dimap_on_state(->(state) { state }, fn, view)
121
+ end
122
+
123
+ def self.dimap_on_state(fl, fr, view)
124
+ define do
125
+ initial_state fr.call(view.initial_state)
126
+
127
+ evolve proc { true } do
128
+ fr.call(view.evolve(fl.call(state), event))
129
+ end
130
+ end
131
+ end
132
+ 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)
@@ -155,8 +156,6 @@ module Decider
155
156
  class Builder
156
157
  DEFAULT = Object.new
157
158
 
158
- attr_reader :module
159
-
160
159
  def initialize
161
160
  @initial_state = DEFAULT
162
161
  @deciders = {}
@@ -171,14 +170,14 @@ module Decider
171
170
 
172
171
  decider = Class.new
173
172
 
174
- @module = Module.new(
173
+ mod = Module.new(
175
174
  initial_state: @initial_state,
176
175
  deciders: deciders,
177
176
  evolutions: evolutions,
178
177
  terminal: terminal
179
178
  )
180
179
 
181
- decider.extend(@module)
180
+ decider.extend(mod)
182
181
 
183
182
  decider
184
183
  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.0
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: []