module Mocha # :nodoc: # A state machine that is used to constrain the order of invocations. # An invocation can be constrained to occur when a state is, or is_not, active. class StateMachine class State # :nodoc: def initialize(state_machine, state) @state_machine, @state = state_machine, state end def activate @state_machine.current_state = @state end def active? @state_machine.current_state == @state end def mocha_inspect "#{@state_machine.name} is #{@state.mocha_inspect}" end end class StatePredicate # :nodoc: def initialize(state_machine, state) @state_machine, @state = state_machine, state end def active? @state_machine.current_state != @state end def mocha_inspect "#{@state_machine.name} is not #{@state.mocha_inspect}" end end attr_reader :name # :nodoc: attr_accessor :current_state # :nodoc: def initialize(name) # :nodoc: @name = name @current_state = nil end # :call-seq: starts_as(initial_state) -> state_machine # # Put the +state_machine+ into the +initial_state+. def starts_as(initial_state) become(initial_state) self end # :call-seq: become(next_state) # # Put the +state_machine+ into the +next_state+. def become(next_state) @current_state = next_state end # :call-seq: is(state) # # Determines whether the +state_machine+ is in the specified +state+. def is(state) State.new(self, state) end # :call-seq: is_not(state) # # Determines whether the +state_machine+ is not in the specified +state+. def is_not(state) StatePredicate.new(self, state) end def mocha_inspect # :nodoc: if @current_state "#{@name} is #{@current_state.mocha_inspect}" else "#{@name} has no current state" end end end end