Динамический конечный автомат в Ruby? Должны ли государственные машины быть классами?

Вопрос в том, всегда ли конечные автоматы определены статически (на классах)? Или есть способ для меня, чтобы у каждого экземпляра класса был свой набор состояний?

Я проверяю Stonepath для реализации Task Engine. Я действительно не вижу различия между "состояниями" и "задачами", поэтому думаю, что могу просто сопоставить задачу непосредственно состоянию. Это позволило бы мне иметь возможность определять списки задач (или рабочие процессы) динамически, без необходимости делать такие вещи, как:

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

Вместо этого WorkItem (основная модель рабочего процесса / менеджера задач) просто будет иметь много задач. Тогда задачи будут работать как состояния, поэтому я мог бы сделать что-то вроде этого:

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

Тем не менее, я не могу сделать это с помощью Aasm Gem, потому что эти методы (aasm_state а также aasm_event) являются методами класса, поэтому каждый экземпляр класса с этим конечным автоматом имеет одинаковые состояния. Я хочу, чтобы "WorkItem" или "TaskList" динмически создавали последовательность состояний и переходов на основе задач, которые у них есть.

Это позволило бы мне динамически определять рабочие процессы и просто сопоставлять состояния задачам.

Государственные машины когда-либо используются таким образом? Кажется, что этот рубиновый рабочий процесс похож на то, что я описываю.

Обновление: я вижу, что делаю что-то вроде следующего, но это выглядит как хакерский:

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

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

... где будет свойство на моей модели implementation_state_machine, Я бы переопределил method_missing делегировать методы, связанные с состоянием (accepted_phase?) к реализации анонимного класса.

2 ответа

В моей реализации конечным автоматом является хеш https://github.com/mpapis/state_attr

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

Вы можете определить столько атрибутов состояния, сколько захотите

Кстати: на заднем плане есть еще класс, но только в качестве прокси для атрибута

Да, это кажется очень хакерским и довольно грязным. Недавно я написал новый гем, который позволяет вам использовать динамические переходы "к" с установкой решения.

Таким образом, вместо того чтобы динамически создавать события и переходы, можно ли сначала отобразить их и использовать параметр выбора, чтобы позволить переходу решить, в какое новое состояние войти? Вы также можете заключить ваш переход from в массив, чтобы вам не нужно было делать:from => previous_state? "#{task.name}_phase": "initial", вы можете просто сделать:from => [:cool_task_phase,:initial ]

Я обнаружил, что излагая ваши переходы и события в первую очередь, вы можете получить более полное представление о том, что делает ваша модель.

Проверьте это на http://github.com/ryanza/stateflow

Надеюсь, вы можете найти какую-то пользу от этого.

Другие вопросы по тегам