validating-workflow 0.7.2 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -4,4 +4,5 @@ pkg
4
4
  doc/
5
5
  html/
6
6
  *.swp
7
+ *.gemspec
7
8
  .yardoc
data/README.markdown CHANGED
@@ -1,7 +1,7 @@
1
- What is workflow?
2
- -----------------
1
+ What is validating-workflow?
2
+ ----------------------------
3
3
 
4
- Workflow is a finite-state-machine-inspired API for modeling and
4
+ Validating-Workflow is a finite-state-machine-inspired API for modeling and
5
5
  interacting with what we tend to refer to as 'workflow'.
6
6
 
7
7
  A lot of business modeling tends to involve workflow-like concepts, and
@@ -20,6 +20,10 @@ from, and we can cause transitions to fail (guards), and we can hook in
20
20
  to every transition that occurs ever for whatever reason we can come up
21
21
  with.
22
22
 
23
+ For convenience, validating-workflow adds certain validation options for
24
+ ActiveModel so you may declaratively specify what to validate in which
25
+ states or transitions when defining your validators.
26
+
23
27
  Now, all that's a mouthful, but we'll demonstrate the API bit by bit
24
28
  with a real-ish world example.
25
29
 
data/Rakefile CHANGED
@@ -19,12 +19,12 @@ end
19
19
  begin
20
20
  require 'jeweler'
21
21
  Jeweler::Tasks.new do |gemspec|
22
- gemspec.name = "workflow"
22
+ gemspec.name = 'workflow'
23
23
  gemspec.rubyforge_project = 'workflow'
24
- gemspec.email = "vladimir@geekq.net"
25
- gemspec.homepage = "http://www.geekq.net/workflow/"
26
- gemspec.authors = ["Vladimir Dobriakov"]
27
- gemspec.summary = "A replacement for acts_as_state_machine."
24
+ gemspec.email = 'vladimir@geekq.net'
25
+ gemspec.homepage = 'http://www.geekq.net/workflow/'
26
+ gemspec.authors = ['Vladimir Dobriakov', 'Willem van Kerkhof']
27
+ gemspec.summary = 'A replacement for acts_as_state_machine.'
28
28
  gemspec.description = <<-EOS
29
29
  Workflow is a finite-state-machine-inspired API for modeling and interacting
30
30
  with what we tend to refer to as 'workflow'.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.0
1
+ 0.7.6
@@ -1,3 +1,5 @@
1
+ require 'active_model/validations'
2
+
1
3
  module Workflow
2
4
  module StateDependentValidations
3
5
  module StateDependency
@@ -7,18 +9,30 @@ module Workflow
7
9
  end
8
10
 
9
11
  def validate_with_state_dependency(record)
10
- if not record.respond_to?(:current_state) or perform_validation_for_state?(record.current_state)
12
+ if not record.respond_to?(:current_state) or
13
+ perform_validation_for_state?(record.current_state) or
14
+ perform_validation_for_transition?(record.in_transition) or
15
+ perform_validation_for_transition?("#{record.in_exit}_exit") or
16
+ perform_validation_for_transition?("#{record.in_entry}_entry")
11
17
  validate_without_state_dependency(record)
12
18
  end
13
19
  end
14
20
 
15
21
  protected
16
22
  def perform_validation_for_state?(state)
17
- (unless_in_state_option.empty? and if_in_state_option.empty?) or
23
+ (unless_in_state_option.empty? and if_in_state_option.empty? and
24
+ unless_in_transition_option.empty? and if_in_transition_option.empty?) or
18
25
  (if_in_state_option.any? and if_in_state_option.include?(state.to_s)) or
19
26
  (unless_in_state_option.any? and not unless_in_state_option.include?(state.to_s))
20
27
  end
21
28
 
29
+ def perform_validation_for_transition?(transition)
30
+ (unless_in_state_option.empty? and if_in_state_option.empty? and
31
+ unless_in_transition_option.empty? and if_in_transition_option.empty?) or
32
+ (if_in_transition_option.any? and if_in_transition_option.include?(transition.to_s)) or
33
+ (unless_in_transition_option.any? and not unless_in_transition_option.include?(transition.to_s))
34
+ end
35
+
22
36
  def if_in_state_option
