bpmn 0.3.1 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eec917ee2aadb5fcfb00c0320545531d3f0c8fa7a71d792bd0f2c3b98f11f6ea
4
- data.tar.gz: 4cbade6e2c6abe6d0409c038072edbdf3ecbecf6273aa9ca62748982dcc20d66
3
+ metadata.gz: 570a8c61fe26fb937180699bec4ba9f2bb8d4232aea10647249c18cafbcd6b73
4
+ data.tar.gz: a2660ffe0e2ecab73c2941c5398748204e61fb3df81a6768c2490a46303d130b
5
5
  SHA512:
6
- metadata.gz: 624a13c93bfc3ab6e8e20709b48a6c11c7c7b19c352bd1cbed245175de6de1fb5a52a4b03b2969978bcd4259ef11e0318c45860130e9386ad889211b282bf327
7
- data.tar.gz: a1db62cb116e4829b5ef4d2dd7cdd3c28de6e257c677fadfacc4f59ff5e9a22393ec4d9e587775fbd8c97e5bea079894d789b1530314345524000ef6c052cebd
6
+ metadata.gz: 453bf5fa1b709c5929d2fa11484aaf20d8bbf386824b0cdad9b8b2344b3e4e37607f4db119fc116ac0505c05576ca6398207803785ca068272524be82a977a5d
7
+ data.tar.gz: 1cc2dd3f4b066713b16eac9c998b910c75ddbfa5f54bc6b459943bb0bfd5794e9a50e0774078daa3e59967c1d4a256cf978b0638172d3dce128509d1aa3f2a8a
@@ -5,7 +5,7 @@ module BPMN
5
5
  include ActiveModel::Model
6
6
 
7
7
  attr_accessor :id, :name, :target_namespace, :exporter, :exporter_version, :execution_platform, :execution_platform_version
8
- attr_reader :messages, :signals, :errors, :processes
8
+ attr_reader :messages, :signals, :errors, :escalations, :processes
9
9
 
10
10
  def self.from_xml(xml)
11
11
  XmlHasher.configure do |config|
@@ -22,11 +22,12 @@ module BPMN
22
22
  end
23
23
 
24
24
  def initialize(attributes={})
25
- super(attributes.except(:message, :signal, :error, :process))
25
+ super(attributes.except(:message, :signal, :error, :escalation, :process))
26
26
 
27
27
  @messages = Array.wrap(attributes[:message]).map { |atts| Message.new(atts) }
28
28
  @signals = Array.wrap(attributes[:signal]).map { |atts| Signal.new(atts) }
29
29
  @errors = Array.wrap(attributes[:error]).map { |atts| Error.new(atts) }
30
+ @escalations = Array.wrap(attributes[:escalation]).map { |atts| Escalation.new(atts) }
30
31
  @processes = Array.wrap(attributes[:process]).map { |atts| Process.new(atts) }
31
32
  end
32
33
 
@@ -42,12 +43,16 @@ module BPMN
42
43
  errors.find { |error| error.id == id }
43
44
  end
44
45
 
46
+ def escalation_by_id(id)
47
+ escalations.find { |escalation| escalation.id == id }
48
+ end
49
+
45
50
  def process_by_id(id)
46
51
  processes.find { |process| process.id == id }
47
52
  end
48
53
 
49
54
  def inspect
50
- "#<BPMN::Definitions @id=#{id.inspect} @name=#{name.inspect} @messages=#{messages.inspect} @signals=#{signals.inspect} @errors=#{errors.inspect} @processes=#{processes.inspect}>"
55
+ "#<BPMN::Definitions @id=#{id.inspect} @name=#{name.inspect} @messages=#{messages.inspect} @signals=#{signals.inspect} @errors=#{errors.inspect} @escalations=#{escalations.inspect} @processes=#{processes.inspect}>"
51
56
  end
52
57
  end
53
58
  end
data/lib/bpmn/element.rb CHANGED
@@ -26,6 +26,9 @@ module BPMN
26
26
  class Error < Element
27
27
  end
28
28
 
29
+ class Escalation < Element
30
+ end
31
+
29
32
  class Collaboration < Element
30
33
  end
31
34
 
