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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33862df282c4b5eae3fa1b4317e7762c299ace6ac8794f138efc86d6225645c0
4
- data.tar.gz: 7f67bb1e73ee9020c5f5bb5f67ff29c2312f3412ae8ae77a3be142c1d12c6a1e
3
+ metadata.gz: 7ffd863edea8a05d607b816c4fc0464968a822db50e8389ccfd36cc68734e6ba
4
+ data.tar.gz: 624fc1a44f2b4c6c9c3dd1bd309ce6d0a2a381f74fe975a65c067616384d2af3
5
5
  SHA512:
6
- metadata.gz: c4e9586ba65c154da496be6b5635000ab3f6e61624f8733a2b2fec87eecac5b193df176075d4db146d84e09d22e99fcce2090e559fd01ed8847d4399d3808b42
7
- data.tar.gz: f995dbb81528b381e56d8cd74286ae273d8e890a4a2f2f35fca8de736169cce2eddec467148a48d4bd4943a8b8345bed2b2d99285921417a07457dc8adecfe8f
6
+ metadata.gz: 9581fe6232d79731cb29b5267afeced58fd5c8f817ba7e98ee77aadfb048ef8f05f0e0851010cce4f78e0de4b18beddfc812874ce0cf99e6b0ae46d6e43e6370
7
+ data.tar.gz: 338dad681a7d7ec6c67bb1a16b2cb42a0745575cb66fe23fbea2479eeee9b430248ed94a0bb6c0bbb49809eaa3c9494a3de028b381239a3ffd0d221b9d79b1d7
data/README.md CHANGED
@@ -15,14 +15,14 @@ Processes are made of a series of tasks. Tasks can be manual (require `signal` t
15
15
  - BusinessRuleTask (automated): evaluates the decision_id (expects dmn source to be included in the context).
16
16
  - ScriptTask (automated): evaluates the FEEL expression in the script property.
17
17
 
18
- To start the process, initialize SpotFlow with the BPMN and DMN source files, then call `start`.
18
+ To start the process, initialize with the BPMN and DMN source files, then call `start`.
19
19
 
20
20
  ```ruby
21
21
  sources = [
22
22
  File.read("hello_world.bpmn"),
23
23
  File.read("choose_greeting.dmn")
24
24
  ]
25
- execution = SpotFlow.new(sources).start
25
+ execution = BPMN.new(sources).start
26
26
  ```
27
27
 
28
28
  It's often useful to print the process state to the console.
@@ -39,7 +39,7 @@ HelloWorld started * Flow_080794y
39
39
  2 BoundaryEvent EggTimer: waiting
40
40
  ```
41
41
 
42
- The HelloWorld process began at the Start event and is _waiting_ at the IntroduceYourself user task. This is an important concept in the SpotFlow engine. It's designed to be used in a Rails application where a process might be waiting for a user to complete a form, or a background job to complete. It's common to save the state the process until a task is complete. Calling `serialize` on a process will return the execution state so it can be continued later.
42
+ The HelloWorld process began at the Start event and is _waiting_ at the IntroduceYourself user task. This is an important concept in the BPMN engine. It's designed to be used in a Rails application where a process might be waiting for a user to complete a form, or a background job to complete. It's common to save the state the process until a task is complete. Calling `serialize` on a process will return the execution state so it can be continued later.
43
43
 
44
44
  ```ruby
45
45
  # Returns a hash of the process state.
@@ -49,7 +49,7 @@ execution_state = execution.serialize
49
49
  # or a background job completes (ServiceTask)
50
50
 
51
51
  # Restores the process from the execution state.
52
- execution = SpotFlow.restore(sources, execution_state:)
52
+ execution = BPMN.restore(sources, execution_state:)
53
53
 
54
54
  # Now we can continue the process by `signaling` the waiting task.
55
55
  step = execution.step_by_element_id("IntroduceYourself")
@@ -162,13 +162,13 @@ HelloWorld completed *
162
162
  Execute:
163
163
 
164
164
  ```bash
165
- $ bundle add spot_flow
165
+ $ bundle add bpmn
166
166
  ```
167
167
 
168
168
  Or install it directly:
169
169
 
170
170
  ```bash
171
- $ gem install spot_flow
171
+ $ gem install bpmn
172
172
  ```
173
173
 
174
174
  ## Development
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SpotFlow
3
+ module BPMN
4
4
  class Context
5
5
  attr_reader :sources, :processes, :decisions, :services, :executions
6
6
  attr_reader :bpmn_definitions, :dmn_definitions
@@ -11,15 +11,15 @@ module SpotFlow
11
11
  @bpmn_definitions = []
12
12
  @dmn_definitions = []
13
13
  @decisions = Array.wrap(decisions)
14
- @services = HashWithIndifferentAccess.new((SpotFlow.config.services || {}).merge(services))
14
+ @services = HashWithIndifferentAccess.new((BPMN.config.services || {}).merge(services))
15
15
 
16
16
  @sources.each do |source|
17
17
  if source.include?("http://www.omg.org/spec/DMN/20180521/DC/")
18
- definitions = SpotFeel.definitions_from_xml(source)
18
+ definitions = DMN.definitions_from_xml(source)
19
19
  @dmn_definitions << definitions
20
20
  @decisions += definitions.decisions
21
21
  else
22
- @processes += SpotFlow.processes_from_xml(source)
22
+ @processes += BPMN.processes_from_xml(source)
23
23
  end
24
24
  end
25
25
 
@@ -55,7 +55,7 @@ module SpotFlow
55
55
  end
56
56
 
57
57
  def notify_listener(*args)
58
- SpotFlow.config.listener&.call(args)
58
+ BPMN.config.listener&.call(args)
59
59
  end
60
60
 
61
61
  def default_process
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BPMN
4
+ class Definitions
5
+ include ActiveModel::Model
6
+
7
+ attr_accessor :id, :name, :target_namespace, :exporter, :exporter_version, :execution_platform, :execution_platform_version
8
+ attr_reader :messages, :signals, :errors, :processes
9
+
10
+ def self.from_xml(xml)
11
+ XmlHasher.configure do |config|
12
+ config.snakecase = true
13
+ config.ignore_namespaces = true
14
+ config.string_keys = false
15
+ end
16
+ hash = XmlHasher.parse(xml)
17
+ Definitions.new(hash[:definitions].except(:bpmn_diagram)).tap do |definitions|
18
+ definitions.processes.each do |process|
19
+ process.wire_references(definitions)
20
+ end
21
+ end
22
+ end
23
+
24
+ def initialize(attributes={})
25
+ super(attributes.except(:message, :signal, :error, :process))
26
+
27
+ @messages = Array.wrap(attributes[:message]).map { |atts| Message.new(atts) }
28
+ @signals = Array.wrap(attributes[:signal]).map { |atts| Signal.new(atts) }
29
+ @errors = Array.wrap(attributes[:error]).map { |atts| Error.new(atts) }
30
+ @processes = Array.wrap(attributes[:process]).map { |atts| Process.new(atts) }
31
+ end
32
+
33
+ def message_by_id(id)
34
+ messages.find { |message| message.id == id }
35
+ end
36
+
37
+ def signal_by_id(id)
38
+ signals.find { |signal| signal.id == id }
39
+ end
40
+
41
+ def error_by_id(id)
42
+ errors.find { |error| error.id == id }
43
+ end
44
+
45
+ def process_by_id(id)
46
+ processes.find { |process| process.id == id }
47
+ end
48
+
49
+ def inspect
50
+ "#<BPMN::Definitions @id=#{id.inspect} @name=#{name.inspect} @messages=#{messages.inspect} @signals=#{signals.inspect} @errors=#{errors.inspect} @processes=#{processes.inspect}>"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BPMN
4
+ class Element
5
+ include ActiveModel::Model
6
+
7
+ attr_accessor :id, :name, :extension_elements
8
+
9
+ def initialize(attributes = {})
10
+ super(attributes.slice(:id, :name))
11
+
12
+ @extension_elements = ExtensionElements.new(attributes[:extension_elements]) if attributes[:extension_elements].present?
13
+ end
14
+
15
+ def inspect
16
+ "#<#{self.class.name.gsub(/BPMN::/, "")} @id=#{id.inspect} @name=#{name.inspect}>"
17
+ end
18
+ end
19
+
20
+ class Message < Element
21
+ end
22
+
23
+ class Signal < Element
24
+ end
25
+
26
+ class Error < Element
27
+ end
28
+
29
+ class Collaboration < Element
30
+ end
31
+
32
+ class LaneSet < Element
33
+ end
34
+
35
+ class Participant < Element
36
+ attr_accessor :process_ref, :process
37
+
38
+ def initialize(attributes = {})
39
+ super(attributes.except(:process_ref))
40
+ end
41
+ end
42
+ end
data/lib/bpmn/event.rb ADDED
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BPMN
4
+ class Event < Step
5
+ attr_accessor :event_definitions
6
+
7
+ def initialize(attributes = {})
8
+ super(attributes.except(:message_event_definition, :signal_event_definition, :error_event_definition, :terminate_event_definition, :timer_event_definition))
9
+
10
+ @event_definitions = []
11
+
12
+ Array.wrap(attributes[:message_event_definition]).each do |med|
13
+ @event_definitions.push MessageEventDefinition.new(med)
14
+ end if attributes[:message_event_definition].present?
15
+
16
+ Array.wrap(attributes[:signal_event_definition]).each do |sed|
17
+ @event_definitions.push SignalEventDefinition.new(sed)
18
+ end if attributes[:signal_event_definition].present?
19
+
20
+ Array.wrap(attributes[:error_event_definition]).each do |eed|
21
+ @event_definitions.push ErrorEventDefinition.new(eed)
22
+ end if attributes[:error_event_definition].present?
23
+
24
+ Array.wrap(attributes[:terminate_event_definition]).each do |ted|
25
+ @event_definitions.push TerminateEventDefinition.new(ted)
26
+ end if attributes[:terminate_event_definition].present?
27
+
28
+ Array.wrap(attributes[:timer_event_definition]).each do |ted|
29
+ @event_definitions.push TimerEventDefinition.new(ted)
30
+ end if attributes[:timer_event_definition].present?
31
+ end
32
+
33
+ def event_definition_ids
34
+ event_definitions.map(&:id)
35
+ end
36
+
37
+ def is_catching?
38
+ false
39
+ end
40
+
41
+ def is_throwing?
42
+ false
43
+ end
44
+
45
+ def is_none?
46
+ event_definitions.empty?
47
+ end
48
+
49
+ def is_conditional?
50
+ conditional_event_definition.present?
51
+ end
52
+
53
+ def is_escalation?
54
+ escalation_event_definition.present?
55
+ end
56
+
57
+ def is_error?
58
+ error_event_definition.present?
59
+ end
60
+
61
+ def is_message?
62
+ !message_event_definitions.empty?
63
+ end
64
+
65
+ def is_signal?
66
+ !signal_event_definitions.empty?
67
+ end
68
+
69
+ def is_terminate?
70
+ terminate_event_definition.present?
71
+ end
72
+
73
+ def is_timer?
74
+ timer_event_definition.present?
75
+ end
76
+
77
+ def conditional_event_definition
78
+ event_definitions.find { |ed| ed.is_a?(ConditionalEventDefinition) }
79
+ end
80
+
81
+ def escalation_event_definition
82
+ event_definitions.find { |ed| ed.is_a?(EscalationEventDefinition) }
83
+ end
84
+
85
+ def error_event_definitions
86
+ event_definitions.select { |ed| ed.is_a?(ErrorEventDefinition) }
87
+ end
88
+
89
+ def error_event_definition
90
+ event_definitions.find { |ed| ed.is_a?(ErrorEventDefinition) }
91
+ end
92
+
93
+ def message_event_definitions
94
+ event_definitions.select { |ed| ed.is_a?(MessageEventDefinition) }
95
+ end
96
+
97
+ def signal_event_definitions
98
+ event_definitions.select { |ed| ed.is_a?(SignalEventDefinition) }
99
+ end
100
+
101
+ def terminate_event_definition
102
+ event_definitions.find { |ed| ed.is_a?(TerminateEventDefinition) }
103
+ end
104
+
105
+ def timer_event_definition
106
+ event_definitions.find { |ed| ed.is_a?(TimerEventDefinition) }
107
+ end
108
+
109
+ def execute(execution)
110
+ event_definitions.each { |event_definition| event_definition.execute(execution) }
111
+ end
112
+ end
113
+
114
+ class StartEvent < Event
115
+
116
+ def is_catching?
117
+ true
118
+ end
119
+
120
+ def execute(execution)
121
+ super
122
+ leave(execution)
123
+ end
124
+ end
125
+
126
+ class IntermediateThrowEvent < Event
127
+
128
+ def is_throwing?
129
+ true
130
+ end
131
+
132
+ def execute(execution)
133
+ super
134
+ leave(execution)
135
+ end
136
+ end
137
+
138
+ class IntermediateCatchEvent < Event
139
+
140
+ def is_catching?
141
+ true
142
+ end
143
+
144
+ def execute(execution)
145
+ super
146
+ execution.wait
147
+ end
148
+
149
+ def signal(execution)
150
+ leave(execution)
151
+ end
152
+ end
153
+
154
+ class BoundaryEvent < Event
155
+ attr_accessor :attached_to_ref, :attached_to, :cancel_activity
156
+
157
+ def initialize(attributes = {})
158
+ super(attributes.except(:attached_to_ref, :cancel_activity))
159
+
160
+ @attached_to_ref = attributes[:attached_to_ref]
161
+ @cancel_activity = true
162
+ if attributes[:cancel_activity].present?
163
+ @cancel_activity = attributes[:cancel_activity] == "false" ? false : true
164
+ end
165
+ end
166
+
167
+ def is_catching?
168
+ true
169
+ end
170
+
171
+ def execute(execution)
172
+ super
173
+ execution.wait
174
+ end
175
+
176
+ def signal(execution)
177
+ execution.attached_to.terminate if cancel_activity
178
+ leave(execution)
179
+ end
180
+ end
181
+
182
+ class EndEvent < Event
183
+
184
+ def is_throwing?
185
+ true
186
+ end
187
+
188
+ def execute(execution)
189
+ super
190
+ execution.end(true)
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BPMN
4
+ class EventDefinition < Element
5
+ def execute(execution)
6
+ end
7
+ end
8
+
9
+ class ConditionalEventDefinition < EventDefinition
10
+ attr_accessor :variable_name, :variable_events, :condition
11
+
12
+ def initialize(attributes = {})
13
+ super(attributes.except(:variable_name, :variable_events, :condition))
14
+
15
+ @variable_name = moddle[:variable_name] # "var1"
16
+ @variable_events = moddle[:variable_events] # "create, update"
17
+ @condition = moddle[:condition] # var1 = 1
18
+ end
19
+ end
20
+
21
+ class EscalationEventDefinition < EventDefinition
22
+ end
23
+
24
+ class ErrorEventDefinition < EventDefinition
25
+ attr_accessor :error_ref, :error
26
+ attr_accessor :error_code_variable, :error_message_variable
27
+
28
+ def initialize(attributes = {})
29
+ super(attributes.except(:error_ref, :error_code_variable, :error_message_variable))
30
+
31
+ @error_ref = attributes[:error_ref]
32
+ @error_code_variable = attributes[:error_code_variable]
33
+ @error_message_variable = attributes[:error_message_variable]
34
+ end
35
+
36
+ def execute(execution)
37
+ if execution.step.is_throwing?
38
+ execution.throw_error(error_name)
39
+ else
40
+ execution.error_names.push error_name
41
+ end
42
+ end
43
+
44
+ def error_id
45
+ error&.id
46
+ end
47
+
48
+ def error_name
49
+ error&.name
50
+ end
51
+ end
52
+
53
+ class MessageEventDefinition < EventDefinition
54
+ attr_accessor :message_ref, :message
55
+
56
+ def initialize(attributes = {})
57
+ super(attributes.except(:message_ref))
58
+
59
+ @message_ref = attributes[:message_ref]
60
+ end
61
+
62
+ def execute(execution)
63
+ if execution.step.is_throwing?
64
+ execution.throw_message(message_name)
65
+ else
66
+ execution.message_names.push message_name
67
+ end
68
+ end
69
+
70
+ def message_id
71
+ message&.id
72
+ end
73
+
74
+ def message_name
75
+ message&.name
76
+ end
77
+ end
78
+
79
+ class SignalEventDefinition < EventDefinition
80
+ attr_accessor :signal_ref, :signal
81
+
82
+ def initialize(attributes = {})
83
+ super(attributes.except(:signal_ref))
84
+
85
+ @signal_ref = moddle[:signal_ref]
86
+ end
87
+
88
+ def signal_id
89
+ signal&.id
90
+ end
91
+
92
+ def signal_name
93
+ signal&.name
94
+ end
95
+ end
96
+
97
+ class TerminateEventDefinition < EventDefinition
98
+
99
+ def execute(execution)
100
+ execution.parent&.terminate
101
+ end
102
+ end
103
+
104
+ class TimerEventDefinition < EventDefinition
105
+ attr_accessor :time_date, :time_duration_type, :time_duration, :time_cycle
106
+
107
+ def initialize(attributes = {})
108
+ super(attributes.except(:time_date, :time_duration, :time_cycle))
109
+
110
+ @time_duration_type = attributes[:time_duration_type]
111
+ @time_duration = attributes[:time_duration]
112
+ end
113
+
114
+ def execute(execution)
115
+ if execution.step.is_catching?
116
+ execution.timer_expires_at = time_due
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ def time_due
123
+ # Return the next time the timer is due
124
+ if time_date
125
+ return Date.parse(time_date)
126
+ elsif time_duration
127
+ return Time.zone.now + ActiveSupport::Duration.parse(time_duration)
128
+ else
129
+ return Time.zone.now # time_cycle not yet implemented
130
+ end
131
+ end
132
+ end
133
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module SpotFlow
3
+ module BPMN
4
4
  class Execution
5
5
  attr_accessor :id, :status, :started_at, :ended_at, :variables, :tokens_in, :tokens_out, :start_event_id, :timer_expires_at, :message_names, :error_names, :condition
6
6
  attr_accessor :step, :parent, :children, :context, :attached_to_id
@@ -97,7 +97,7 @@ module SpotFlow
97
97
  @started_at = Time.zone.now
98
98
  map_input_variables if step&.input_mappings&.present?
99
99
  context.notify_listener(:execution_started, execution: self)
100
- step.attachments.each { |attachment| parent.execute_step(attachment, attached_to: self) } if step.is_a?(SpotFlow::Bpmn::Activity)
100
+ step.attachments.each { |attachment| parent.execute_step(attachment, attached_to: self) } if step.is_a?(BPMN::Activity)
101
101
  continue
102
102
  end
103
103
 
@@ -147,7 +147,7 @@ module SpotFlow
147
147
  def throw_message(message_name, variables: {})
148
148
  waiting_children.each do |child|
149
149
  step = child.step
150
- if step.is_a?(SpotFlow::Bpmn::Event) && step.message_event_definitions.any? { |message_event_definition| message_event_definition.message_name == message_name }
150
+ if step.is_a?(BPMN::Event) && step.message_event_definitions.any? { |message_event_definition| message_event_definition.message_name == message_name }
151
151
  child.signal(variables)
152
152
  break
153
153
  end
@@ -158,7 +158,7 @@ module SpotFlow
158
158
  def throw_error(error_name, variables: {})
159
159
  waiting_children.each do |child|
160
160
  step = child.step
161
- if step.is_a?(SpotFlow::Bpmn::Event) && step.error_event_definitions.any? { |error_event_definition| error_event_definition.error_name == error_name }
161
+ if step.is_a?(BPMN::Event) && step.error_event_definitions.any? { |error_event_definition| error_event_definition.error_name == error_name }
162
162
  child.signal(variables)
163
163
  break
164
164
  end
@@ -175,7 +175,7 @@ module SpotFlow
175
175
  end
176
176
 
177
177
  def evaluate_expression(expression, variables: parent&.variables || {}.with_indifferent_access)
178
- SpotFeel.evaluate(expression.delete_prefix("="), variables:)
178
+ DMN.evaluate(expression.delete_prefix("="), variables:)
179
179
  end
180
180
 
181
181
  def run_automated_tasks
@@ -202,7 +202,7 @@ module SpotFlow
202
202
  # Called by the child step executors when they have ended
203
203
  #
204
204
  def has_ended(_child)
205
- step.leave(self) if step.is_a?(SpotFlow::Bpmn::SubProcess) || step.is_a?(SpotFlow::Bpmn::CallActivity)
205
+ step.leave(self) if step.is_a?(BPMN::SubProcess) || step.is_a?(BPMN::CallActivity)
206
206
  self.end(true)
207
207
  end
208
208
 
@@ -219,7 +219,7 @@ module SpotFlow
219
219
  end
220
220
 
221
221
  def waiting_tasks
222
- waiting_children.select { |child| child.step.is_a?(SpotFlow::Bpmn::Task) }
222
+ waiting_children.select { |child| child.step.is_a?(BPMN::Task) }
223
223
  end
224
224
 
225
225
  def waiting_automated_tasks
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BPMN
4
+ class ExtensionElements
5
+ VALID_EXTENSION_NAMESPACES = %w[zeebe]
6
+
7
+ attr_accessor :assignment_definition, :called_element, :called_decision, :form_definition, :io_mapping, :properties, :script, :subscription, :task_definition, :task_headers, :task_schedule
8
+
9
+ def initialize(attributes = {})
10
+ if attributes[:properties].present?
11
+ @properties = HashWithIndifferentAccess.new
12
+ Array.wrap(attributes[:properties][:property]).each { |property_moddle| @properties[property_moddle[:name]] = property_moddle[:value] }
13
+ end
14
+
15
+ @assignment_definition = Zeebe::AssignmentDefinition.new(attributes[:assignment_definition]) if attributes[:assignment_definition].present?
16
+ @called_element = Zeebe::CalledElement.new(attributes[:called_element]) if attributes[:called_element].present?
17
+ @called_decision = Zeebe::CalledDecision.new(attributes[:called_decision]) if attributes[:called_decision].present?
18
+ @form_definition = Zeebe::FormDefinition.new(attributes[:form_definition]) if attributes[:form_definition].present?
19
+ @io_mapping = Zeebe::IoMapping.new(attributes[:io_mapping]) if attributes[:io_mapping].present?
20
+ @script = Zeebe::Script.new(attributes[:script]) if attributes[:script].present?
21
+ @subscription = Zeebe::Subscription.new(attributes[:subscription]) if attributes[:subscription].present?
22
+ @task_definition = Zeebe::TaskDefinition.new(attributes[:task_definition]) if attributes[:task_definition].present?
23
+ @task_headers = Zeebe::TaskHeaders.new(attributes[:task_headers]) if attributes[:task_headers].present?
24
+ @task_schedule = Zeebe::TaskSchedule.new(attributes[:task_schedule]) if attributes[:task_schedule].present?
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BPMN
4
+ class Extension
5
+ include ActiveModel::Model
6
+ end
7
+ end
8
+
9
+ module Zeebe
10
+ class AssignmentDefinition < BPMN::Extension
11
+ attr_accessor :assignee, :candidate_groups, :candidate_users
12
+ end
13
+
14
+ class CalledElement < BPMN::Extension
15
+ attr_accessor :process_id, :propagate_all_child_variables, :propagate_all_parent_variables
16
+
17
+ def initialize(attributes = {})
18
+ super(attributes.except(:propagate_all_child_variables))
19
+
20
+ @propagate_all_parent_variables = true
21
+ @propagate_all_parent_variables = attributes[:propagate_all_parent_variables] == "true" if attributes[:propagate_all_parent_variables].present?
22
+ @propagate_all_child_variables = attributes[:propagate_all_child_variables] == "true"
23
+ end
24
+ end
25
+
26
+ class CalledDecision < BPMN::Extension
27
+ attr_accessor :decision_id, :result_variable
28
+ end
29
+
30
+ class FormDefinition < BPMN::Extension
31
+ attr_accessor :form_key
32
+ end
33
+
34
+ class IoMapping < BPMN::Extension
35
+ attr_reader :inputs, :outputs
36
+
37
+ def initialize(attributes = {})
38
+ super(attributes.except(:input, :output))
39
+
40
+ @inputs = Array.wrap(attributes[:input]).map { |atts| Parameter.new(atts) } if attributes[:input].present?
41
+ @outputs = Array.wrap(attributes[:output]).map { |atts| Parameter.new(atts) } if attributes[:output].present?
42
+ end
43
+ end
44
+
45
+ class Parameter < BPMN::Extension
46
+ attr_accessor :source, :target
47
+ end
48
+
49
+ class Script < BPMN::Extension
50
+ attr_accessor :expression, :result_variable
51
+ end
52
+
53
+ class Subscription < BPMN::Extension
54
+ attr_accessor :correlation_key
55
+ end
56
+
57
+ class TaskDefinition < BPMN::Extension
58
+ attr_accessor :type, :retries
59
+ end
60
+
61
+ class TaskHeaders < BPMN::Extension
62
+ attr_accessor :headers
63
+
64
+ def initialize(attributes = {})
65
+ super(attributes.except(:header))
66
+
67
+ @headers = HashWithIndifferentAccess.new
68
+ Array.wrap(attributes[:header]).each { |header| @headers[header[:key]] = header[:value] }
69
+ end
70
+ end
71
+
72
+ class TaskSchedule < BPMN::Extension
73
+ attr_accessor :due_date, :follow_up_date
74
+ end
75
+ end