Skip to content

Commit f65abb3

Browse files
committed
Defining workflow dynamically from JSON #241
1 parent 5e6849a commit f65abb3

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

README.adoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,12 @@ The workflow library itself uses this feature to tweak the graphical
494494
representation of the workflow. See below.
495495
496496
497+
### Defining workflow dynamically from JSON
498+
499+
For an advance example please see
500+
link:https://github.com/geekq/workflow/blob/develop/test/workflow_from_json_test.rb[workflow_from_json_test.rb].
501+
502+
497503
### Compose workflow definition with `include`
498504
499505
In case you have very extensive workflow definition or would like to reuse
@@ -525,6 +531,7 @@ Changelog
525531
526532
* link:https://github.com/geekq/workflow/pull/227[#227] Allow event arguments to be taken into account when selecting the event
527533
* link:https://github.com/geekq/workflow/pull/232[#232] Add ability to include partial workflow definitions for composability
534+
* link:https://github.com/geekq/workflow/pull/241[#241] Example for defining workflow dynamically from JSON
528535
529536
=== New in the version 3.0.0
530537

test/workflow_from_json_test.rb

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
require File.join(File.dirname(__FILE__), 'test_helper')
2+
require 'workflow'
3+
class WorkflowFromJsonTest < Minitest::Test
4+
5+
test '#241 define a workflow from JSON' do
6+
c = Class.new
7+
c.class_eval do
8+
include Workflow
9+
10+
attr_reader :events
11+
12+
def record(event)
13+
@events ||= []
14+
@events << event
15+
end
16+
17+
def ran?(event)
18+
@events.include? event
19+
end
20+
21+
def clear_events
22+
@events = []
23+
end
24+
25+
def event_1(test)
26+
# puts "running event_1 with arg '#{test}'"
27+
record __method__
28+
end
29+
30+
def before_transition(from, to, triggering_event, *args, **kwargs)
31+
# puts "before_transition #{from} -> #{to}, #{triggering_event}, #{args}, #{kwargs}"
32+
record __method__
33+
end
34+
35+
def on_transition(from, to, triggering_event, *args, **kwargs)
36+
# puts "on_transition #{from} -> #{to}, #{triggering_event}, #{args}, #{kwargs}"
37+
record __method__
38+
end
39+
40+
def after_transition(from, to, triggering_event, *args, **kwargs)
41+
# puts "after_transition #{from} -> #{to}, #{triggering_event}, #{args}, #{kwargs}"
42+
record __method__
43+
end
44+
45+
def event_1_condition?
46+
# puts "event_1_condition? -> true"
47+
record __method__
48+
true
49+
end
50+
51+
def on_state_1_exit(new_state, event, *args)
52+
# puts "on_state_1_exit(#{new_state}, #{event}, #{args})"
53+
record __method__
54+
end
55+
56+
def entering_state_2(prior_state, triggering_event, *args, **kwargs)
57+
# puts "entering_state_2 #{prior_state}, #{triggering_event}, #{args}, #{kwargs}"
58+
record __method__
59+
end
60+
61+
def entering_state_3(prior_state, triggering_event, *args, **kwargs)
62+
# puts "entering_state_3 #{prior_state}, #{triggering_event}, #{args}, #{kwargs}"
63+
record __method__
64+
end
65+
66+
def on_state_2_entry(new_state, event, *args)
67+
# puts "on_state_2_entry(#{new_state}, #{event}, #{args})"
68+
record __method__
69+
end
70+
71+
end
72+
73+
ran_normal = []
74+
hash = {
75+
state_1: {
76+
events: {
77+
event_1: {
78+
transition_to: :state_2,
79+
if: :event_1_condition?,
80+
meta: { e1: 1 }
81+
},
82+
},
83+
meta: { a: 1 }
84+
},
85+
state_2: {
86+
events: {
87+
event_2: {
88+
transition_to: :state_3,
89+
}
90+
},
91+
on_entry: :entering_state_2,
92+
meta: { a: 2 }
93+
},
94+
state_3: {
95+
on_entry: "entering_state_3",
96+
}
97+
}
98+
99+
spec = Workflow::Specification.new do
100+
101+
hash.each_pair do |state_name, state_def|
102+
103+
state state_name, state_def
104+
105+
on_entry {|prior_state, triggering_event| send state_def[:on_entry], prior_state, triggering_event } if state_def.include?(:on_entry)
106+
on_exit { ran_normal << :on_exit }
107+
108+
state_def[:events]&.each_pair do |event_name, event_def|
109+
event event_name, event_def
110+
end
111+
112+
end
113+
114+
before_transition do |from, to, triggering_event, *args, **kwargs|
115+
ran_normal << :before_transition
116+
before_transition(from, to, triggering_event, *args, **kwargs)
117+
end
118+
119+
on_transition do |from, to, triggering_event, *args, **kwargs|
120+
ran_normal << :on_transition
121+
on_transition(from, to, triggering_event, *args, **kwargs)
122+
end
123+
124+
after_transition do |from, to, triggering_event, *args, **kwargs|
125+
ran_normal << :after_transition
126+
after_transition(from, to, triggering_event, *args, **kwargs)
127+
end
128+
129+
end
130+
131+
c.send :assign_workflow, spec
132+
133+
o = c.new
134+
135+
assert o.state_1?, "Should be state_1"
136+
refute o.state_2?, "Should not be state_2"
137+
138+
o.event_1! "hello"
139+
[:event_1_condition?, :event_1, :entering_state_2, :before_transition, :on_transition, :after_transition].each do |event|
140+
assert o.ran?(event), "Should have run event #{event}"
141+
end
142+
143+
refute o.state_1?, "Should not be state_1"
144+
assert o.state_2?, "Should be state_2"
145+
146+
o.clear_events
147+
o.event_2!
148+
refute o.ran?(:event_1), "Should not have run event_1"
149+
[:entering_state_3, :before_transition, :on_transition, :after_transition].each do |event|
150+
assert o.ran?(event), "Should have run event #{event}"
151+
end
152+
153+
assert ran_normal.include?(:before_transition), "Should have run before_transition proc"
154+
assert ran_normal.include?(:on_transition), "Should have run on_transition proc"
155+
assert ran_normal.include?(:after_transition), "Should have run after_transition proc"
156+
assert ran_normal.include?(:on_exit), "Should have run on_exit proc"
157+
end
158+
end

0 commit comments

Comments
 (0)