2010-03-21 7 views
5

La pregunta es, ¿las máquinas de estados siempre se definen estáticamente (en las clases)? ¿O hay una manera de que yo lo tenga así que cada instancia de la clase tiene su propio conjunto de estados?Dynamic State Machine en Ruby? ¿Las máquinas de estado deben ser clases?

Estoy revisando Stonepath para implementar un Motor de tareas. Realmente no veo la distinción entre "estados" y "tareas" allí, así que estoy pensando que podría asignar una tarea directamente a un estado. Esto permitiría que yo sea capaz de definir tareas listas (o flujos de trabajo) de forma dinámica, sin tener que hacer cosas como:

aasm_event :evaluate do 
    transitions :to => :in_evaluation, :from => :pending 
end 

aasm_event :accept do 
    transitions :to => :accepted, :from => :pending 
end 

aasm_event :reject do 
    transitions :to => :rejected, :from => :pending 
end 

En cambio, un WorkItem (el flujo de trabajo/tarea principal modelo manager), simplemente tendría muchos Tareas. A continuación, las tareas trabajarían como estados, por lo que podría hacer algo como esto:

aasm_initial_state :initial 

tasks.each do |task| 
    aasm_state task.name.to_sym 
end 

previous_state = nil 
tasks.each do |tasks| 
    aasm_event task.name.to_sym do 
    transitions :to => "#{task.name}_phase".to_sym, :from => previous_state ? "#{task.name}_phase" : "initial" 
    end 
    previous_state = state 
end 

Sin embargo, no puedo hacer eso con el aasm gem porque esos métodos (aasm_state y aasm_event) son métodos de clase, por lo que cada instancia de la clase con esa máquina de estados tiene los mismos estados. Lo quiero para que un "WorkItem" o "TaskList" dinámicamente cree una secuencia de estados y transiciones basadas en las tareas que tiene.

Esto me permitiría definir dinámicamente los flujos de trabajo y simplemente hacer que los estados se correlacionen con las tareas.

¿Alguna vez se han utilizado máquinas de estados como esta? Parece que este ruby workflow gem es similar a lo que estoy describiendo.

Actualización: Me veo haciendo algo como lo siguiente, pero parece tipo de hacker:

@implementation_state_machine = Class::new do 
    include AASM 
    aasm_initial_state :initial 

    tasks.each { |state| aasm_state :"#{task.name}"} 
    # ... 
end 

... donde una propiedad en mi modelo sería implementation_state_machine. Tendría que anular method_missing para delegar métodos relacionados con el estado (accepted_phase?) a la clase anónima de implementación.

Respuesta

1

Sí, eso parece muy raro y bastante desordenado. Recientemente escribí una nueva gema que le permite usar transiciones dinámicas 'a' con una configuración de decisión.

Entonces, en lugar de construir dinámicamente sus eventos y transiciones, ¿sería posible mapearlos primero, y usar la configuración de decisión para permitir la transición decidir qué nuevo estado ingresar? También puede envolver su transición desde una matriz para que no tenga que hacer: from => previous_state? "# {task.name} _phase": "initial", puede hacer: from => [: cool_task_phase,: initial]

Me parece que establecer sus transiciones y eventos primero, le permite obtener una una imagen más clara de lo que está haciendo su modelo.

echarle un vistazo en http://github.com/ryanza/stateflow

Esperamos que usted puede encontrar un cierto uso de esta.

1

En mi máquina de estados aplicación es un hash https://github.com/mpapis/state_attr

state_attr :state, { 
    nil => :first, 
    :first => [:second, :third], 
    :second => :last, 
    :third => nil, 
} 

puede definir como muchos atributos de estado como desee

Por cierto: en el fondo todavía hay una clase, pero sólo como un proxy para atributo

Cuestiones relacionadas