Rubyで状態遷移を管理するgemを作った(state_transition)
https://github.com/jakesgordon/javascript-state-machine
このjavascript-state-machineが便利だったので、Rubyでも使いたいと思い、Ruby versionを作ってみました。
https://github.com/siman-man/state_transition
gemのインストール
gem install state_transition
サンプルコード
require 'state_transition' state = StateTransition::StateMachine.new({ initial: :first, actions: [ { name: "move_first", from: [ :second, :third ], to: :first }, { name: "move_second", from: [ :first, :third ], to: :second }, { name: "move_third", from: :second, to: :third }, ], callbacks: { before_second: -> { puts "before_second" }, after_second: -> { puts "after_second" }, } }) puts state.current #=> :first puts state.can_move?(:second) #=> true puts state.can_move?(:third) #=> false state.move_second puts state.current #=> :second
実行結果
first true false before_second after_second second
初期化について
初期化はStateTransitionモジュールのStateMachineクラスを使用します。
渡す引数は、initial, actions, callbacksの3つです(callbacksは任意)
state = StateTransition::StateMachine.new({ initial: :first, actions: [ { name: "move_first", from: [ :second, :third ], to: :first }, { name: "move_second", from: [ :first, :third ], to: :second }, { name: "move_third", from: :second, to: :third }, ], callbacks: { before_second: -> { puts "before_second" }, after_second: -> { puts "after_second" }, } })
3つの引数について説明します。
・initial (初期状態の宣言)
initial: :first
この部分で最初の初期状態を決定します。
・actions (移動時のアクション宣言)
actions: [ { name: "move_first", from: [ :second, :third ], to: :first }, { name: "move_second", from: [ :first, :third ], to: :second }, { name: "move_third", from: :second, to: :third }, ]
配列の各要素に、それぞれアクションを定義しており、「アクション名、移動元、移動先」といった感じで定義していきます。移動元は複数指定可能ですが、移動先は1つだけです。また、移動元、移動先で定義されている状態は自動的に作成されます。
actionsで定義した状態遷移図
・callbacks
ここでは遷移前と遷移後に実行させたいプログラムを記述することが出来ます。移動前のメソッド名は「before_ + "状態名"」、移動後のメソッド名は「after_ + "状態名"」で固定です。
callbacks: { before_second: -> { puts "before_second" }, after_second: -> { puts "after_second" }, }
アクション実行
actionsで定義したアクションを実行することで、状態を遷移させることが出来ます。移動の際にcallbacksが定義されている場合はそれを実行します。この場合「before_second」->「current = :second」->「after_second」と実行されます。
puts state.current #=> :first state.move_second puts state.current #=> :second
その他
・can_move?
can_move?メソッドでは現在の状態から引数で渡した状態に遷移できるかどうかをチェックします。
state.current #=> :first state.can_move?(:second) #=> true state.can_move?(:third) #=> false
いままでgemを作ったことがなかったのですが、bundlerを使用すると簡単に作成できました。本当はgem名を「state_machine」とかにしようと思ったのですが、既に使われていてダメでした。