data/lib/bpmn/event.rb CHANGED
@@ -5,7 +5,7 @@ module BPMN
5
5
  attr_accessor :event_definitions
6
6
 
7
7
  def initialize(attributes = {})
8
- super(attributes.except(:message_event_definition, :signal_event_definition, :error_event_definition, :terminate_event_definition, :timer_event_definition))
8
+ super(attributes.except(:message_event_definition, :signal_event_definition, :error_event_definition, :escalation_event_definition, :terminate_event_definition, :timer_event_definition))
9
9
 
10
10
  @event_definitions = []
11
11
 
@@ -21,6 +21,10 @@ module BPMN
21
21
  @event_definitions.push ErrorEventDefinition.new(eed)
22
22
  end if attributes[:error_event_definition].present?
23
23
 
24
+ Array.wrap(attributes[:escalation_event_definition]).each do |esed|
25
+ @event_definitions.push EscalationEventDefinition.new(esed)
26
+ end if attributes[:escalation_event_definition].present?
27
+
24
28
  Array.wrap(attributes[:terminate_event_definition]).each do |ted|
25
29
  @event_definitions.push TerminateEventDefinition.new(ted)
26
30
  end if attributes[:terminate_event_definition].present?
@@ -82,6 +86,10 @@ module BPMN
82
86
  event_definitions.find { |ed| ed.is_a?(EscalationEventDefinition) }
83
87
  end
84
88
 
89
+ def escalation_event_definitions
90
+ event_definitions.select { |ed| ed.is_a?(EscalationEventDefinition) }
91
+ end
92
+
85
93
  def error_event_definitions
86
94
  event_definitions.select { |ed| ed.is_a?(ErrorEventDefinition) }
87
95
  end
@@ -19,6 +19,29 @@ module BPMN
19
19
  end
20
20
 
21
21
  class EscalationEventDefinition < EventDefinition
22
+ attr_accessor :escalation_ref, :escalation
23
+
24
+ def initialize(attributes = {})
25
+ super(attributes.except(:escalation_ref))
26
+
27
+ @escalation_ref = attributes[:escalation_ref]
28
+ end
29
+
30
+ def execute(execution)
31
+ if execution.step.is_throwing?
32
+ execution.throw_escalation(escalation_name)
33
+ else
34
+ execution.escalation_names.push escalation_name
35
+ end
36
+ end
37
+
38
+ def escalation_id
39
+ escalation&.id
40
+ end
41
+
42
+ def escalation_name
43
+ escalation&.name
44
+ end
22
45
  end
23
46
 
24
47
  class ErrorEventDefinition < EventDefinition
@@ -2,7 +2,7 @@
2
2
 
3
3
  module BPMN
4
4
  class Execution
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
5
+ attr_accessor :id, :status, :started_at, :ended_at, :variables, :tokens_in, :tokens_out, :start_event_id, :timer_expires_at, :message_names, :error_names, :escalation_names, :condition
6
6
  attr_accessor :step, :parent, :children, :context, :attached_to_id
7
7
 
8
8
  delegate :print, to: :printer
@@ -50,6 +50,7 @@ module BPMN
50
50
  @tokens_out ||= []
51
51
  @message_names ||= []
52
52
  @error_names ||= []
53
+ @escalation_names ||= []
53
54
  @children ||= []
54
55
  end
55
56
 
@@ -166,16 +167,59 @@ module BPMN
166
167
  context.notify_listener(:error_thrown, execution: self, error_name: error_name)
167
168
  end
168
169
 
170
+ def throw_escalation(escalation_name, variables: {})
171
+ caught = false
172
+ waiting_children.each do |child|
173
+ step = child.step
174
+ if step.is_a?(BPMN::Event) && step.escalation_event_definitions.any? { |eed| eed.escalation_name == escalation_name }
175
+ child.signal(variables)
176
+ caught = true
177
+ break
178
+ end
179
+ end
180
+ unless caught
181
+ waiting_children.each do |child|
182
+ step = child.step
183
+ if step.is_a?(BPMN::Event) && step.escalation_event_definitions.any? { |eed| eed.escalation_name.nil? }
184
+ child.signal(variables)
185
+ break
186
+ end
187
+ end
188
+ end
189
+ context.notify_listener(:escalation_thrown, execution: self, escalation_name: escalation_name)
190
+ end
191
+
192
+ def timer_expired?
193
+ waiting? && timer_expires_at.present? && Time.zone.now > timer_expires_at
194
+ end
195
+
169
196
  def check_expired_timers
