lib/state_machine/machine.rb in state_machine-0.6.0 vs lib/state_machine/machine.rb in state_machine-0.6.1

- old
+ new

@@ -42,11 +42,11 @@ # *Note* that if a +before+ callback fails and the bang version of an event # was invoked, an exception will be raised instead of returning false. For # example, # # class Vehicle - # state_machine, :initial => :parked do + # state_machine :initial => :parked do # before_transition any => :idling, :do => lambda {|vehicle| throw :halt} # ... # end # end # @@ -140,10 +140,14 @@ class Machine include Assertions include MatcherHelpers class << self + # The default message to use when invalidating objects that fail to + # transition when triggering an event + attr_accessor :default_invalid_message + # Attempts to find or create a state machine for the given class. For # example, # # StateMachine::Machine.find_or_create(Vehicle) # StateMachine::Machine.find_or_create(Vehicle, :initial => :parked) @@ -206,10 +210,13 @@ end end end end + # Set defaults + self.default_invalid_message = 'cannot be transitioned via :%s from :%s' + # The class that the machine is defined in attr_accessor :owner_class # The attribute for which the machine is being defined attr_reader :attribute @@ -243,18 +250,19 @@ attr_reader :namespace # Creates a new state machine for the given attribute def initialize(owner_class, *args, &block) options = args.last.is_a?(Hash) ? args.pop : {} - assert_valid_keys(options, :initial, :action, :plural, :namespace, :integration) + assert_valid_keys(options, :initial, :action, :plural, :namespace, :integration, :invalid_message) # Set machine configuration @attribute = args.first || :state @events = NodeCollection.new @states = StateCollection.new @callbacks = {:before => [], :after => []} @namespace = options[:namespace] + @invalid_message = options[:invalid_message] self.owner_class = owner_class self.initial_state = options[:initial] # Find an integration that matches this machine's owner class if integration = options[:integration] ? StateMachine::Integrations.find(options[:integration]) : StateMachine::Integrations.match(owner_class) @@ -452,11 +460,11 @@ # be raised at runtime, indicating that the state machine could not figure # out what the current state of the object was. # # == Behaviors # - # Behaviors defined a series of methods to mixin with objects when the current + # Behaviors define a series of methods to mixin with objects when the current # state matches the given one(s). This allows instance methods to behave # a specific way depending on what the value of the object's state is. # # For example, # @@ -567,11 +575,11 @@ # conditions can continue to be used. # # This functionality is not library-specific and can work for any class-level # method that is defined like so: # - # def validates_presence_of(args, options = {}) + # def validates_presence_of(attribute, options = {}) # ... # end # # The minimum requirement is that the last argument in the method be an # options hash which contains at least <tt>:if</tt> condition support. @@ -595,11 +603,11 @@ alias_method :other_states, :state # Determines whether the given object is in a specific state. If the # object's current value doesn't match the state, then this will return # false, otherwise true. If the given state is unknown, then an ArgumentError - # exception will be raised. + # will be raised. # # == Examples # # class Vehicle # state_machine :initial => :parked do @@ -902,10 +910,23 @@ # for defining callbacks. def after_transition(options = {}, &block) add_callback(:after, options.is_a?(Hash) ? options : {:do => options}, &block) end + # Marks the given object as invalid after failing to transition via the + # given event. + # + # By default, this is a no-op. + def invalidate(object, event) + end + + # Resets an errors previously added when invalidating the given object + # + # By default, this is a no-op. + def reset(object) + end + # Runs a transaction, rolling back any changes if the yielded block fails. # # This is only applicable to integrations that involve databases. By # default, this will not run any transactions, since the changes aren't # taking place within the context of a database. @@ -1074,8 +1095,14 @@ states << state = State.new(self, new_state) end state end + end + + # Generates the message to use when invalidating the given object after + # failing to transition on a specific event + def invalid_message(object, event) + (@invalid_message || self.class.default_invalid_message) % [event.name, state_for(object).name] end end end