<commit_before>![Statesman](http://f.cl.ly/items/410n2A0S3l1W0i3i0o2K/statesman.png)

A statesmanlike state machine library for Ruby 1.9.3 and 2.0.

[![Gem Version](https://badge.fury.io/rb/statesman.png)](http://badge.fury.io/rb/statesman)
[![Build Status](https://travis-ci.org/gocardless/statesman.png?branch=master)](https://travis-ci.org/gocardless/statesman)
[![Code Climate](https://codeclimate.com/github/gocardless/statesman.png)](https://codeclimate.com/github/gocardless/statesman)
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/gocardless/statesman?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)


Statesman is a little different from other state machine libraries which tack
state behaviour directly onto a model. A statesman state machine is defined as a
separate class which is instantiated with the model to which it should
apply. State transitions are also modelled as a class which can optionally be
persisted to the database for a full audit history, including JSON metadata
which can be set during a transition.

This data model allows for interesting things like using a different state
machine depending on the value of a model attribute.

## TL;DR Usage

```ruby
class OrderStateMachine
  include Statesman::Machine

  state :pending, initial: true
  state :checking_out
  state :purchased
  state :shipped
  state :cancelled
  state :failed
  state :refunded

  transition from: :pending,      to: [:checking_out, :cancelled]
  transition from: :checking_out, to: [:purchased, :cancelled]
  transition from: :purchased,    to: [:shipped, :failed]
  transition from: :shipped,      to: :refunded

  guard_transition(to: :checking_out) do |order|
    order.products_in_stock?
  end

  before_transition(from: :checking_out, to: :cancelled) do |order, transition|
    order.reallocate_stock
  end

  before_transition(to: :purchased) do |order, transition|
    PaymentService.new(order).submit
  end

  after_transition(to: :purchased) do |order, transition|
    MailerService.order_confirmation(order).deliver
  end
end

class Order < ActiveRecord::Base
  include Statesman::Adapters::ActiveRecordQueries

  has_many :order_transitions

  def state_machine
    OrderStateMachine.new(self, transition_class: OrderTransition)
  end

  private

  def self.transition_class<commit_msg>Look at the TLDR example using memoization - is this valid?<commit_after>![Statesman](http://f.cl.ly/items/410n2A0S3l1W0i3i0o2K/statesman.png)

A statesmanlike state machine library for Ruby 1.9.3 and 2.0.

[![Gem Version](https://badge.fury.io/rb/statesman.png)](http://badge.fury.io/rb/statesman)
[![Build Status](https://travis-ci.org/gocardless/statesman.png?branch=master)](https://travis-ci.org/gocardless/statesman)
[![Code Climate](https://codeclimate.com/github/gocardless/statesman.png)](https://codeclimate.com/github/gocardless/statesman)
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/gocardless/statesman?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)


Statesman is a little different from other state machine libraries which tack
state behaviour directly onto a model. A statesman state machine is defined as a
separate class which is instantiated with the model to which it should
apply. State transitions are also modelled as a class which can optionally be
persisted to the database for a full audit history, including JSON metadata
which can be set during a transition.

This data model allows for interesting things like using a different state
machine depending on the value of a model attribute.

## TL;DR Usage

```ruby
class OrderStateMachine
  include Statesman::Machine

  state :pending, initial: true
  state :checking_out
  state :purchased
  state :shipped
  state :cancelled
  state :failed
  state :refunded

  transition from: :pending,      to: [:checking_out, :cancelled]
  transition from: :checking_out, to: [:purchased, :cancelled]
  transition from: :purchased,    to: [:shipped, :failed]
  transition from: :shipped,      to: :refunded

  guard_transition(to: :checking_out) do |order|
    order.products_in_stock?
  end

  before_transition(from: :checking_out, to: :cancelled) do |order, transition|
    order.reallocate_stock
  end

  before_transition(to: :purchased) do |order, transition|
    PaymentService.new(order).submit
  end

  after_transition(to: :purchased) do |order, transition|
    MailerService.order_confirmation(order).deliver
  end
end

class Order < ActiveRecord::Base
  include Statesman::Adapters::ActiveRecordQueries

  has_many :order_transitions

  def state_machine
    @state_machine ||= OrderStateMachine.new(self, transition_class: OrderTransition)
  end

  private

  def self.transition_class
{'fraction_non_alphanumeric': 0.09972763461135555, 'fraction_numerical': 0.006704378797402053, 'mean_word_length': 5.152061855670103, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 14, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1474872', 'n_tokens_mistral': 1554, 'n_tokens_neox': 1489, 'n_words': 413}