workflow 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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