Skip to content

Instantly share code, notes, and snippets.

@aileron
Created July 25, 2012 17:58
Show Gist options
  • Save aileron/3177543 to your computer and use it in GitHub Desktop.
Save aileron/3177543 to your computer and use it in GitHub Desktop.
ステートマシーンのRuby実装 ほぼ AASMと同じ使い方。
module StateMachine
class Event
def transition opt={from:nil,to:nil,guard:nil}
self.ts ||= {}
self.ts[ opt[:from] ] = opt if (opt[:from].is_a? String) || (opt[:from].is_a? Symbol)
opt[:from].each do |name|
ts[name] = opt
end if opt[:from].is_a? Array
end
attr_accessor :ts
end
class Smg
def initialize name,klass
self.name = name
self.klass = klass
self.states = {}
smg = self
klass.class_eval do
define_method :initialize do |*args|
super(*args)
smg.states.each do |n,s|
next unless s[:initial]
send s[:enter] if s[:enter]
send "#{name}=",n
end
end
end
end
def state name, opt={enter:nil, initial:nil}
self.states[ name ] = opt
end
def event name, opt={before:nil,after:nil}, &block
smg = self
event = Event.new
event.instance_eval &block
klass.class_eval do
define_method name do
transition = event.ts[ send(smg.name) ]
return unless transition
return if transition[:guard] && send(transition[:guard])
raise "not state #{transition[:to]}" unless state = smg.states[ transition[:to] ]
send opt[:before] if opt[:before]
send state[:enter] if state[:enter]
send "#{smg.name}=", transition[:to]
send opt[:after] if opt[:after]
send :save
end
end
end
attr_accessor :name
attr_accessor :klass
attr_accessor :states
attr_accessor :instance
end
def self.included(klass)
klass.class.instance_eval do
define_method :smg do |name,&block|
_smg = Smg.new name,klass
_smg.instance_eval &block
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment