状態遷移のための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
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
でオッケーです。
まず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
以下のテスト用のモデルや、テストをご覧ください。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