workflow 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -83,6 +83,14 @@ Alternatively you can just download the lib/workflow.rb and put it in
83
83
  the lib folder of your Rails or Ruby application.
84
84
 
85
85
 
86
+ Ruby 1.9
87
+ --------
88
+
89
+ Workflow gem does not work with some (but very widespread) Ruby 1.9
90
+ builds due to a known bug in Ruby 1.9. Either compile your Ruby 1.9 from
91
+ source or [comment out some lines in workflow](http://github.com/geekq/workflow/issues#issue/6)
92
+ (reduces functionality).
93
+
86
94
  Examples
87
95
  --------
88
96
 
@@ -370,7 +378,11 @@ Then you define your different classes:
370
378
  Another solution would be to connect different workflows to object
371
379
  instances via metaclass, e.g.
372
380
 
381
+ # Load an object from the database
373
382
  booking = Booking.find(1234)
383
+
384
+ # Now define a workflow - exclusively for this object,
385
+ # probably depending on some condition or database field
374
386
  if # some condition
375
387
  class << booking
376
388
  include Workflow
@@ -381,7 +393,9 @@ instances via metaclass, e.g.
381
393
  end
382
394
  # if some other condition, use a different workflow
383
395
 
384
- Please also have a look at [the full working example][multiple_workflow_test]!
396
+ You can also encapsulate this in a class method or even put in some
397
+ ActiveRecord callback. Please also have a look at [the full working
398
+ example][multiple_workflow_test]!
385
399
 
386
400
  [STI]: http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
387
401
  [ActiveRecord]: http://api.rubyonrails.org/classes/ActiveRecord/Base.html
@@ -432,6 +446,14 @@ when using both a block and a callback method for an event, the block executes p
432
446
  Changelog
433
447
  ---------
434
448
 
449
+ ### New in the version 0.7.0
450
+
451
+ * fix issue#10 Workflow::create_workflow_diagram documentation and path
452
+ escaping
453
+ * fix issue#7 workflow_column does not work STI (single table
454
+ inheritance) ActiveRecord models
455
+ * fix issue#5 Diagram generation fails for models in modules
456
+
435
457
  ### New in the version 0.6.0
436
458
 
437
459
  * enable multiple workflows by connecting workflow to object instances
@@ -440,8 +462,8 @@ Changelog
440
462
 
441
463
  ### New in the version 0.5.0
442
464
 
443
- * change the behaviour of halt! to immediately raise an exception. See
444
- also http://github.com/geekq/workflow/issues/#issue/3
465
+ * fix issue#3 change the behaviour of halt! to immediately raise an
466
+ exception. See also http://github.com/geekq/workflow/issues/#issue/3
445
467
 
446
468
  ### New in the version 0.4.0
447
469
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.0
data/lib/workflow.rb CHANGED
@@ -100,10 +100,11 @@ module Workflow
100
100
  def workflow_column(column_name=nil)
101
101
  if column_name
102
102
  @workflow_state_column_name = column_name.to_sym
103
- else
104
- @workflow_state_column_name ||= :workflow_state
105
103
  end
106
- @workflow_state_column_name
104
+ if !@workflow_state_column_name && superclass.respond_to?(:workflow_column)
105
+ @workflow_state_column_name = superclass.workflow_column
106
+ end
107
+ @workflow_state_column_name ||= :workflow_state
107
108
  end
108
109
 
109
110
  def workflow(&specification)
@@ -160,8 +161,10 @@ module Workflow
160
161
  else
161
162
  check_transition(event)
162
163
  run_on_transition(current_state, spec.states[event.transitions_to], name, *args)
163
- transition(current_state, spec.states[event.transitions_to], name, *args)
164
- return_value
164
+ transition_value = transition(
165
+ current_state, spec.states[event.transitions_to], name, *args
166
+ )
167
+ return_value.nil? ? transition_value : return_value
165
168
  end
166
169
  end
167
170
 
@@ -205,8 +208,9 @@ module Workflow
205
208
 
