Created
November 16, 2024 23:31
-
-
Save jandudulski/d69acfefd97fd58abb257f2c679d965f to your computer and use it in GitHub Desktop.
Revisions
-
jandudulski created this gist
Nov 16, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,179 @@ # Example based on https://github.com/thinkbeforecoding/dddeu-2023-deciders/blob/main/run.fsx require "bundler/inline" gemfile do source "https://rubygems.org" gem "minitest" gem "decide.rb", "~> 0.4.1" end require "minitest/autorun" require "decider" module Bulb module Commands Fit = Data.define(:max_uses) SwitchOn = Data.define SwitchOff = Data.define end module Events Fitted = Data.define(:max_uses) SwitchedOn = Data.define SwitchedOff = Data.define Blew = Data.define end module States NotFitted = Data.define Working = Data.define(:status, :remaining_uses) Blown = Data.define end Decider = ::Decider.define do initial_state States::NotFitted.new terminal? { _1.is_a? Blown } decide Commands::Fit do |command, state| case state in States::NotFitted [Events::Fitted.new(command.max_uses)] else raise "Bulb has already been fitted" end end decide Commands::SwitchOn do |command, state| case state in States::Working(status: :off, remaining_uses:) if remaining_uses > 0 [Events::SwitchedOn.new] in States::Working(status: :off) [Events::Blew.new] else [] end end decide Commands::SwitchOff do |command, state| case state in States::Working(status: :on) [Events::SwitchedOff.new] else [] end end evolve Events::Fitted do |state, event| States::Working.new(status: :off, remaining_uses: event.max_uses) end evolve Events::SwitchedOn do |state, event| state.with(status: :on, remaining_uses: state.remaining_uses - 1) end evolve Events::SwitchedOff do |state, event| state.with(status: :off) end evolve Events::Blew do |state, event| States::Blown.new end end end class TestDecide < Minitest::Test def decider = Bulb::Decider def given(events) @state = events.reduce(decider.initial_state, &decider.method(:evolve)) self end def when(command) @events = decider.decide(command, @state) self end def expect(expected) assert_equal(expected, @events) end def test_fit given( [] ).when( Bulb::Commands::Fit.new(max_uses: 5) ).expect( [Bulb::Events::Fitted.new(max_uses: 5)] ) end def test_switch_on given( [Bulb::Events::Fitted.new(max_uses: 5)] ).when( Bulb::Commands::SwitchOn.new ).expect( [Bulb::Events::SwitchedOn.new] ) end def test_switch_on_already_on given( [ Bulb::Events::Fitted.new(max_uses: 5), Bulb::Events::SwitchedOn.new ] ).when( Bulb::Commands::SwitchOn.new ).expect( [] ) end def test_switch_off given( [ Bulb::Events::Fitted.new(max_uses: 5), Bulb::Events::SwitchedOn.new ] ).when( Bulb::Commands::SwitchOff.new ).expect( [Bulb::Events::SwitchedOff.new] ) end def test_switch_off_already_off given( [ Bulb::Events::Fitted.new(max_uses: 5), Bulb::Events::SwitchedOn.new, Bulb::Events::SwitchedOff.new ] ).when( Bulb::Commands::SwitchOff.new ).expect( [] ) end def test_blew given( [ Bulb::Events::Fitted.new(max_uses: 1), Bulb::Events::SwitchedOn.new, Bulb::Events::SwitchedOff.new ] ).when( Bulb::Commands::SwitchOn.new ).expect( [Bulb::Events::Blew.new] ) end end