23
37
  @if_in_state_option ||= [options[:if_in_state]].flatten.compact.collect(&:to_s)
24
38
  end
@@ -26,19 +40,23 @@ module Workflow
26
40
  def unless_in_state_option
27
41
  @unless_in_state_option ||= [options[:unless_in_state]].flatten.compact.collect(&:to_s)
28
42
  end
43
+
44
+ def if_in_transition_option
45
+ @if_in_transition_option ||= [options[:if_in_transition]].flatten.compact.collect(&:to_s)
46
+ end
47
+
48
+ def unless_in_transition_option
49
+ @unless_in_transition_option ||= [options[:unless_in_transition]].flatten.compact.collect(&:to_s)
50
+ end
29
51
  end
30
52
 
31
53
  end
32
54
  end
33
55
 
34
- # unless defined? ActiveModel::Validations
35
- module ActiveModel::Validations
36
- [AcceptanceValidator, ConfirmationValidator, ExclusionValidator,
37
- FormatValidator, InclusionValidator, LengthValidator,
38
- NumericalityValidator, PresenceValidator].each do |validator|
39
- validator.send :include, Workflow::StateDependentValidations::StateDependency
40
- end
56
+ module ActiveModel::Validations
57
+ [AcceptanceValidator, ConfirmationValidator, ExclusionValidator,
58
+ FormatValidator, InclusionValidator, LengthValidator,
59
+ NumericalityValidator, PresenceValidator].each do |validator|
60
+ validator.send :include, Workflow::StateDependentValidations::StateDependency
41
61
  end
42
- # else
43
- # raise 'state dependent validation only works with ActiveModel::Validations'
44
- # end
62
+ end
data/lib/workflow.rb CHANGED
@@ -2,10 +2,14 @@ require 'rubygems'
2
2
 
3
3
  # See also README.markdown for documentation
4
4
  module Workflow
5
+ autoload :ActiveModelPersistence, 'workflow/active_model_persistence'
6
+ autoload :MongoidPersistence, 'workflow/mongoid_persistence'
7
+ autoload :RemodelPersistence, 'workflow/remodel_persistence'
8
+ autoload :Transactional, 'workflow/transactional'
5
9
 
6
10
  class Specification
7
11
 
8
- attr_accessor :states, :initial_state, :meta, :on_transition_proc
12
+ attr_accessor :states, :initial_state, :meta, :on_transition_proc, :on_failed_transition_proc
9
13
 
10
14
  def initialize(meta = {}, &specification)
11
15
  @states = Hash.new
@@ -22,31 +26,41 @@ module Workflow
22
26
  def state(name, meta = {:meta => {}}, &events_and_etc)
23
27
  # meta[:meta] to keep the API consistent..., gah
24
28
  new_state = Workflow::State.new(name, meta[:meta])
25
- @initial_state = new_state if @states.empty?
29
+ @initial_state = new_state if @states.empty?
26
30
  @states[name.to_sym] = new_state
27
- @scoped_state = new_state
31
+ @scoped_state = new_state
28
32
  instance_eval(&events_and_etc) if events_and_etc
29
33
  end
30
34
 
31
35
  def event(name, args = {}, &action)
32
36
  target = args[:transitions_to] || args[:transition_to]
33
- raise WorkflowDefinitionError.new(
34
- "missing ':transitions_to' in workflow event definition for '#{name}'") \
35
- if target.nil?
37
+ if target.nil?
38
+ raise WorkflowDefinitionError.new \
39
+ "missing ':transitions_to' in workflow event definition for '#{name}'"
40
+ end
36
41
  @scoped_state.events[name.to_sym] =
37
- Workflow::Event.new(name, target, (args[:meta] or {}), &action)
42
+ Workflow::Event.new(name, target, (args[:meta] || {}), &action)
43
+ end
44
+
45
+ def allow(name, args={}, &action)
46
+ args[:transitions_to] ||= args[:transition_to] || @scoped_state.to_sym
47
+ event name, args, &action
38
48
  end