206
209
  def transition(from, to, name, *args)
207
210
  run_on_exit(from, to, name, *args)
208
- persist_workflow_state to.to_s
211
+ val = persist_workflow_state to.to_s
209
212
  run_on_entry(to, from, name, *args)
213
+ val
210
214
  end
211
215
 
212
216
  def run_on_transition(from, to, event, *args)
@@ -306,13 +310,13 @@ module Workflow
306
310
  end
307
311
 
308
312
  # Generates a `dot` graph of the workflow.
309
- # Prerequisite: the `dot` binary.
310
- # You can use it in your own Rakefile like this:
313
+ # Prerequisite: the `dot` binary. (Download from http://www.graphviz.org/)
314
+ # You can use this method in your own Rakefile like this:
311
315
  #
312
316
  # namespace :doc do
313
317
  # desc "Generate a graph of the workflow."
314
- # task :workflow do
315
- # Workflow::create_workflow_diagram(Order.new)
318
+ # task :workflow => :environment do # needs access to the Rails environment
319
+ # Workflow::create_workflow_diagram(Order)
316
320
  # end
317
321
  # end
318
322
  #
@@ -331,8 +335,8 @@ module Workflow
331
335
  # @param klass A class with the Workflow mixin, for which you wish the graphical workflow representation
332
336
  # @param [String] target_dir Directory, where to save the dot and the pdf files
333
337
  # @param [String] graph_options You can change graph orientation, size etc. See graphviz documentation
334
- def self.create_workflow_diagram(klass, target_dir, graph_options='rankdir="LR", size="7,11.6", ratio="fill"')
335
- workflow_name = "#{klass.name.tableize}_workflow"
338
+ def self.create_workflow_diagram(klass, target_dir='.', graph_options='rankdir="LR", size="7,11.6", ratio="fill"')
339
+ workflow_name = "#{klass.name.tableize}_workflow".gsub('/', '_')
336
340
  fname = File.join(target_dir, "generated_#{workflow_name}")
337
341
  File.open("#{fname}.dot", 'w') do |file|
338
342
  file.puts %Q|
@@ -357,11 +361,11 @@ digraph #{workflow_name} {
357
361
  file.puts "}"
358
362
  file.puts
359
363
  end
360
- `dot -Tpdf -o#{fname}.pdf #{fname}.dot`
364
+ `dot -Tpdf -o'#{fname}.pdf' '#{fname}.dot'`
361
365
  puts "
362
366
  Please run the following to open the generated file:
363
367
 
364
- open #{fname}.pdf
368
+ open '#{fname}.pdf'
365
369
 
366
370
  "
367
371
  end
data/test/main_test.rb CHANGED
@@ -5,6 +5,7 @@ require 'active_record'
5
5
  require 'sqlite3'
6
6
  require 'workflow'
7
7
  require 'mocha'
8
+ require 'stringio'
8
9
  #require 'ruby-debug'
9
10
 
10
11
  ActiveRecord::Migration.verbose = false
@@ -21,7 +22,6 @@ class Order < ActiveRecord::Base
21
22
  end
22
23
  state :shipped
23
24
  end
24
-
25
25
  end
26
26
 
27
27
  class LegacyOrder < ActiveRecord::Base
@@ -39,9 +39,26 @@ class LegacyOrder < ActiveRecord::Base
39
39
  end
40
40
  state :shipped
41
41
  end
42
+ end
43
+
44
+ class Image < ActiveRecord::Base
45
+ include Workflow
46
+
47
+ workflow_column :status
48
+
49
+ workflow do
50
+ state :unconverted do
51
+ event :convert, :transitions_to => :converted
52
+ end
53
+ state :converted
54
+ end
55
+ end
42
56
 
57
+ class SmallImage < Image
43
58
  end
44
59
 
60
+ class SpecialSmallImage < SmallImage
61
+ end
45
62
 
46
63
  class MainTest < ActiveRecordTestCase
47
64
 
@@ -66,6 +83,13 @@ class MainTest < ActiveRecordTestCase
66
83
 
