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