39
49
 
40
- def on_entry(&proc)
41
- @scoped_state.on_entry = proc
50
+ def on_entry(&proc_to_run)
51
+ @scoped_state.on_entry = proc_to_run
42
52
  end
43
53
 
44
- def on_exit(&proc)
45
- @scoped_state.on_exit = proc
54
+ def on_exit(&proc_to_run)
55
+ @scoped_state.on_exit = proc_to_run
46
56
  end
47
57
 
48
- def on_transition(&proc)
49
- @on_transition_proc = proc
58
+ def on_transition(&proc_to_run)
59
+ @on_transition_proc = proc_to_run
60
+ end
61
+
62
+ def on_failed_transition(&proc_to_run)
63
+ @on_failed_transition_proc = proc_to_run
50
64
  end
51
65
  end
52
66
 
@@ -92,6 +106,18 @@ module Workflow
92
106
  @name, @transitions_to, @meta, @action = name, transitions_to.to_sym, meta, action
93
107
  end
94
108
 
109
+ def perform_validation?
110
+ !self.meta[:skip_all_validations]
111
+ end
112
+
113
+ def to_sym
114
+ @name.to_sym
115
+ end
116
+
117
+ def to_s
118
+ @name.to_s
119
+ end
120
+
95
121
  end
96
122
 
97
123
  module WorkflowClassMethods
@@ -113,7 +139,15 @@ module Workflow
113
139
  state_name = state.name
114
140
  module_eval do
115
141
  define_method "#{state_name}?" do
116
- state_name == current_state.name
142
+ state_name.to_sym == current_state.name.to_sym
143
+ end
144
+
145
+ define_method "in_#{state_name}_exit?" do
146
+ self.in_exit and self.in_exit.to_sym == state_name.to_sym
147
+ end
148
+
149
+ define_method "in_#{state_name}_entry?" do
150
+ self.in_entry and self.in_entry.to_sym == state_name.to_sym
117
151
  end
118
152
  end
119
153
 
@@ -124,9 +158,19 @@ module Workflow
124
158
  process_event!(event_name, *args)
125
159
  end
126
160
 
161
+ # this allows checks like can_approve? or can_reject_item?
162
+ # note we don't have a more generic can?(:approve) method.
163
+ # this is fully intentional, since this way it is far easier
164
+ # to overwrite the can_...? mehtods in a model than it would be
165
+ # with a generic can?(...) method.
127
166
  define_method "can_#{event_name}?" do
128
167
  return self.current_state.events.include? event_name
129
168
  end
169
+
170
+ define_method "in_transition_#{event_name}?" do
171
+ return false unless self.in_transition
172
+ return self.in_transition.to_sym == event_name.to_sym
173
+ end
130
174
  end
131
175
  end
132
176
  end
@@ -134,6 +178,8 @@ module Workflow
134
178
  end
135
179
 
136
180
  module WorkflowInstanceMethods
181
+ attr_accessor :in_entry, :in_exit, :in_transition
182
+
137
183
  def current_state
138
184
  loaded_state = load_workflow_state
139
185
  res = spec.states[loaded_state.to_sym] if loaded_state
@@ -153,38 +199,36 @@ module Workflow
153
199
  end
154
200
 
155
201
  def process_event!(name, *args)
202
+ assure_transition_allowed! name
156
203
  event = current_state.events[name.to_sym]
157
- if event.nil?
158
- raise NoTransitionAllowed.new \
159
- "There is no event #{name.to_sym} defined for the #{current_state} state"
160
- end
204
+ assure_target_state_exists!(event)
205
+ set_transition_flags(current_state, spec.states[event.transitions_to], event)
161
206
  @halted_because = nil
162
- @halted = false
163
- return_value = run_action(event.action, *args) || run_action_callback(event.name, *args)
207
+ @halted = false
208
+ return_value = run_action(event.action, *args) || run_action_callback(event.name, *args)
164
209
  if @halted