67
84
  exec "INSERT INTO legacy_orders(title, foo_bar) VALUES('some order', 'accepted')"
68
85
 
86
+ ActiveRecord::Schema.define do
87
+ create_table :images do |t|
88
+ t.string :title, :null => false
89
+ t.string :state
90
+ t.string :type
91
+ end
92
+ end
69
93
  end
70
94
 
71
95
  def assert_state(title, expected_state, klass = Order)
@@ -76,13 +100,13 @@ class MainTest < ActiveRecordTestCase
76
100
 
77
101
  test 'immediately save the new workflow_state on state machine transition' do
78
102
  o = assert_state 'some order', 'accepted'
79
- o.ship!
103
+ assert o.ship!
80
104
  assert_state 'some order', 'shipped'
81
105
  end
82
106
 
83
107
  test 'immediately save the new workflow_state on state machine transition with custom column name' do
84
108
  o = assert_state 'some order', 'accepted', LegacyOrder
85
- o.ship!
109
+ assert o.ship!
86
110
  assert_state 'some order', 'shipped', LegacyOrder
87
111
  end
88
112
 
@@ -257,6 +281,12 @@ class MainTest < ActiveRecordTestCase
257
281
  assert !bo.accepted?
258
282
  end
259
283
 
284
+ test 'STI when parent changed the workflow_state column' do
285
+ assert_equal 'status', Image.workflow_column.to_s
286
+ assert_equal 'status', SmallImage.workflow_column.to_s
287
+ assert_equal 'status', SpecialSmallImage.workflow_column.to_s
288
+ end
289
+
260
290
  test 'Two-level inheritance' do
261
291
  class BigOrder < Order
262
292
  end
@@ -407,5 +437,28 @@ class MainTest < ActiveRecordTestCase
407
437
  assert article.rejected?, 'Transition should happen now'
408
438
  end
409
439
 
440
+ test 'workflow graph generation' do
441
+ Dir.chdir('tmp') do
442
+ capture_streams do
443
+ Workflow::create_workflow_diagram(Order)
444
+ end
445
+ end
446
+ end
447
+
448
+ test 'workflow graph generation in path with spaces' do
449
+ `mkdir -p '/tmp/Workflow test'`
450
+ capture_streams do
451
+ Workflow::create_workflow_diagram(Order, '/tmp/Workflow test')
452
+ end
453
+ end
454
+
455
+ def capture_streams
456
+ old_stdout = $stdout
457
+ $stdout = captured_stdout = StringIO.new
458
+ yield
459
+ $stdout = old_stdout
460
+ captured_stdout
461
+ end
462
+
410
463
  end
411
464
 
@@ -41,6 +41,13 @@ class MultipleWorkflowsTest < ActiveRecordTestCase
41
41
  end
42
42
  end
43
43
  end
44
+
45
+ def metaclass; class << self; self; end; end
46
+
47
+ def workflow_spec
48
+ metaclass.workflow_spec
49
+ end
50
+
44
51
  end
45
52
 
46
53
  booking1 = Booking.find_by_title('booking1')
@@ -56,6 +63,15 @@ class MultipleWorkflowsTest < ActiveRecordTestCase
56
63
  assert booking2.initial?
57
64
  booking2.progress!
58
65
  assert booking2.intermediate?, 'booking2 should transition to the "intermediate" state'
66
+
67
+ assert booking1.workflow_spec, 'can access the individual workflow specification'
68
+ assert_equal 2, booking1.workflow_spec.states.length
69
+ assert_equal 3, booking2.workflow_spec.states.length
70
+ end
71
+
72
+ class Object
73
+ # The hidden singleton lurks behind everyone
74
+ def metaclass; class << self; self; end; end
59
75
  end
60
76
 
61
77
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 6
7
+ - 7
8
8
  - 0
9
- version: 0.6.0
9
+ version: 0.7.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Vladimir Dobriakov
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-07-08 00:00:00 +02:00
17
+ date: 2010-09-08 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20