cequel_stateful_enum is a simple state machine gem built on top of Cequel's built-in enum column. This gem is totally based on stateful_enum gem for ActiveRecord. Huge thanks to Akira Matsuda! This gem in not depends on Rails.
Add this line to your app's Gemfile:
gem 'cequel_stateful_enum'And bundle.
The cequel_stateful_enum gem extends Cequel's column definition to take a block with a similar DSL to the state_machine gem.
Example:
class Bug
include Cequel::Record
column :status, :enum, values: { unassigned: 0, assigned: 1, resolved: 2, closed: 3 } do
event :assign do
transition :unassigned => :assigned
end
event :resolve do
before do
self.resolved_at = Time.now
end
transition [:unassigned, :assigned] => :resolved
end
event :close do
transition all - [:closed] => :closed
after :notify_author_about_status
after do
BugCache.remove_from_open_cache(self)
end
end
end
# ...
endJust call the Cequel's column method with :enum type. The only difference from the original method is that our column call takes a block.
You can declare events through event method inside of an column block. Then cequel_stateful_enum defines the following methods per each event:
An instance method to fire the event
@bug.assign # does nothing and returns false if a valid transition for the current state is not definedAn instance method with ! to fire the event
@bug.assign! # raises if a valid transition for the current state is not definedA predicate method that returns if the event is fireable
@bug.can_assign? # returns if the `assign` event can be called on this bug or not and all `if` and `unless` conditions are metYou can define state transitions through transition method inside of an event block.
There are a few important details to note regarding this feature:
- The
transitionmethod takes a Hash each key of which is state "from" transitions to the Hash value. - The "from" states and the "to" states should both be given in Symbols.
- The "from" state can be multiple states, in which case the key can be given as an Array of states, as shown in the usage example.
- The "from" state can be
allthat means all defined states.
The transition method takes an :if and/or :unless option as a Proc or Symbol.
Example:
event :assign do
transition :unassigned => :assigned, if: -> { assigned_to.any? }, unless: :blocked?
endWhen firing the event model will be saved by default. To prevent saving use save: false attribute:
@bug.assign(save: false) # => trueIf model can't be saved (for example, it is in invalid state) and there was no save: false parameter passed, event will return false, but field will be changed and before callbacks will be fired. Can method does not check is the model valid:
@bug.subject = '' # Invalid subject
@bug.can_resolve? # => true
@bug.resolve # => false
@bug.updated_at # Not saved
@bug.status # => :resolved
@bug.resolved_at # Setted by after callbackIf you should control the bang and non-bang behavour with variable, you can use danger: value parameter, where value is true or false. Parameter is accepted on both event and can methods:
@bug.assign(danger: true) # Same as @bug.assign!
@bug.can_assign?(danger: true) # Will raise error if can'tYou can define before and after event hooks inside of an event block as shown in the example above. Symbols and Proc objects are supported.
Pull requests are welcome on GitHub at https://github.com/Xanders/cequel_stateful_enum.
The gem is available as open source under the terms of the MIT License.