165
- return false
210
+ run_on_failed_transition(*args)
211
+ return_value = false
166
212
  else
167
- target_state = spec.states[event.transitions_to]
168
- check_transition(event)
169
- set_validation_triggers(current_state, target_state, name)
170
- # TODO: shift this down by one line?!
171
- # ... or possibly validate twice!
172
- run_on_transition(current_state, target_state, name, *args) # if valid?
173
- if valid?
174
- transition(current_state, target_state, name, *args)
213
+ if event.perform_validation? and not valid?
214
+ run_on_failed_transition(*args)
215
+ @halted = true # make sure this one is not reset in the on_failed_transition callback
216
+ return_value = false
175
217
  else
176
- @halted_because = 'Validation for transition failed: %{errors}' % {:errors => self.errors.full_messages.join(', ')}
177
- @halted = true
178
- return false
218
+ transition(*args)
179
219
  end
180
- return_value.nil? ? true : return_value
181
220
  end
221
+ return_value.nil? ? true : return_value
182
222
  end
183
223
 
184
- def set_validation_triggers(current_state, target_state, event_name)
185
- self.instance_variable_set "@validate_on_#{current_state}_exit", true
186
- self.instance_variable_set "@validate_on_#{target_state}_entry", true
187
- self.instance_variable_set "@validate_on_#{event_name}", true
224
+ def set_transition_flags(current_state, target_state, event)
225
+ @in_exit = current_state
226
+ @in_entry = target_state
227
+ @in_transition = event
228
+ end
229
+
230
+ def clear_transition_flags
231
+ set_transition_flags nil, nil, nil
188
232
  end
189
233
 
190
234
  def halt(reason = nil)
@@ -193,8 +237,7 @@ module Workflow
193
237
  end
194
238
 
195
239
  def halt!(reason = nil)
196
- @halted_because = reason
197
- @halted = true
240
+ halt reason
198
241
  raise TransitionHalted.new(reason)
199
242
  end
200
243
 
@@ -213,27 +256,49 @@ module Workflow
213
256
  c.workflow_spec
214
257
  end
215
258
 
216
- private
259
+ protected
260
+
261
+ def assure_transition_allowed!(name)
262
+ unless self.send "can_#{name}?"
263
+ prohibit_transition! name
264
+ end
265
+ end
266
+
267
+ def prohibit_transition!(name)
268
+ raise NoTransitionAllowed.new \
269
+ "There is no event #{name} defined for the #{current_state} state."
270
+ end
217
271
 
218
- def check_transition(event)
272
+ def assure_target_state_exists!(event)
219
273
  # Create a meaningful error message instead of
220
274
  # "undefined method `on_entry' for nil:NilClass"
221
275
  # Reported by Kyle Burton
222
276
  if !spec.states[event.transitions_to]
223
- raise WorkflowError.new("Event[#{event.name}]'s " +
224
- "transitions_to[#{event.transitions_to}] is not a declared state.")
277
+ raise WorkflowError.new \
278
+ "Event[#{event.name}]'s transitions_to[#{event.transitions_to}] is not a declared state."
225
279
  end
226
280
  end
227
281
 
228
- def transition(from, to, name, *args)
229
- run_on_exit(from, to, name, *args)
230
- val = persist_workflow_state to.to_s
231
- run_on_entry(to, from, name, *args)
282
+ def transition(*args)
283
+ run_on_exit(*args)
284
+ run_on_transition(*args)
285
+ val = persist_workflow_state wf_target_state.name
286
+ run_on_entry(*args)
232
287
  val
233
288
  end
234
289
 
