This gem provides simple DSL for building Functional Event Sourcing Decider in Ruby. To learn more about the pattern read the original article by Jérémie Chassaing.
Special credits for Ismael Celis for inspiration.
gem install decide.rb
or add to Gemfile
gem "decide.rb"
require "decider"
State = Data.define(:value) do
def max?
value >= MAX
end
def min?
value <= MIN
end
end
module Commands
Increase = Data.define
Decrease = Data.define
end
module Events
ValueIncreased = Data.define
ValueDecreased = Data.define
end
MIN = 0
MAX = 100
ValueDecider = Decider.define do
# define intial state
initial_state State.new(value: 0)
# decide command with state
decide Commands::Increase do
# return collection of events
if state.max?
[]
else
[Events::ValueIncreased.new]
end
end
decide Commands::Decrease do
if state.min?
[]
else
[Events::ValueDecreased.new]
end
end
# evolve state with events
evolve Events::ValueIncreased do
# return new state
state.with(value: state.value + 1)
end
evolve Events::ValueDecreased do
# state is immutable Data object
state.with(value: state.value - 1)
end
terminal? do
state <= 0
end
end
state = ValueDecider.initial_state
events = ValueDecider.decide(Commands::Increase.new, state)
new_state = events.reduce(state) { |state, event| ValueDecider.evolve(state, events)
You can also compose deciders:
Left = Data.define(:value)
Right = Data.define(:value)
left = Decider.define do
initial_state Left.new(value: 0)
decide Commands::LeftCommand do
[Events::LeftEvent.new(value: command.value)]
end
evolve Events::LeftEvent do
state.with(value: state.value + 1)
end
terminal? do
state <= 0
end
end
right = Decider.define do
initial_state Right.new(value: 0)
decide Commands::RightCommand do
[Events::RightEvent.new(value: command.value)]
end
evolve Events::RightEvent do
state.with(value: state.value + 1)
end
terminal? do
state <= 0
end
end
Composition = Decider.compose(left, right)
state = Composition.initial_state
#> #<data Decider::Pair left=#<data Left value=0>, right=#<data Right value=0>>
events = Composition.decide(Decider::Left.new(Commands::LeftCommand.new(value: 1)), state)
#> [#<Decider::Left value=#<data value=1>]
state = events.reduce(state, &Composition.method(:evolve))
#> #<data Decider::Pair left=#<data value=1>, right=#<data value=0>>
After checking out the repo, run bin/setup
to install dependencies. Then, run rake test
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/decider.
The gem is available as open source under the terms of the MIT License.