170
- waiting_children.each { |child| child.signal if child.timer_expires_at.present? && Time.zone.now > child.timer_expires_at }
197
+ if timer_expired?
198
+ signal
199
+ else
200
+ children.each { |child| child.check_expired_timers }
201
+ end
202
+ end
203
+
204
+ def next_timer_expires_at
205
+ times = []
206
+ times << timer_expires_at if waiting? && timer_expires_at
207
+ children.each { |child| child_time = child.next_timer_expires_at; times << child_time if child_time }
208
+ times.min
171
209
  end
172
210
 
173
211
  def evaluate_condition(condition)
174
- evaluate_expression(condition.delete_prefix("=")) == true
212
+ evaluate_expression(condition) == true
175
213
  end
176
214
 
177
215
  def evaluate_expression(expression, variables: parent&.variables || {}.with_indifferent_access)
178
- DMN.evaluate(expression.delete_prefix("="), variables: variables)
216
+ return nil if expression.nil?
217
+
218
+ if expression.start_with?("=")
219
+ DMN.evaluate(expression.delete_prefix("="), variables: variables)
220
+ else
221
+ expression
222
+ end
179
223
  end
180
224
 
181
225
  def run_automated_tasks
@@ -257,6 +301,7 @@ module BPMN
257
301
  tokens_out: tokens_out,
258
302
  message_names: message_names,
259
303
  error_names: error_names,
304
+ escalation_names: escalation_names,
260
305
  timer_expires_at: timer_expires_at,
261
306
  condition: condition,
262
307
  children: children.map { |child| child.as_json },
@@ -276,6 +321,7 @@ module BPMN
276
321
  # parts << "@tokens_out=#{tokens_out.inspect}" if tokens_out.present?
277
322
  parts << "@message_names=#{message_names.inspect}" if message_names.present?
278
323
  parts << "@error_names=#{error_names.inspect}" if error_names.present?
324
+ parts << "@escalation_names=#{escalation_names.inspect}" if escalation_names.present?
279
325
  parts << "@timer_expires_at=#{timer_expires_at.inspect}" if timer_expires_at
280
326
  parts << "@condition=#{condition.inspect}" if condition
281
327
  parts << "@children=#{children.inspect}" if children.present?
data/lib/bpmn/process.rb CHANGED
@@ -76,6 +76,8 @@ module BPMN
76
76
  event_definition.signal = definitions.signal_by_id(event_definition.signal_ref)
77
77
  elsif event_definition.is_a?(ErrorEventDefinition)
78
78
  event_definition.error = definitions.error_by_id(event_definition.error_ref)
79
+ elsif event_definition.is_a?(EscalationEventDefinition)
80
+ event_definition.escalation = definitions.escalation_by_id(event_definition.escalation_ref)
79
81
  end
80
82
  end
81
83
 
@@ -162,11 +164,10 @@ module BPMN
162
164
  attr_reader :process_id
163
165
 
164
166
  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
167
+ @process_id = execution.evaluate_expression(
168
+ extension_elements&.called_element&.process_id,
169
+ variables: execution.variables
170
+ )
170
171
 
171
172
  execution.wait
172
173
 
data/lib/bpmn/task.rb CHANGED
@@ -105,7 +105,7 @@ module BPMN
105
105
  end
106
106
 
107
107
  def run(execution)
108
- DMN.evaluate(script.delete_prefix("="), variables: execution.parent.variables)
108
+ execution.parent.evaluate_expression(script, variables: execution.parent.variables)
109
109
  end
110
110
  end
111
111
 
data/lib/bpmn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BPMN
4
- VERSION = "0.3.1"
4
+ VERSION = "0.4.0"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bpmn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Connected Bits
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-02-06 00:00:00.000000000 Z
10
+ date: 2026-03-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: dmn
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 0.3.0
18
+ version: 0.4.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 0.3.0
25
+ version: 0.4.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activemodel
28
28
  requirement: !ruby/object:Gem::Requirement