akm / state_flow

state_flow plugin provides a DSL to define flow of state with ActiveRecord

This URL has Read+Write access

akm (author)
Thu Nov 05 03:53:29 -0800 2009
commit  d0e1d3fde35e6dbd203d14cf0b2a5a2dc523a7a7
tree    c143cc47a0d930f02ea8d12a899bdbdfd8e2fbbd
parent  5e7d6d065840b3a29a81d636871c97b37f5568c3
README.rdoc

StateFlow

StateFlowとは?

状態遷移のためのDSLを提供するためのActiveRecordを拡張するプラグインです。

基本的にUMLのステートチャート図に忠実に状態遷移を記述できるようにすることが最終目標です。 現在のところ、以下のような機能があります。

 * イベント/ガード/アクションの設定
  * イベントとして定義可能なのは、以下の通りです。
   * モデルに対する任意の名前のアクション(メソッドとして定義されるので、メソッド名に被っていると上書きされます)。
   * アクションの戻り値
   * 例外
  * ガードはその条件に該当するかどうかを判断するメソッド名を指定します。
  * アクションはモデルのメソッドを指定しますが、状態を変更するコードは不要です。
  * 状態の遷移は自動で行われます。
 * 状態のネスト
  * 親の状態で定義されたイベントが実行された場合に正しく状態を遷移します。
 * 状態を遷移する際のトランザクションの制御
  * 各状態間の遷移毎にトランザクションを発行します。
  * 例外発生時などにはロールバックを行い、(指定されていれば)例外に対応する状態に遷移してモデルを保存します。

サンプル

以下のような記述が可能です。

 class Order < ActiveRecord::Base

   class StockShortageError < StandardError
   end

   selectable_attr :status_cd do
     entry '00', :waiting_settling , '決済前'
     entry '01', :online_settling  , '決済中'
     entry '02', :receiving        , '入金待ち'
     entry '03', :deliver_preparing, '配送準備中'
   end

   state_flow(:status_cd) do
     origin(:waiting_settling)

     group(:valid) do
       from(:waiting_settling) do
         guard(:pay_cash_on_delivery?).action(:reserve_point).action(:reserve_stock){
           event(:reserve_stock_ok).to(:deliver_preparing)
           event_else.action(:delete_point).to(:stock_error)
         }
         guard_else.action(:reserve_point).action(:reserve_stock, :temporary => true){
           event(:reserve_stock_ok){
             guard(:bank_deposit?).action(:send_mail_thanks).to(:receiving)
             guard(:credit_card?).to(:online_settling)
             guard(:foreign_payment?).action(:settle).to(:online_settling)
           }
           event_else{
             guard(:foreign_payment?).action(:delete_point).action(:send_mail_stock_shortage)
           }.to(:stock_error)
         }
         recover(StockShortageError).to(:stock_error)
       end

       from(:online_settling) do
         guard(:credit_card?).action(:settle){
           event(:ok).action(:reserve_stock).action(:send_mail_thanks).to(:deliver_preparing)
           event_else.action(:release_stock).action(:delete_point).to(:settlement_error)
         }
         guard(:foreign_payment?){
           event(:settlement_ok).to(:deliver_preparing)
           event(:settlement_ng).action(:release_stock).action(:delete_point).action(:send_mail_invalid_purchage).to(:settlement_error)
         }
         recover(Exception).action(:release_stock).action(:delete_point).to(:settlement_error)
       end
     end
   end
 end

詳しくはspec/order_spec.rbをご覧ください。

セットアップ

state_flowプラグインはselectable_attrに依存しています。

  • selectable_attr

github.com/akm/selectable_attr

  • selectable_attr_rails

github.com/akm/selectable_attr_rails

Railsで使う場合

プラグインとしてインストール

 ruby script/plugin install git://github.com/akm/selectable_attr.git
 ruby script/plugin install git://github.com/akm/selectable_attr_rails.git
 ruby script/plugin install git://github.com/akm/state_flow.git

でオッケーです。

gemの場合

まずgemcutterの設定をしていなかったら、

 gem install gemcutter
 gem tumble

を実行した後、

 gem install selectable_attr selectable_attr_rails state_flow

を実行するとインストール完了。

で、config/initializersに以下の2つのファイルを作成すればオッケーです。

config/initializers/selectable_attr.rb

 require 'selectable_attr'
 require 'selectable_attr_i18n'
 require 'selectable_attr_rails'
 SelectableAttrRails.add_features_to_rails

config/initializers/state_flow.rb

 require 'state_flow'
 ActiveRecord::Base.module_eval do
   include StateFlow
 end

Example

以下のテスト用のモデルや、テストをご覧ください。 github.com/akm/state_flow/blob/master/spec/resources/models/order.rb github.com/akm/state_flow/blob/master/spec/order_spec.rb

Copyright © 2009 [Takeshi AKIMA], released under the MIT license