Permalink
Browse files

Generate'able state machine and a navigating one, but firing and valu…

…es and inputs totally weird and not done
  • Loading branch information...
1 parent aa45831 commit c5ae6b3981504f04ef9a2eeb3188e4f1d254aad8 @enebo committed Jan 5, 2013
@@ -0,0 +1,38 @@
+module Wreckem
+ class StateMachineBuilder
+ include Wreckem::StateMachineComponents
+ def self.build(machine_def)
+ unless machine_def.is?(Machine)
+ raise ArgumentError.new "Not a state machine defintiion #{machine_def.as_string}"
+ end
+
+ name = machine_def.one(Name)
+ start = machine_def.one(StateDestinationRef)
+ start_state = build_state(start).to_entity
+
+ new(name, start_state)
+ end
+
+ def self.build_state(state)
+ raise ArgumentError.new "Not a state entity" if !state.is? StateState
+
+ transitions = state.many(StateTransitionRef).inject([]) do |list, str|
+ list << build_transition(str.entity)
+ end
+
+ Wreckem::State.new state.one(Name), transitions, state.is?(StateGoal)
+ end
+
+ def self.build_transition(transition)
+ unless state.is? StateTransition
+ raise ArgumentError.new "Not a state transition"
+ end
+
+ name = transition.one(Name).value
+ destination = transtion.one(StateDestinationRef).to_entity
+ expression = transition.one(StateExpression).value
+
+ Wreck::Transition.generate(name, destination, expression)
+ end
+ end
+end
@@ -1,11 +1,13 @@
require 'wreckem/component'
module Wreckem
- class StateMachine
- StateMachine = Wreckem::Component.define
+ module StateMachineComponents
+ Machine = Wreckem::Component.define
+ Goal = Wreckem::Component.define
Name = Wreckem::Component.define_as_string
StateDestinationRef = Wreckem::Component.define_as_ref
StateState = Wreckem::Component.define
+ StateTransition = Wreckem::Component.define
StateTransitionRef = Wreckem::Component.define_as_ref
StateExpression = Wreckem::Component.define_as_string
end
@@ -0,0 +1,52 @@
+require 'wreckem/state_machine'
+
+module Wreckem
+ class StateMachineGenerator
+ include Wreckem::StateMachineComponents
+ def initialize
+ @states_visited = {}
+ @transitions_visited = {}
+ end
+
+ def generate(state_machine)
+ Entity.is! do |e|
+ e.is Machine
+ e.has Name.new(state_machine.name)
+ state = generate_state(state_machine.start_state)
+ e.has StateDestinationRef.new state
+ end
+ end
+
+ def generate_state(state)
+ new_state = @states_visited[state]
+ return if new_state # Only need to generate once
+
+ @states_visited[state] = Entity.is! do |e|
+ e.is StateState
+ e.has Name.new(state.name)
+ e.is Goal if state.goal?
+ state.transitions.each do |transition|
+ trans = generate_transition(transition)
+ e.has StateTransitionRef.new trans
+ end
+ end
+ end
+
+ def generate_transition(transition)
+ new_transition = @transitions_visited[transition]
+ return if new_transition # Only need to generate once
+
+ @transitions_visited[transition] = Entity.is! do |e|
+ e.is StateTransition
+ e.has Name.new(transition.name)
+ e.has StateExpression.new(transition.expression_as_string)
+ dest_state = generate_state(transition.destination)
+ e.has StateDestinationRef.new dest_state
+ end
+ end
+
+ def self.generate(state_machine)
+ new.generate(state_machine)
+ end
+ end
+end
@@ -4,10 +4,15 @@ class State
def initialize(name, transitions, goal=false)
@name, @transitions = name, transitions
+ @goal = goal
+ end
+
+ def goal?
+ @goal
end
def execute(subject, object)
- return nil if goal
+ return nil if goal?
fired_transition = @transitions.find do |transition|
transition.fires?(subject, object)
@@ -4,6 +4,8 @@
module Wreckem
class StateMachine
+ attr_reader :name, :start_state
+
def initialize(name, start_state)
@name, @start_state = name, start_state
end
@@ -14,49 +16,8 @@ def execute(a, b)
end
end
- def self.build(machine_def)
- unless machine_def.is?(StateMachine)
- raise ArgumentError.new "Not a state machine defintiion #{machine_def.as_string}"
- end
-
- name = machine_def.one(Name)
- start = machine_def.one(StateDestinationRef)
- start_state = build_state(start).to_entity
-
- new(name, start_state)
- end
-
- def self.build_state(state)
- raise ArgumentError.new "Not a state entity" if !state.is? StateState
-
- transitions = state.many(StateTransitionRef).inject([]) do |list, str|
- list << build_transition(str.entity)
- end
-
- Wreckem::State.new(state.one(Name), transitions, state.is?(Goal))
- end
-
- def self.build_transition(transition)
- unless state.is? StateTransition
- raise ArgumentError.new "Not a state transition"
- end
-
- name = transition.one(Name).value
- expression = transition.one(StateExpression).value
- destination = transtion.one(StateDestinationRef).to_entity
-
- cls = eval(<<-EOS)
-Class.new(Wreckem::Transition) do
- def initialize(name, destination)
- super(name, destination)
- end
-
- def fires?
- #{expression}
- end
-end
-EOS
- cls.new(name, destination)
+ def self.build(machine_definition_entity)
+ Wreckem::StateMachineBuilder.build(machine_definition_entity)
end
end
end
@@ -1,9 +1,25 @@
module Wreckem
class Transition
- attr_accessor :name, :destination
+ attr_accessor :name, :destination, :expression_as_string
- def initialize(name, destination)
+ def initialize(name, destination, expression_as_string)
@name, @destination = name, destination
+ @expression_as_string = expression_as_string
+ end
+
+ def self.generate(name, destination, expression_as_string)
+ cls = eval(<<-EOS)
+Class.new(Wreckem::Transition) do
+ def initialize(name, destination, expression_as_string)
+ super(name, destination, expression_as_string)
+ end
+
+ def fires?(a, b)
+ #{expression_as_string}
+ end
+end
+EOS
+ cls.new(name, destination, expression_as_string)
end
end
end
View
@@ -0,0 +1,29 @@
+require 'wreckem/state_machine'
+require 'wreckem/state_machine/generator'
+
+describe Wreckem::StateMachine do
+ before { @em = Wreckem::EntityManager.new }
+ after { @em.destroy }
+
+ def simple_machine
+ positive = Wreckem::State.new "Positive", [], true
+ positive_transition = Wreckem::Transition.generate("Positive", positive, "a > b")
+ negative = Wreckem::State.new "Negative", [], true
+ negative_transition = Wreckem::Transition.generate("Negative", negative, "a < b")
+ equal = Wreckem::State.new "Equal", [], true
+ equal_transition = Wreckem::Transition.generate("Equal", equal, "a == b")
+ transitions = [positive_transition, negative_transition, equal_transition]
+ start = Wreckem::State.new "Start", transitions, false
+ Wreckem::StateMachine.new("Positive value", start)
+ end
+
+ it "should generate state_machine entities" do
+ machine_entity = Wreckem::StateMachineGenerator.generate(simple_machine)
+ machine_entity.one(Wreckem::StateMachineComponents::Name).value.should == "Positive value"
+ end
+
+ it "should execute a simple state machine" do
+ machine = simple_machine
+ machine.execute(1, 2)
+ end
+end

0 comments on commit c5ae6b3

Please sign in to comment.