geekq / workflow

Ruby finite-state-machine-inspired API for modeling workflow
MIT License
1.74k stars 207 forks source link

Illegal state transitions #240

Open aThorp96 opened 4 months ago

aThorp96 commented 4 months ago

When changing a transition using event input as is done in the discard event method, it's possible to get into illegal state transitions when not halting the current transition in the right place. See the below example. This appears to be because when you call an event like keep! it resets @halted to false, so the after exit the halted workflow state transition is persisted. The workaround is to call halt after you call keep!, but it feels like the order there shouldn't affect things, and certainly that it shouldn't be possible to go from :trash to :fridge.

require 'workflow'

class Page
  include Workflow

  def workflow_state
    @workflow_state
  end

  workflow do
    state :new do
      event :draw_on_page, :transitions_to => :drawing
    end

    state :drawing do
      event :discard, :transitions_to => :trash
      event :keep, :transitions_to => :fridge
    end

    state :trash

    state :fridge

    on_transition do |from, to, triggering_event, *event_args|
      puts "#{workflow_state} -> #{to}"
    end
  end

  def discard(good_drawing)
    if good_drawing
      halt
      keep!
    end
  end

  def keep
    puts "so happy this drawing isn't going into the trash"
  end
end

page = Page.new
page.draw_on_page!
page.discard!(true)
puts "Paper's final resting place: #{page.workflow_state}"
athorp$ bundle exec ruby repro.rb
 -> drawing
so happy this drawing isn't going into the trash
drawing -> fridge
fridge -> trash
Paper's final resting place: trash