Rubyの有限状態マシン

この記事はhabrayuzer プリプロセッサーの作者であり、すべての明白な理由で公開できませんでした。 彼へのすべてのプラス:)



有限状態マシンは、有限数の状態を持つオブジェクトの動作を記述するものです。 ある状態から別の状態への遷移の方法、この遷移の条件、遷移中またはその後に実行されるアクション。 私はいつも理論に悪い時間を過ごしていたので、これ以上は触れません。代わりに、詳細に興味がある人には、ウィキペディアを見ることをお勧めします(それなしでどうすればいいですか) http://en.wikipedia.org/wiki/Finite-state_machineおよびhttp://ru.wikipedia.org/wiki/Final_automaton 、そしてそこからすでに必要なだけ点滴します。 実際には、これは文字列の解析(hello Ragel )からWebアプリケーションのUserモデルまで、多くの場合に使用できます。



次に、Ruby言語でのステートマシンの実装について説明します。 このような素晴らしいサイトruby-toolbox.comがあり、これにより、現在ルビーの世界で人気のあるものをかなり正確に判断できます。 ステートマシンのセクションでは、そもそもrubyistからのgem aasmがあります。 ところで、Rubyライブラリの品質は、ほとんどの場合、ライブラリの競合がある分野での人気によって判断されることがありました。 それで、それは起こりました。 aasmは非常に優れており、その人気のある前任者( acts_as_state_machine )はActiveRecordだけでなく(一部ではありませんが)rubyオブジェクトでも機能します。 それは単なるドキュメントであり、西部のウェブ上でさえ、このライブラリの多少なりとも完全な説明を見つけることができませんでした。 それで、私は実際、それのために小さなマニュアルを書くことを許可します。



それでは、ライブラリ自体のサンプルから始めましょう(これがすべてのドキュメントです)。



class Conversation < ActiveRecord::Base

include AASM



aasm_initial_state :unread



aasm_state :unread

aasm_state :read

aasm_state :closed



aasm_event :view do

transitions :to => :read, :from => [:unread]

end



aasm_event :close do

transitions :to => :closed, :from => [:read, :unread]

end

end










生成されたもの:



conversation = Conversation.new



conversation.aasm_current_state => :unread



conversation.view # :read



conversation.view! # :read aasm_write_state,

conversation.read? # true or false. “ read?”



conversation.closed # named scopes , scope .








オブジェクトがActiveRecord :: Baseを継承する場合、aamsの永続化コンポーネントがそれに混ざります。 そもそも強打法が重要なのは彼女にとってだ。 conversation.view! オブジェクトの現在の状態を変換するだけでなく、データベースに保存します。 また、どのオブジェクトにもaasm_write_stateを定義して、魂が望むすべてのことを(aasm_read_stateのように)行うことを誰も気にしません。



さらにいくつかの例を見てみましょう。



aasm_state :waiting, :enter => :start_timer

aasm_state :selecting_cards

aasm_state :made_turn, :exit => lambda { unseletcted_cards.each { |c| c.destroy }



aasm_event :go do

transitions :to => :selecting_cards, :from => [:ready], :guard => :attacking?

transitions :to => :waiting, :from => [:ready], :guard => :defending?

end



aasm_event :make_turn, :success => :after_make_turn do

transitions :to => :made_turn, :from => [:selecting_cards], :on_transition => :do_make_turn

end








見えるもの。 最初のコールバック。

移行の場合、これらは次のとおりです。guardおよびon_transition。 次の場合:guard trueの場合、移行は失敗し、そうでない場合はnoになります。 :on_transitionは遷移中に実行さます。 たとえば、これは、このコールバックで次の状態に進むことができないことを意味します。

イベント-:成功。移行が正常に完了した後に実行されます。

状態-:enterおよび:exitでは、状態に入るときと状態から出るときにそれぞれ実行されます(どのイベントおよびどの遷移を介してもかまいません)。

これらのコールバックはいずれも、他のすべての場所と同様に、一般にSymbolまたはProcのいずれかです。



オブジェクト自体にはaasm_event_firedおよびaasm_event_failedがあります。 それらのいずれかがオブジェクトで定義されている場合、aasm_event_failedは1つのパラメーター(イベントの名前)で呼び出され、aasm_event_firedは2つのパラメーター(イベントの名前とオブジェクトが転送された状態の名前)で呼び出されます



この例から、イベントには任意の数の遷移を定義できることもわかります。 fromが現在の状態に対応し、かつguardがtrueを返した場合に実行されます。



基本的には以上です。 これは、小さいながらも非常に柔軟で拡張可能なルビーライブラリの例です。 まあ、少しアマチュアのパフォーマンスの終わりに。



http://github.com/preprocessor/aasm



整数の形式でデータベースに状態を保存するメカニズムを実装しました。 パフォーマンスとそのすべて。 使い方は簡単です:



aasm_state :unread, :integer => 0

aasm_state :read, :integer => 1

aasm_state :closed, :integer => 2



Conversation.aasm_integers[:read] => 1








名前付きスコープは、必要に応じて引き続き機能します。



http://github.com/preprocessor/railroad_xing



フォークフォーク(紳士、ルビー開発者、少なくとも何らかの形でプロジェクトをgithubに保管しましょう。結局のところ、トレンドです)。 aasmのサポートを追加します。 その結果、以下が得られます。







なぜこれが必要なのですか? このようなスキーマを使用すると、多くの場合、コードの理解と議論がはるかに簡単になります。 ただし、描画には5〜10分かかります。 そして、10個のモデルと頻繁に変更される場合 当然、誰もそれらを描きません。 しかし、すべてが自動で便利な場合は、そうではありません。



がんばって。



更新しました。 私のフォークrailroad_xingは、元のバージョンと同じようになりました。 したがって、 github.com / royw / railroad_xing / tree / masterをフォローして使用できます






All Articles