bpmn 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/lib/{spot_flow → bpmn}/context.rb +5 -5
- data/lib/bpmn/definitions.rb +53 -0
- data/lib/bpmn/element.rb +42 -0
- data/lib/bpmn/event.rb +193 -0
- data/lib/bpmn/event_definition.rb +133 -0
- data/lib/{spot_flow → bpmn}/execution.rb +7 -7
- data/lib/bpmn/extension_elements.rb +27 -0
- data/lib/bpmn/extensions.rb +75 -0
- data/lib/bpmn/flow.rb +45 -0
- data/lib/bpmn/gateway.rb +83 -0
- data/lib/bpmn/process.rb +177 -0
- data/lib/bpmn/step.rb +56 -0
- data/lib/bpmn/task.rb +126 -0
- data/lib/bpmn/version.rb +5 -0
- data/lib/{spot_flow.rb → bpmn.rb} +19 -8
- metadata +17 -18
- data/lib/spot_flow/bpmn/definitions.rb +0 -55
- data/lib/spot_flow/bpmn/element.rb +0 -44
- data/lib/spot_flow/bpmn/event.rb +0 -195
- data/lib/spot_flow/bpmn/event_definition.rb +0 -135
- data/lib/spot_flow/bpmn/extension_elements.rb +0 -29
- data/lib/spot_flow/bpmn/extensions.rb +0 -77
- data/lib/spot_flow/bpmn/flow.rb +0 -47
- data/lib/spot_flow/bpmn/gateway.rb +0 -85
- data/lib/spot_flow/bpmn/process.rb +0 -179
- data/lib/spot_flow/bpmn/step.rb +0 -58
- data/lib/spot_flow/bpmn/task.rb +0 -128
- data/lib/spot_flow/bpmn.rb +0 -18
- data/lib/spot_flow/version.rb +0 -5
data/lib/bpmn/flow.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Flow < Element
|
5
|
+
attr_accessor :source_ref, :target_ref
|
6
|
+
attr_accessor :source, :target
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
super(attributes.except(:source_ref, :target_ref))
|
10
|
+
|
11
|
+
@source_ref = attributes[:source_ref]
|
12
|
+
@target_ref = attributes[:target_ref]
|
13
|
+
@source = nil
|
14
|
+
@target = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
parts = ["#<#{self.class.name.gsub(/BPMN::/, "")} @id=#{id.inspect}"]
|
19
|
+
parts << "@source_ref=#{source_ref.inspect}" if source_ref
|
20
|
+
parts << "@target_ref=#{target_ref.inspect}" if target_ref
|
21
|
+
parts.join(" ") + ">"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Association < Flow
|
26
|
+
end
|
27
|
+
|
28
|
+
class SequenceFlow < Flow
|
29
|
+
attr_accessor :condition
|
30
|
+
|
31
|
+
def initialize(attributes = {})
|
32
|
+
super(attributes.except(:condition))
|
33
|
+
|
34
|
+
@condition = attributes[:condition_expression]
|
35
|
+
end
|
36
|
+
|
37
|
+
def evaluate(execution)
|
38
|
+
return true unless condition
|
39
|
+
execution.evaluate_condition(condition)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class TextAnnotation < Flow
|
44
|
+
end
|
45
|
+
end
|
data/lib/bpmn/gateway.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Gateway < Step
|
5
|
+
|
6
|
+
def execute(execution)
|
7
|
+
if converging?
|
8
|
+
if is_enabled?(execution)
|
9
|
+
return leave(execution)
|
10
|
+
else
|
11
|
+
execution.wait
|
12
|
+
end
|
13
|
+
else
|
14
|
+
return leave(execution)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Algorithm from https://researcher.watson.ibm.com/researcher/files/zurich-hvo/bpm2010-1.pdf
|
20
|
+
#
|
21
|
+
def is_enabled?(execution)
|
22
|
+
filled = []
|
23
|
+
empty = []
|
24
|
+
|
25
|
+
incoming.each { |flow| execution.tokens_in.include?(flow.id) ? filled.push(flow) : empty.push(flow) }
|
26
|
+
|
27
|
+
# Filled slots don't need to be searched for tokens
|
28
|
+
index = 0
|
29
|
+
while (index < filled.length)
|
30
|
+
current_flow = filled[index]
|
31
|
+
current_flow.source.incoming.each do |incoming_flow|
|
32
|
+
filled.push(incoming_flow) unless filled.include?(incoming_flow) || incoming_flow.target == self
|
33
|
+
end
|
34
|
+
index = index + 1
|
35
|
+
end
|
36
|
+
|
37
|
+
# Empty slots need to be searched for tokens
|
38
|
+
index = 0
|
39
|
+
while (index < empty.length)
|
40
|
+
current_flow = empty[index]
|
41
|
+
current_flow.source.incoming.each do |incoming_flow|
|
42
|
+
empty.push(incoming_flow) unless filled.include?(incoming_flow) || empty.include?(incoming_flow) || incoming_flow.target == self
|
43
|
+
end
|
44
|
+
index = index + 1
|
45
|
+
end
|
46
|
+
|
47
|
+
empty_ids = empty.map { |g| g.id }
|
48
|
+
|
49
|
+
# If there are empty slots with tokens we need to wait
|
50
|
+
return false if (empty_ids & execution.parent.tokens).length > 0
|
51
|
+
return true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ExclusiveGateway < Gateway
|
56
|
+
# RULE: Only one flow is taken
|
57
|
+
def outgoing_flows(step_execution)
|
58
|
+
flows = super
|
59
|
+
return [flows.first]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class ParallelGateway < Gateway
|
64
|
+
# RULE: All flows are taken
|
65
|
+
end
|
66
|
+
|
67
|
+
class InclusiveGateway < Gateway
|
68
|
+
# RULE: All valid flows are taken
|
69
|
+
# NOTE: Camunda 8 only support diverging but not converging inclusive gateways
|
70
|
+
end
|
71
|
+
|
72
|
+
class EventBasedGateway < Gateway
|
73
|
+
#
|
74
|
+
# RULE: when an event created from an event gateway is caught,
|
75
|
+
# all other waiting events must be canceled.
|
76
|
+
#
|
77
|
+
def cancel_waiting_events(execution)
|
78
|
+
execution.targets.each do |target_execution|
|
79
|
+
target_execution.terminate unless target_execution.ended?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/bpmn/process.rb
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Process < Step
|
5
|
+
attr_accessor :is_executable
|
6
|
+
|
7
|
+
attr_accessor :start_events, :end_events, :intermediate_catch_events, :intermediate_throw_events, :boundary_events
|
8
|
+
attr_accessor :tasks, :user_tasks, :service_tasks, :script_tasks, :send_tasks, :receive_tasks, :manual_tasks, :business_rule_tasks, :call_activities
|
9
|
+
attr_accessor :sub_processes, :ad_hoc_sub_processes
|
10
|
+
attr_accessor :sequence_flows, :message_flows, :associations, :data_associations, :data_inputs, :data_outputs
|
11
|
+
attr_accessor :data_objects, :data_stores, :data_stores_references
|
12
|
+
attr_accessor :gateways, :exclusive_gateways, :parallel_gateways, :inclusive_gateways, :event_based_gateways, :complex_gateways
|
13
|
+
|
14
|
+
attr_accessor :parent
|
15
|
+
|
16
|
+
def initialize(attributes = {})
|
17
|
+
super(attributes.slice(:id, :name, :extension_elements, :incoming, :outgoing, :default))
|
18
|
+
|
19
|
+
@is_executable = attributes[:is_executable] == ("true" || true)
|
20
|
+
|
21
|
+
@start_events = Array.wrap(attributes[:start_event]).map { |se| StartEvent.new(se) }
|
22
|
+
@end_events = Array.wrap(attributes[:end_event]).map { |ee| EndEvent.new(ee) }
|
23
|
+
@intermediate_catch_events = Array.wrap(attributes[:intermediate_catch_event]).map { |ice| IntermediateCatchEvent.new(ice) }
|
24
|
+
@intermediate_throw_events = Array.wrap(attributes[:intermediate_throw_event]).map { |ite| IntermediateThrowEvent.new(ite) }
|
25
|
+
@boundary_events = Array.wrap(attributes[:boundary_event]).map { |be| BoundaryEvent.new(be) }
|
26
|
+
@tasks = Array.wrap(attributes[:task]).map { |t| Task.new(t) }
|
27
|
+
@user_tasks = Array.wrap(attributes[:user_task]).map { |ut| UserTask.new(ut) }
|
28
|
+
@service_tasks = Array.wrap(attributes[:service_task]).map { |st| ServiceTask.new(st) }
|
29
|
+
@script_tasks = Array.wrap(attributes[:script_task]).map { |st| ScriptTask.new(st) }
|
30
|
+
@business_rule_tasks = Array.wrap(attributes[:business_rule_task]).map { |brt| BusinessRuleTask.new(brt) }
|
31
|
+
@call_activities = Array.wrap(attributes[:call_activity]).map { |ca| CallActivity.new(ca) }
|
32
|
+
@sub_processes = Array.wrap(attributes[:sub_process]).map { |sp| SubProcess.new(sp) }
|
33
|
+
@ad_hoc_sub_processes = Array.wrap(attributes[:ad_hoc_sub_processe]).map { |ahsp| AdHocSubProcess.new(ahsp) }
|
34
|
+
@exclusive_gateways = Array.wrap(attributes[:exclusive_gateway]).map { |eg| ExclusiveGateway.new(eg) }
|
35
|
+
@parallel_gateways = Array.wrap(attributes[:parallel_gateway]).map { |pg| ParallelGateway.new(pg) }
|
36
|
+
@inclusive_gateways = Array.wrap(attributes[:inclusive_gateway]).map { |ig| InclusiveGateway.new(ig) }
|
37
|
+
@event_based_gateways = Array.wrap(attributes[:event_based_gateway]).map { |ebg| EventBasedGateway.new(ebg) }
|
38
|
+
@sequence_flows = Array.wrap(attributes[:sequence_flow]).map { |sf| SequenceFlow.new(sf) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def elements
|
42
|
+
@elements ||= {}.tap do |elements|
|
43
|
+
elements.merge!(start_events.index_by(&:id))
|
44
|
+
elements.merge!(end_events.index_by(&:id))
|
45
|
+
elements.merge!(intermediate_catch_events.index_by(&:id))
|
46
|
+
elements.merge!(intermediate_throw_events.index_by(&:id))
|
47
|
+
elements.merge!(boundary_events.index_by(&:id))
|
48
|
+
elements.merge!(tasks.index_by(&:id))
|
49
|
+
elements.merge!(user_tasks.index_by(&:id))
|
50
|
+
elements.merge!(service_tasks.index_by(&:id))
|
51
|
+
elements.merge!(script_tasks.index_by(&:id))
|
52
|
+
elements.merge!(business_rule_tasks.index_by(&:id))
|
53
|
+
elements.merge!(call_activities.index_by(&:id))
|
54
|
+
elements.merge!(sub_processes.index_by(&:id))
|
55
|
+
elements.merge!(ad_hoc_sub_processes.index_by(&:id))
|
56
|
+
elements.merge!(exclusive_gateways.index_by(&:id))
|
57
|
+
elements.merge!(parallel_gateways.index_by(&:id))
|
58
|
+
elements.merge!(inclusive_gateways.index_by(&:id))
|
59
|
+
elements.merge!(event_based_gateways.index_by(&:id))
|
60
|
+
elements.merge!(sequence_flows.index_by(&:id))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def wire_references(definitions)
|
65
|
+
elements.values.each do |element|
|
66
|
+
if element.is_a?(Step)
|
67
|
+
element.incoming = element.incoming.map { |id| element_by_id(id) }
|
68
|
+
element.outgoing = element.outgoing.map { |id| element_by_id(id) }
|
69
|
+
|
70
|
+
if element.is_a?(Event)
|
71
|
+
|
72
|
+
element.event_definitions.each do |event_definition|
|
73
|
+
if event_definition.is_a?(MessageEventDefinition)
|
74
|
+
event_definition.message = definitions.message_by_id(event_definition.message_ref)
|
75
|
+
elsif event_definition.is_a?(SignalEventDefinition)
|
76
|
+
event_definition.signal = definitions.signal_by_id(event_definition.signal_ref)
|
77
|
+
elsif event_definition.is_a?(ErrorEventDefinition)
|
78
|
+
event_definition.error = definitions.error_by_id(event_definition.error_ref)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if element.is_a?(BoundaryEvent)
|
83
|
+
host_element = element_by_id(element.attached_to_ref)
|
84
|
+
host_element.attachments << element
|
85
|
+
element.attached_to = host_element
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
if element.is_a?(Gateway)
|
91
|
+
element.default = element_by_id(element.default_ref)
|
92
|
+
end
|
93
|
+
|
94
|
+
if element.is_a?(SubProcess)
|
95
|
+
element.wire_references(definitions)
|
96
|
+
end
|
97
|
+
|
98
|
+
elsif element.is_a?(SequenceFlow)
|
99
|
+
element.source = element_by_id(element.source_ref)
|
100
|
+
element.target = element_by_id(element.target_ref)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Not handled participant process ref
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def element_by_id(id)
|
108
|
+
elements[id]
|
109
|
+
end
|
110
|
+
|
111
|
+
def elements_by_type(type)
|
112
|
+
elements.select { |e| e.class == type }
|
113
|
+
end
|
114
|
+
|
115
|
+
def default_start_event
|
116
|
+
start_events.find { |se| se.event_definitions.empty? }
|
117
|
+
end
|
118
|
+
|
119
|
+
def execute(execution)
|
120
|
+
start_event = execution.start_event_id ? element_by_id(execution.start_event_id) : default_start_event
|
121
|
+
raise ExecutionErrorNew.new("Process must have at least one start event.") if start_event.blank?
|
122
|
+
execution.execute_step(start_event)
|
123
|
+
end
|
124
|
+
|
125
|
+
def inspect
|
126
|
+
parts = ["#<#{self.class.name.gsub(/BPMN::/, "")} @id=#{id.inspect} @name=#{name.inspect} @is_executable=#{is_executable.inspect}"]
|
127
|
+
parts << "@parent=#{parent.inspect}" if parent
|
128
|
+
event_attrs = (start_events + intermediate_catch_events + intermediate_throw_events + boundary_events + end_events).compact
|
129
|
+
parts << "@events=#{event_attrs.inspect}" unless event_attrs.blank?
|
130
|
+
activity_attrs = (tasks + user_tasks + service_tasks + script_tasks + business_rule_tasks + call_activities).compact
|
131
|
+
parts << "@activities=#{activity_attrs.inspect}" unless activity_attrs.blank?
|
132
|
+
gateway_attrs = (exclusive_gateways + parallel_gateways + inclusive_gateways + event_based_gateways).compact
|
133
|
+
parts << "@gateways=#{gateway_attrs.inspect}" unless gateway_attrs.blank?
|
134
|
+
sub_process_attrs = (sub_processes + ad_hoc_sub_processes).compact
|
135
|
+
parts << "@sub_processes=#{sub_process_attrs.inspect}" unless sub_process_attrs.blank?
|
136
|
+
parts << "@sequence_flows=#{sequence_flows.inspect}" unless sequence_flows.blank?
|
137
|
+
parts.join(" ") + ">"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class SubProcess < Process
|
142
|
+
attr_accessor :triggered_by_event
|
143
|
+
|
144
|
+
def initialize(attributes = {})
|
145
|
+
super(attributes.except(:triggered_by_event))
|
146
|
+
|
147
|
+
@is_executable = false
|
148
|
+
@sub_processes = []
|
149
|
+
@triggered_by_event = attributes[:triggered_by_event]
|
150
|
+
end
|
151
|
+
|
152
|
+
def execution_ended(execution)
|
153
|
+
leave(execution)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class AdHocSubProcess < SubProcess
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
class CallActivity < Activity
|
162
|
+
attr_reader :process_id
|
163
|
+
|
164
|
+
def execute(execution)
|
165
|
+
if extension_elements&.called_element&.process_id&.start_with?("=")
|
166
|
+
@process_id = DMN.evaluate(extension_elements&.called_element&.process_id, variables: execution.variables)
|
167
|
+
else
|
168
|
+
@process_id = extension_elements&.called_element&.process_id
|
169
|
+
end
|
170
|
+
|
171
|
+
execution.wait
|
172
|
+
|
173
|
+
process = execution.context.process_by_id(@process_id) if @process_id
|
174
|
+
execution.execute_step(process.default_start_event) if process
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
data/lib/bpmn/step.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Step < Element
|
5
|
+
attr_accessor :incoming, :outgoing, :default, :default_ref
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
super(attributes.except(:incoming, :outgoing, :default))
|
9
|
+
|
10
|
+
@incoming = Array.wrap(attributes[:incoming]) || []
|
11
|
+
@outgoing = Array.wrap(attributes[:outgoing]) || []
|
12
|
+
@default_ref = attributes[:default]
|
13
|
+
end
|
14
|
+
|
15
|
+
def diverging?
|
16
|
+
outgoing.length > 1
|
17
|
+
end
|
18
|
+
|
19
|
+
def converging?
|
20
|
+
incoming.length > 1
|
21
|
+
end
|
22
|
+
|
23
|
+
def leave(execution)
|
24
|
+
execution.end(false)
|
25
|
+
execution.take_all(outgoing_flows(execution))
|
26
|
+
end
|
27
|
+
|
28
|
+
def outgoing_flows(execution)
|
29
|
+
flows = []
|
30
|
+
outgoing.each do |flow|
|
31
|
+
result = flow.evaluate(execution) unless default&.id == flow.id
|
32
|
+
flows.push flow if result
|
33
|
+
end
|
34
|
+
flows = [default] if flows.empty? && default
|
35
|
+
return flows
|
36
|
+
end
|
37
|
+
|
38
|
+
def input_mappings
|
39
|
+
extension_elements&.io_mapping&.inputs || []
|
40
|
+
end
|
41
|
+
|
42
|
+
def output_mappings
|
43
|
+
extension_elements&.io_mapping&.outputs || []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Activity < Step
|
48
|
+
attr_accessor :attachments
|
49
|
+
|
50
|
+
def initialize(attributes = {})
|
51
|
+
super(attributes.except(:attachments))
|
52
|
+
|
53
|
+
@attachments = []
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/bpmn/task.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BPMN
|
4
|
+
class Task < Activity
|
5
|
+
|
6
|
+
def is_automated?
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
def is_manual?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(execution)
|
15
|
+
execution.wait
|
16
|
+
end
|
17
|
+
|
18
|
+
def signal(execution)
|
19
|
+
leave(execution)
|
20
|
+
end
|
21
|
+
|
22
|
+
def result_to_variables(result)
|
23
|
+
if result_variable
|
24
|
+
return { "#{result_variable}": result }
|
25
|
+
else
|
26
|
+
if result.is_a? Hash
|
27
|
+
result
|
28
|
+
else
|
29
|
+
{}.tap { |h| h[id.underscore] = result }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class UserTask < Task
|
36
|
+
|
37
|
+
def form_key
|
38
|
+
extension_elements&.form_definition&.form_key
|
39
|
+
end
|
40
|
+
|
41
|
+
def assignee
|
42
|
+
extension_elements&.assignment_definition&.assignee
|
43
|
+
end
|
44
|
+
|
45
|
+
def candidate_groups
|
46
|
+
extension_elements&.assignment_definition&.candidate_groups
|
47
|
+
end
|
48
|
+
|
49
|
+
def candidate_users
|
50
|
+
extension_elements&.assignment_definition&.candidate_users
|
51
|
+
end
|
52
|
+
|
53
|
+
def due_date
|
54
|
+
extension_elements&.task_schedule&.due_date
|
55
|
+
end
|
56
|
+
|
57
|
+
def follow_up_date
|
58
|
+
extension_elements&.task_schedule&.follow_up_date
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class ServiceTask < Task
|
63
|
+
attr_accessor :service
|
64
|
+
|
65
|
+
def is_automated?
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def is_manual?
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
def execute(execution)
|
74
|
+
execution.wait
|
75
|
+
end
|
76
|
+
|
77
|
+
def task_type
|
78
|
+
extension_elements&.task_definition&.type
|
79
|
+
end
|
80
|
+
|
81
|
+
def task_retries
|
82
|
+
extension_elements&.task_definition&.retries
|
83
|
+
end
|
84
|
+
|
85
|
+
def headers
|
86
|
+
extension_elements&.task_headers&.headers
|
87
|
+
end
|
88
|
+
|
89
|
+
def run(execution)
|
90
|
+
if defined?(task_type)
|
91
|
+
klass = task_type.constantize
|
92
|
+
klass.new.call(execution.parent.variables, headers || {})
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class ScriptTask < ServiceTask
|
98
|
+
|
99
|
+
def script
|
100
|
+
extension_elements&.script&.expression
|
101
|
+
end
|
102
|
+
|
103
|
+
def result_variable
|
104
|
+
extension_elements&.script&.result_variable
|
105
|
+
end
|
106
|
+
|
107
|
+
def run(execution)
|
108
|
+
DMN.evaluate(script.delete_prefix("="), variables: execution.parent.variables)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class BusinessRuleTask < ServiceTask
|
113
|
+
|
114
|
+
def decision_id
|
115
|
+
extension_elements&.called_decision&.decision_id
|
116
|
+
end
|
117
|
+
|
118
|
+
def result_variable
|
119
|
+
extension_elements&.called_decision&.result_variable
|
120
|
+
end
|
121
|
+
|
122
|
+
def run(execution)
|
123
|
+
DMN.decide(decision_id, definitions: execution.context.dmn_definitions_by_decision_id(decision_id), variables: execution.parent.variables)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/bpmn/version.rb
ADDED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "bpmn/version"
|
4
4
|
|
5
5
|
require "active_support"
|
6
6
|
require "active_support/time"
|
@@ -9,13 +9,24 @@ require "active_support/core_ext/object/json"
|
|
9
9
|
require "active_support/configurable"
|
10
10
|
require "active_model"
|
11
11
|
|
12
|
-
require "
|
12
|
+
require "dmn"
|
13
13
|
|
14
|
-
require "
|
15
|
-
require "
|
16
|
-
require "
|
14
|
+
require "bpmn/element"
|
15
|
+
require "bpmn/extensions"
|
16
|
+
require "bpmn/extension_elements"
|
17
|
+
require "bpmn/step"
|
18
|
+
require "bpmn/flow"
|
19
|
+
require "bpmn/event_definition"
|
20
|
+
require "bpmn/event"
|
21
|
+
require "bpmn/gateway"
|
22
|
+
require "bpmn/task"
|
23
|
+
require "bpmn/process"
|
24
|
+
require "bpmn/definitions"
|
17
25
|
|
18
|
-
|
26
|
+
require "bpmn/context"
|
27
|
+
require "bpmn/execution"
|
28
|
+
|
29
|
+
module BPMN
|
19
30
|
include ActiveSupport::Configurable
|
20
31
|
|
21
32
|
#
|
@@ -36,14 +47,14 @@ module SpotFlow
|
|
36
47
|
# Extract processes from a BMPN XML file.
|
37
48
|
#
|
38
49
|
def self.processes_from_xml(xml)
|
39
|
-
|
50
|
+
Definitions.from_xml(xml)&.processes || []
|
40
51
|
end
|
41
52
|
|
42
53
|
#
|
43
54
|
# Extract decisions from a DMN XML file.
|
44
55
|
#
|
45
56
|
def self.decisions_from_xml(xml)
|
46
|
-
definitions =
|
57
|
+
definitions = DMN.definitions_from_xml(xml)
|
47
58
|
definitions.decisions
|
48
59
|
end
|
49
60
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bpmn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Connected Bits
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -189,22 +189,21 @@ files:
|
|
189
189
|
- MIT-LICENSE
|
190
190
|
- README.md
|
191
191
|
- Rakefile
|
192
|
-
- lib/
|
193
|
-
- lib/
|
194
|
-
- lib/
|
195
|
-
- lib/
|
196
|
-
- lib/
|
197
|
-
- lib/
|
198
|
-
- lib/
|
199
|
-
- lib/
|
200
|
-
- lib/
|
201
|
-
- lib/
|
202
|
-
- lib/
|
203
|
-
- lib/
|
204
|
-
- lib/
|
205
|
-
- lib/
|
206
|
-
- lib/
|
207
|
-
- lib/spot_flow/version.rb
|
192
|
+
- lib/bpmn.rb
|
193
|
+
- lib/bpmn/context.rb
|
194
|
+
- lib/bpmn/definitions.rb
|
195
|
+
- lib/bpmn/element.rb
|
196
|
+
- lib/bpmn/event.rb
|
197
|
+
- lib/bpmn/event_definition.rb
|
198
|
+
- lib/bpmn/execution.rb
|
199
|
+
- lib/bpmn/extension_elements.rb
|
200
|
+
- lib/bpmn/extensions.rb
|
201
|
+
- lib/bpmn/flow.rb
|
202
|
+
- lib/bpmn/gateway.rb
|
203
|
+
- lib/bpmn/process.rb
|
204
|
+
- lib/bpmn/step.rb
|
205
|
+
- lib/bpmn/task.rb
|
206
|
+
- lib/bpmn/version.rb
|
208
207
|
homepage: https://www.connectedbits.com
|
209
208
|
licenses:
|
210
209
|
- MIT
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module SpotFlow
|
4
|
-
module Bpmn
|
5
|
-
class Definitions
|
6
|
-
include ActiveModel::Model
|
7
|
-
|
8
|
-
attr_accessor :id, :name, :target_namespace, :exporter, :exporter_version, :execution_platform, :execution_platform_version
|
9
|
-
attr_reader :messages, :signals, :errors, :processes
|
10
|
-
|
11
|
-
def self.from_xml(xml)
|
12
|
-
XmlHasher.configure do |config|
|
13
|
-
config.snakecase = true
|
14
|
-
config.ignore_namespaces = true
|
15
|
-
config.string_keys = false
|
16
|
-
end
|
17
|
-
hash = XmlHasher.parse(xml)
|
18
|
-
Definitions.new(hash[:definitions].except(:bpmn_diagram)).tap do |definitions|
|
19
|
-
definitions.processes.each do |process|
|
20
|
-
process.wire_references(definitions)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize(attributes={})
|
26
|
-
super(attributes.except(:message, :signal, :error, :process))
|
27
|
-
|
28
|
-
@messages = Array.wrap(attributes[:message]).map { |atts| Message.new(atts) }
|
29
|
-
@signals = Array.wrap(attributes[:signal]).map { |atts| Signal.new(atts) }
|
30
|
-
@errors = Array.wrap(attributes[:error]).map { |atts| Error.new(atts) }
|
31
|
-
@processes = Array.wrap(attributes[:process]).map { |atts| Process.new(atts) }
|
32
|
-
end
|
33
|
-
|
34
|
-
def message_by_id(id)
|
35
|
-
messages.find { |message| message.id == id }
|
36
|
-
end
|
37
|
-
|
38
|
-
def signal_by_id(id)
|
39
|
-
signals.find { |signal| signal.id == id }
|
40
|
-
end
|
41
|
-
|
42
|
-
def error_by_id(id)
|
43
|
-
errors.find { |error| error.id == id }
|
44
|
-
end
|
45
|
-
|
46
|
-
def process_by_id(id)
|
47
|
-
processes.find { |process| process.id == id }
|
48
|
-
end
|
49
|
-
|
50
|
-
def inspect
|
51
|
-
"#<Bpmn::Definitions @id=#{id.inspect} @name=#{name.inspect} @messages=#{messages.inspect} @signals=#{signals.inspect} @errors=#{errors.inspect} @processes=#{processes.inspect}>"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|