235
- def run_on_transition(from, to, event, *args)
236
- instance_exec(from.name, to.name, event, *args, &spec.on_transition_proc) if spec.on_transition_proc
290
+ def run_on_transition(*args)
291
+ instance_exec(self.wf_prior_state.name, self.wf_target_state.name, self.wf_event_name, *args, &spec.on_transition_proc) if spec.on_transition_proc
292
+ end
293
+
294
+ def run_on_failed_transition(*args)
295
+ if spec.on_failed_transition_proc
296
+ return_value = instance_exec(self.wf_prior_state.name, self.wf_target_state.name, self.wf_event_name, *args, &spec.on_failed_transition_proc)
297
+ else
298
+ return_value = halt(:validation_failed)
299
+ end
300
+ clear_transition_flags
301
+ return return_value
237
302
  end
238
303
 
239
304
  def run_action(action, *args)
@@ -244,26 +309,42 @@ module Workflow
244
309
  self.send action_name.to_sym, *args if self.respond_to?(action_name.to_sym)
245
310
  end
246
311
 
247
- def run_on_entry(state, prior_state, triggering_event, *args)
248
- if state.on_entry
249
- instance_exec(prior_state.name, triggering_event, *args, &state.on_entry)
312
+ def run_on_entry(*args)
313
+ if self.wf_target_state.on_entry
314
+ instance_exec(self.wf_prior_state.name, self.wf_event_name, *args, &self.wf_target_state.on_entry)
250
315
  else
251
- hook_name = "on_#{state}_entry"
252
- self.send hook_name, prior_state, triggering_event, *args if self.respond_to? hook_name
316
+ hook_name = "on_#{self.wf_target_state.name}_entry"
317
+ self.send hook_name, self.wf_prior_state, self.wf_event_name, *args if self.respond_to? hook_name
253
318
  end
254
319
  end
255
320
 
256
- def run_on_exit(state, new_state, triggering_event, *args)
257
- if state
258
- if state.on_exit
259
- instance_exec(new_state.name, triggering_event, *args, &state.on_exit)
321
+ def run_on_exit(*args)
322
+ if self.wf_prior_state # no on_exit for entry into initial state
323
+ if self.wf_prior_state.on_exit
324
+ instance_exec(self.wf_target_state.name, self.wf_event_name, *args, &self.wf_prior_state.on_exit)
260
325
  else
261
- hook_name = "on_#{state}_exit"
262
- self.send hook_name, new_state, triggering_event, *args if self.respond_to? hook_name
326
+ hook_name = "on_#{self.wf_prior_state.name}_exit"
327
+ self.send hook_name, self.wf_target_state, self.wf_event_name, *args if self.respond_to? hook_name
263
328
  end
264
329
  end
265
330
  end
266
331
 
332
+ def wf_prior_state
333
+ @in_exit
334
+ end
335
+
336
+ def wf_target_state
337
+ @in_entry
338
+ end
339
+
340
+ def wf_event_name
341
+ @in_transition.name
342
+ end
343
+
344
+ def wf_event
345
+ @in_transition
346
+ end
347
+
267
348
  # load_workflow_state and persist_workflow_state
268
349
  # can be overriden to handle the persistence of the workflow state.
269
350
  #
@@ -280,66 +361,17 @@ module Workflow
280
361
  end
281
362
  end
282
363
 
283
- module ActiveRecordInstanceMethods
284
- def load_workflow_state
285
- read_attribute(self.class.workflow_column)
286
- end
287
-
288
- # On transition the new workflow state is immediately saved in the
289
- # database.
290
- def persist_workflow_state(new_value)
291
- update_attribute self.class.workflow_column, new_value
292
- end
293
-
294
- private
295
-
296
- # Motivation: even if NULL is stored in the workflow_state database column,
297
- # the current_state is correctly recognized in the Ruby code. The problem
298
- # arises when you want to SELECT records filtering by the value of initial
299
- # state. That's why it is important to save the string with the name of the
300
- # initial state in all the new records.
301
- def write_initial_state
302
- write_attribute self.class.workflow_column, current_state.to_s
303
- end
304
- end
305
-
306
- module RemodelInstanceMethods
307
- def load_workflow_state
308
- send(self.class.workflow_column)
309
- end
310
-
311
- def persist_workflow_state(new_value)
312
- update(self.class.workflow_column => new_value)
313
- end
314
- end
315
-
316
- module MongoidInstanceMethods
317
- include ActiveRecordInstanceMethods
318
- # implementation of abstract method: saves new workflow state to DB
319
- def persist_workflow_state(new_value)
320
- self.write_attribute(self.class.workflow_column, new_value.to_s)
321
- self.save! :validate => false
322
- end
323
- end
324
-
325
364
  def self.included(klass)
