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

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

Я проверяю 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 ]

1 голос
/ 17 мая 2011

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

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

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

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

1 голос
/ 31 марта 2010

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

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

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

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

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

...