326
365
  klass.send :include, WorkflowInstanceMethods
327
366
  klass.extend WorkflowClassMethods
328
- if Object.const_defined?(:ActiveRecord)
329
- if klass < ActiveRecord::Base
330
- klass.send :include, ActiveRecordInstanceMethods
331
- klass.before_validation :write_initial_state
332
- end
333
- elsif Object.const_defined?(:Remodel)
334
- if klass < Remodel::Entity
335
- klass.send :include, RemodelInstanceMethods
336
- end
337
- elsif Object.const_defined?(:Mongoid)
338
- if klass.include? Mongoid::Document
339
- klass.send :include, MongoidInstanceMethods
340
- klass.after_initialize :write_initial_state
341
- end
342
- end
367
+
368
+ # [ActiveModelPersistence, MongoidPersistence, RemodelPersistence].each do |konst|
369
+ # if konst.happy_to_be_included_in? klass
370
+ # raise "including #{konst}"
371
+ # raise "including #{konst}"
372
+ # klass.send :include, konst
373
+ # end
374
+ # end
343
375
  end
344
376
 
345
377
  # Generates a `dot` graph of the workflow.
@@ -372,34 +404,42 @@ module Workflow
372
404
  workflow_name = "#{klass.name.tableize}_workflow".gsub('/', '_')
373
405
  fname = File.join(target_dir, "generated_#{workflow_name}")
374
406
  File.open("#{fname}.dot", 'w') do |file|
375
- file.puts %Q|
376
- digraph #{workflow_name} {
407
+ file.puts klass.new.workflow_diagram(graph_options)
408
+ end
409
+ `dot -Tpdf -o'#{fname}.pdf' '#{fname}.dot'`
410
+ puts "A PDF file was generated at '#{fname}.pdf'"
411
+ end
412
+
413
+ # Returns a representation of the state diagram for the
414
+ # calling model as a string in dot language.
415
+ # See Workflow.create_workflow_diagram for more deails
416
+ def workflow_diagram(graph_options)
417
+ str = <<-EOS
418
+ digraph #{self.class} {
377
419
  graph [#{graph_options}];
378
420
  node [shape=box];
379
421
  edge [len=1];
380
- |
381
-
382
- klass.workflow_spec.states.each do |state_name, state|
383
- file.puts %Q{ #{state.name} [label="#{state.name}"];}
384
- state.events.each do |event_name, event|
385
- meta_info = event.meta
386
- if meta_info[:doc_weight]
387
- weight_prop = ", weight=#{meta_info[:doc_weight]}"
388
- else
389
- weight_prop = ''
390
- end
391
- file.puts %Q{ #{state.name} -> #{event.transitions_to} [label="#{event_name.to_s.humanize}" #{weight_prop}];}
422
+ EOS
423
+
424
+ self.class.workflow_spec.states.each do |state_name, state|
425
+ state_meta = state.meta
426
+ if state == self.class.workflow_spec.initial_state
427
+ str << %Q{ #{state.name} [label="#{state.name}", shape=circle];\n}
428
+ else
429
+ str << %Q{ #{state.name} [label="#{state.name}", shape=#{state_meta[:terminal] ? 'doublecircle' : 'box, style=rounded'}];\n}
430
+ end
431
+ state.events.each do |event_name, event|
432
+ event_meta = event.meta
433
+ event_meta[:doc_weight] = 6 if event_meta[:main_path]
434
+ if event_meta[:doc_weight]
435
+ weight_prop = ", weight=#{event_meta[:doc_weight]}, penwidth=#{event_meta[:doc_weight] / 2 || 0.0}\n"
436
+ else
437
+ weight_prop = ''
392
438
  end
439
+ str << %Q{ #{state.name} -> #{event.transitions_to} [label="#{event_name.to_s.humanize}" #{weight_prop}];\n}
393
440
  end
394
- file.puts "}"
395
- file.puts
396
441
  end
397
- `dot -Tpdf -o'#{fname}.pdf' '#{fname}.dot'`
398
- puts "
399
- Please run the following to open the generated file:
400
-
401
- open '#{fname}.pdf'
402
-
403
- "
442
+ str << "}\n"
443
+ return str
404
444
  end
405
445
  end
metadata CHANGED
@@ -1,46 +1,30 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: validating-workflow
3
- version: !ruby/object:Gem::Version
4
- hash: 7
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 7
9
- - 2
10
- version: 0.7.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.6
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Vladimir Dobriakov
14
9
  - Willem van Kerkhof
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2010-10-16 00:00:00 +02:00
20
- default_executable:
13
+ date: 2014-02-27 00:00:00.000000000 Z
21
14
  dependencies: []
22
-
23
- description: |
24
- Workflow is a finite-state-machine-inspired API for modeling and interacting
25
- with what we tend to refer to as 'workflow'.
26
-
27
- * nice DSL to describe your states, events and transitions
28
- * robust integration with ActiveRecord and non relational data stores
29
- * various hooks for single transitions, entering state etc.
30
- * convenient access to the workflow specification: list states, possible events
31
- for particular state
32
- * state and transition dependent validations for ActiveModel
33
-
34
- email:
35
- - vladimir@geekq.net
36
- - wvk@consolving.de
15
+ description: ! "Validating-Workflow is a finite-state-machine-inspired API for modeling
16
+ and interacting\n with what we tend to refer to as 'workflow'.\n\n * nice
17
+ DSL to describe your states, events and transitions\n * robust integration with
18
+ ActiveRecord and non relational data stores\n * various hooks for single transitions,
19
+ entering state etc.\n * convenient access to the workflow specification: list
20
+ states, possible events\n for particular state\n * state and transition
21
+ dependent validations for ActiveModel\n"
22
+ email: vladimir@geekq.net, wvk@consolving.de
37
23
  executables: []
38
-
39
24
  extensions: []
40
-
41
- extra_rdoc_files:
25
+ extra_rdoc_files:
42
26
  - README.markdown
43
- files:
27
+ files:
44
28
  - .gitignore
45
29
  - MIT-LICENSE
46
30
  - README.markdown
@@ -55,44 +39,36 @@ files:
55
39
  - test/without_active_record_test.rb
56
40
  - workflow.rb
57
41
  - lib/workflow/state_dependent_validations.rb
58
- has_rdoc: true
59
42
  homepage: http://www.geekq.net/workflow/
60
43
  licenses: []
61
-
62
44
  post_install_message:
63
- rdoc_options:
45
+ rdoc_options:
64
46
  - --charset=UTF-8
65
- require_paths:
47
+ require_paths:
66
48
  - lib
67
- required_ruby_version: !ruby/object:Gem::Requirement
49
+ required_ruby_version: !ruby/object:Gem::Requirement
68
50
  none: false
69
- requirements:
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- hash: 3
73
- segments:
74
- - 0
75
- version: "0"
76
- required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
56
  none: false
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- hash: 3
82
- segments:
83
- - 0
84
- version: "0"
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
85
61
  requirements: []
86
-
87
- rubyforge_project: workflow
88
- rubygems_version: 1.3.7
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.23
89
64
  signing_key:
90
65
  specification_version: 3
91
- summary: A replacement for acts_as_state_machine.
92
- test_files:
66
+ summary: A replacement for acts_as_state_machine, an enhancement of workflow.
67
+ test_files:
93
68
  - test/couchtiny_example.rb
94
69
  - test/main_test.rb
95
70
  - test/test_helper.rb
96
71
  - test/without_active_record_test.rb
97
72
  - test/multiple_workflows_test.rb
98
73
  - test/readme_example.rb
74
+ has_rdoc: