openwferu 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/README.txt +4 -5
  2. data/lib/openwfe/engine/engine.rb +14 -14
  3. data/lib/openwfe/expool/expressionpool.rb +60 -45
  4. data/lib/openwfe/expool/expstorage.rb +1 -1
  5. data/lib/openwfe/expressions/condition.rb +47 -34
  6. data/lib/openwfe/expressions/environment.rb +29 -7
  7. data/lib/openwfe/expressions/expressionmap.rb +16 -1
  8. data/lib/openwfe/expressions/fe_concurrence.rb +142 -55
  9. data/lib/openwfe/expressions/fe_cursor.rb +146 -41
  10. data/lib/openwfe/expressions/fe_define.rb +52 -35
  11. data/lib/openwfe/expressions/fe_filter.rb +129 -0
  12. data/lib/openwfe/expressions/fe_filter_definition.rb +170 -0
  13. data/lib/openwfe/expressions/fe_iterator.rb +23 -10
  14. data/lib/openwfe/expressions/fe_losfor.rb +7 -6
  15. data/lib/openwfe/expressions/fe_participant.rb +19 -9
  16. data/lib/openwfe/expressions/fe_raw.rb +11 -16
  17. data/lib/openwfe/expressions/fe_save.rb +225 -0
  18. data/lib/openwfe/expressions/fe_sequence.rb +15 -10
  19. data/lib/openwfe/expressions/fe_subprocess.rb +0 -6
  20. data/lib/openwfe/expressions/fe_value.rb +7 -19
  21. data/lib/openwfe/expressions/filter.rb +104 -0
  22. data/lib/openwfe/expressions/flowexpression.rb +102 -36
  23. data/lib/openwfe/expressions/merge.rb +80 -0
  24. data/lib/openwfe/expressions/raw_prog.rb +21 -18
  25. data/lib/openwfe/filterdef.rb +259 -0
  26. data/lib/openwfe/flowexpressionid.rb +36 -3
  27. data/lib/openwfe/participants/participants.rb +7 -1
  28. data/lib/openwfe/rest/xmlcodec.rb +1 -1
  29. data/lib/openwfe/util/dollar.rb +4 -2
  30. data/lib/openwfe/util/scheduler.rb +3 -1
  31. data/lib/openwfe/util/sqs.rb +1 -2
  32. data/lib/openwfe/utils.rb +13 -0
  33. data/lib/openwfe/version.rb +1 -1
  34. data/lib/openwfe/workitem.rb +1 -1
  35. data/test/filter_test.rb +109 -0
  36. data/test/flowtestbase.rb +12 -1
  37. data/test/ft_11_ppd.rb +13 -1
  38. data/test/ft_11b_ppd.rb +45 -0
  39. data/test/ft_17_condition.rb +1 -1
  40. data/test/ft_2b_concurrence.rb +24 -0
  41. data/test/ft_2c_concurrence.rb +22 -1
  42. data/test/ft_3_equals.rb +26 -0
  43. data/test/ft_42_environments.rb +78 -0
  44. data/test/ft_43_pat10.rb +109 -0
  45. data/test/ft_44_save.rb +81 -0
  46. data/test/ft_44b_restore.rb +159 -0
  47. data/test/ft_45_citerator.rb +104 -0
  48. data/test/ft_46_pparams.rb +62 -0
  49. data/test/ft_47_filter.rb +165 -0
  50. data/test/ft_48_fe_filter.rb +91 -0
  51. data/test/ft_49_condition.rb +65 -0
  52. data/test/ft_50_xml_attribute.rb +89 -0
  53. data/test/ft_9_cursor.rb +36 -6
  54. data/test/ft_tests.rb +11 -1
  55. data/test/misc_test.rb +8 -0
  56. data/test/rake_qtest.rb +2 -2
  57. data/test/rutest_utils.rb +6 -1
  58. data/test/sec_test.rb +2 -2
  59. metadata +20 -2
@@ -59,9 +59,9 @@ module OpenWFE
59
59
  :variables
60
60
 
61
61
  def initialize \
62
- (id, parent, environment_id, application_context, attributes)
62
+ (fei, parent, environment_id, application_context, attributes)
63
63
 
64
- super(id, parent, environment_id, application_context, attributes)
64
+ super(fei, parent, environment_id, application_context, attributes)
65
65
 
66
66
  @variables = {}
67
67
  end
@@ -147,14 +147,36 @@ module OpenWFE
147
147
  end
148
148
 
149
149
  #
150
- # Returns the top environment for the process instance.
150
+ # Returns the top environment for the process instance (the
151
+ # environment just before the engine environment).
151
152
  #
152
- def get_root_environment ()
153
+ def get_root_environment
154
+ #ldebug { "get_root_environment\n#{self}" }
155
+ return self if not @parent_id
156
+ get_parent.get_root_environment
157
+ end
153
158
 
154
- #ldebug { "get_root_environment()\n#{self}" }
159
+ #def get_subprocess_environment
160
+ # return self if not @parent_id
161
+ # return self if @parent_id.sub_instance_id != @fei.sub_instance_id
162
+ # get_parent.get_subprocess_environment
163
+ #end
155
164
 
156
- return self if not @parent_id
157
- return get_parent().get_root_environment()
165
+ #
166
+ # Returns a deep copy of this environment.
167
+ #
168
+ def dup
169
+
170
+ env = Environment.new(
171
+ @fei.dup,
172
+ @parent_id,
173
+ @environment_id,
174
+ @application_context,
175
+ OpenWFE::fulldup(@attributes))
176
+
177
+ env.variables = OpenWFE::fulldup self.variables
178
+
179
+ env
158
180
  end
159
181
  end
160
182
 
@@ -60,6 +60,9 @@ require 'openwfe/expressions/fe_iterator'
60
60
  require 'openwfe/expressions/fe_fqv'
61
61
  require 'openwfe/expressions/fe_cancel'
62
62
  require 'openwfe/expressions/fe_do'
63
+ require 'openwfe/expressions/fe_save'
64
+ require 'openwfe/expressions/fe_filter_definition'
65
+ require 'openwfe/expressions/fe_filter'
63
66
 
64
67
 
65
68
  module OpenWFE
@@ -84,6 +87,8 @@ module OpenWFE
84
87
  register ConcurrenceExpression
85
88
  register GenericSyncExpression
86
89
 
90
+ register ConcurrentIteratorExpression
91
+
87
92
  register SubProcessRefExpression
88
93
 
89
94
  register SetValueExpression
@@ -123,6 +128,12 @@ module OpenWFE
123
128
  register UndoExpression
124
129
  register RedoExpression
125
130
 
131
+ register SaveWorkItemExpression
132
+ register RestoreWorkItemExpression
133
+
134
+ register FilterDefinitionExpression
135
+ register FilterExpression
136
+
126
137
  register Environment
127
138
  #
128
139
  # only used by get_expression_names()
@@ -134,6 +145,9 @@ module OpenWFE
134
145
  #
135
146
  def get_class (expression_name)
136
147
 
148
+ expression_name = expression_name.expression_name \
149
+ if expression_name.kind_of?(RawExpression)
150
+
137
151
  expression_name = OpenWFE::symbol_to_name(expression_name)
138
152
 
139
153
  @expressions[expression_name]
@@ -152,7 +166,8 @@ module OpenWFE
152
166
 
153
167
  c = get_class(expression_name)
154
168
 
155
- c == DefineExpression
169
+ #c == DefineExpression
170
+ (c and c.is_definition?)
156
171
  end
157
172
 
158
173
  #
@@ -41,8 +41,10 @@
41
41
 
42
42
  require 'openwfe/utils'
43
43
  require 'openwfe/rudefinitions'
44
+ require 'openwfe/expressions/merge'
44
45
  require 'openwfe/expressions/condition'
45
46
  require 'openwfe/expressions/flowexpression'
47
+ require 'openwfe/expressions/fe_iterator'
46
48
 
47
49
 
48
50
  #
@@ -120,12 +122,16 @@ module OpenWFE
120
122
  # [override] The default : no mix of values between the workitems do occur
121
123
  # [mix] Priority is given to the 'winning' workitem but their values
122
124
  # get mixed
125
+ # [isolate] the attributes of the workitem of each branch is placed
126
+ # in a field in the resulting workitem. For example, the
127
+ # attributes of the first branch will be stored under the
128
+ # field named '0' of the resulting workitem.
123
129
  #
124
130
  # The merge occurs are the top level of workitem attributes.
125
131
  #
126
132
  # More complex merge behaviour can be obtained by extending the
127
133
  # GenericSyncExpression class. But the default sync options are already
128
- # numerous and powerful.
134
+ # numerous and powerful by their combinations.
129
135
  #
130
136
  class ConcurrenceExpression < SequenceExpression
131
137
  include ConditionMixin
@@ -139,8 +145,8 @@ module OpenWFE
139
145
 
140
146
  sync = lookup_attribute(:sync, workitem, :generic)
141
147
 
142
- @sync_expression = \
143
- get_expression_map().get_sync_class(sync).new(self, workitem)
148
+ @sync_expression =
149
+ get_expression_map.get_sync_class(sync).new(self, workitem)
144
150
 
145
151
  @children.each do |child|
146
152
  @sync_expression.add_child(child)
@@ -150,12 +156,16 @@ module OpenWFE
150
156
 
151
157
  concurrence = self
152
158
 
153
- @children.each do |child|
159
+ @children.each_with_index do |child, index|
154
160
  Thread.new do
155
161
  begin
156
162
  #ldebug { "apply() child : #{child.to_debug_s}" }
157
163
  concurrence.synchronize do
158
- get_expression_pool().apply(child, workitem.dup)
164
+
165
+ get_expression_pool().apply(
166
+ child,
167
+ #workitem.dup)
168
+ get_workitem(workitem, index))
159
169
  end
160
170
  rescue Exception => e
161
171
  lwarn do
@@ -186,6 +196,66 @@ module OpenWFE
186
196
  def reply (workitem)
187
197
  @sync_expression.reply(self, workitem)
188
198
  end
199
+
200
+ protected
201
+
202
+ def get_workitem (workitem, index)
203
+ workitem.dup
204
+ end
205
+ end
206
+
207
+ #
208
+ # This expression is a mix between a 'concurrence' and an 'iterator'.
209
+ # It understands the same attributes and behaves as an interator that
210
+ # forks its children concurrently.
211
+ #
212
+ # (See ConcurrenceExpression and IteratorExpression).
213
+ #
214
+ class ConcurrentIteratorExpression < ConcurrenceExpression
215
+
216
+ names :concurrent_iterator
217
+
218
+ #attr_accessor :iterator
219
+
220
+ def apply (workitem)
221
+
222
+ if @children.length < 1
223
+ reply_to_parent workitem
224
+ return
225
+ end
226
+
227
+ template = @children[0]
228
+
229
+ @children.clear
230
+
231
+ @workitems = []
232
+
233
+ iterator = Iterator.new(self, workitem)
234
+
235
+ while iterator.has_next?
236
+
237
+ wi = workitem.dup
238
+
239
+ @workitems << wi
240
+
241
+ vars = iterator.next self, wi
242
+
243
+ rawexp = get_expression_pool.prepare_from_template(
244
+ self, iterator.index, template, vars)
245
+
246
+ @children << rawexp.fei
247
+ end
248
+
249
+ get_expression_pool.remove(template)
250
+
251
+ super
252
+ end
253
+
254
+ protected
255
+
256
+ def get_workitem (workitem, index)
257
+ @workitems[index]
258
+ end
189
259
  end
190
260
 
191
261
  #
@@ -236,6 +306,8 @@ module OpenWFE
236
306
  merge = synchable.lookup_attribute(:merge, workitem, :first)
237
307
  merge_type = synchable.lookup_attribute(:merge_type, workitem, :mix)
238
308
 
309
+ #synchable.ldebug { "new() merge_type is '#{merge_type}'" }
310
+
239
311
  @merge_array = MergeArray.new(merge, merge_type)
240
312
 
241
313
  @unready_queue = []
@@ -297,7 +369,7 @@ module OpenWFE
297
369
  def do_reply (synchable, workitem)
298
370
 
299
371
  synchable.ldebug do
300
- "#{self.class}.do_reply() "+
372
+ "#{self.class}.do_reply() from"+
301
373
  "#{workitem.last_expression_id.to_debug_s}"
302
374
  end
303
375
 
@@ -307,6 +379,11 @@ module OpenWFE
307
379
 
308
380
  @remaining_children.delete(workitem.last_expression_id)
309
381
 
382
+ #synchable.ldebug do
383
+ # "#{self.class}.do_reply() "+
384
+ # "remaining children : #{@remaining_children.length}"
385
+ #end
386
+
310
387
  if @remaining_children.length <= 0
311
388
  reply_to_parent(synchable)
312
389
  return true
@@ -364,8 +441,7 @@ module OpenWFE
364
441
  if @cancel_remaining
365
442
  expool.cancel(child)
366
443
  else
367
- #expool.remove(child)
368
- expool.forget(child)
444
+ expool.forget(synchable, child)
369
445
  end
370
446
  end
371
447
  end
@@ -388,11 +464,13 @@ module OpenWFE
388
464
  end
389
465
 
390
466
  #
391
- # This inner class is used to gather workitems before the final
392
- # merge, which is triggered by calling the do_merge() method
393
- # which returns the merged workitem.
467
+ # This inner class is used to gather workitems (via push()) before
468
+ # the final merge
469
+ # This final merge is triggered by calling the do_merge() method
470
+ # which will return the resulting, merged workitem.
394
471
  #
395
472
  class MergeArray
473
+ include MergeMixin
396
474
 
397
475
  attr_accessor \
398
476
  :workitem,
@@ -403,8 +481,8 @@ module OpenWFE
403
481
 
404
482
  def initialize (merge, merge_type)
405
483
 
406
- @merge = merge.downcase
407
- @merge_type = merge_type.downcase
484
+ @merge = merge.strip.downcase.intern
485
+ @merge_type = merge_type.strip.downcase.intern
408
486
 
409
487
  ensure_merge_settings()
410
488
 
@@ -418,22 +496,48 @@ module OpenWFE
418
496
 
419
497
  def push (synchable, wi)
420
498
 
421
- if not @workitems_by_arrival
422
- #
423
- # last or first
424
- #
425
- source, target = if first?
426
- [ @workitem, wi ]
427
- else
428
- [ wi, @workitem ]
429
- end
430
- @workitem = merge(target, source)
499
+ #synchable.ldebug do
500
+ # "push() isolate? #{isolate?}"
501
+ #end
431
502
 
432
- return
503
+ if isolate?
504
+ push_in_isolation wi
505
+ elsif last? or first?
506
+ push_by_position wi
507
+ else
508
+ push_by_arrival wi
433
509
  end
510
+ end
511
+
512
+ def push_by_position (wi)
513
+
514
+ source, target = if first?
515
+ [ @workitem, wi ]
516
+ else
517
+ [ wi, @workitem ]
518
+ end
519
+ @workitem = merge_workitems target, source, override?
520
+ end
434
521
 
435
- index = synchable.children.index(
436
- wi.last_expression_id)
522
+ def push_in_isolation (wi)
523
+
524
+ unless @workitem
525
+ @workitem = wi.dup
526
+ att = @workitem.attributes
527
+ @workitem.attributes = {}
528
+ end
529
+
530
+ #key = synchable.children.index wi.last_expression_id
531
+ key = wi.last_expression_id.child_id
532
+
533
+ @workitem.attributes[key.to_s] =
534
+ OpenWFE::fulldup(wi.attributes)
535
+ end
536
+
537
+ def push_by_arrival (wi)
538
+
539
+ #index = synchable.children.index wi.last_expression_id
540
+ index = Integer(wi.last_expression_id.child_id)
437
541
 
438
542
  @workitems_by_arrival << wi
439
543
  @workitems_by_altitude[index] = wi
@@ -460,7 +564,7 @@ module OpenWFE
460
564
 
461
565
  list.each do |wi|
462
566
  next unless wi
463
- result = merge(result, wi)
567
+ result = merge_workitems result, wi, override?
464
568
  end
465
569
 
466
570
  #puts "___ result :"
@@ -473,23 +577,26 @@ module OpenWFE
473
577
  protected
474
578
 
475
579
  def first?
476
- @merge == "first"
580
+ @merge == :first
477
581
  end
478
582
  def last?
479
- @merge == "last"
583
+ @merge == :last
480
584
  end
481
585
  def highest?
482
- @merge == "highest"
586
+ @merge == :highest
483
587
  end
484
588
  def lowest?
485
- @merge == "lowest"
589
+ @merge == :lowest
486
590
  end
487
591
 
488
592
  def mix?
489
- @merge_type == "mix"
593
+ @merge_type == :mix
490
594
  end
491
595
  def override?
492
- @merge_type == "override"
596
+ @merge_type == :override
597
+ end
598
+ def isolate?
599
+ @merge_type == :isolate
493
600
  end
494
601
 
495
602
  #
@@ -498,28 +605,8 @@ module OpenWFE
498
605
  #
499
606
  def ensure_merge_settings
500
607
 
501
- @merge_type = "mix" unless override?
502
- @merge = "first" unless last? or highest? or lowest?
503
- end
504
-
505
- def merge (wiTarget, wiSource)
506
-
507
- return wiSource unless wiTarget
508
- return wiTarget unless wiSource
509
-
510
- return wiSource if override?
511
-
512
- wiSource.attributes.each do |k, v|
513
-
514
- #puts "merge() '#{k}' => '#{v}'"
515
-
516
- nk = OpenWFE::fulldup(k)
517
- nv = OpenWFE::fulldup(v)
518
-
519
- wiTarget.attributes[nk] = nv
520
- end
521
-
522
- wiTarget
608
+ @merge_type = :mix unless override? or isolate?
609
+ @merge = :first unless last? or highest? or lowest?
523
610
  end
524
611
  end
525
612
 
@@ -60,12 +60,37 @@ module OpenWFE
60
60
  C_CANCEL = "cancel"
61
61
  C_REWIND = "rewind"
62
62
  C_CONTINUE = "continue"
63
+ C_JUMP = "jump"
63
64
 
64
65
  A_STEP = "step"
65
66
 
66
67
  #
67
68
  # The 'cursor' is much like a sequence, but you can go
68
- # back and forth within it.
69
+ # back and forth within it, as it reads the field '\_\_cursor_command__' (or
70
+ # the field specified in the 'command-field' attribute) at each
71
+ # transition (each time it's supposed to move from one child expression to
72
+ # the next).
73
+ #
74
+ # cursor do
75
+ # participant "alpha"
76
+ # skip :step => "2"
77
+ # participant "bravo"
78
+ # participant "charly"
79
+ # set :field => "__cursor_command__", value => "2"
80
+ # participant "delta"
81
+ # participant "echo"
82
+ # skip 2
83
+ # participant "fox"
84
+ # #
85
+ # # in that cursor example, only the participants alpha, charly and
86
+ # # echo will be handed a workitem
87
+ # # (notice the last 'skip' with its light syntax)
88
+ # #
89
+ # end
90
+ #
91
+ # As you can see, you can directly set the value of the field
92
+ # '\_\_cursor_command__' or use a CursorCommandExpression like 'skip' or
93
+ # 'jump'.
69
94
  #
70
95
  class CursorExpression < WithTemplateExpression
71
96
 
@@ -100,22 +125,36 @@ module OpenWFE
100
125
  return
101
126
  end
102
127
 
103
- command_field = lookup_command_field(workitem)
104
- command = lookup_command(command_field, workitem)
105
- disallow_list = lookup_disallow(workitem)
128
+ command_field = lookup_command_field workitem
129
+
130
+ command, step = lookup_command command_field, workitem
131
+
132
+ disallow_list = lookup_disallow workitem
106
133
 
107
134
  command = nil \
108
- if disallow_list and disallow_list.include? command
135
+ if disallow_list and disallow_list.include?(command)
136
+
137
+ ldebug { "reply() command is '#{command} #{step}'" }
109
138
 
110
139
  if command == C_BREAK or command == C_CANCEL
111
- reply_to_parent(workitem)
140
+ reply_to_parent workitem
112
141
  return
113
142
  end
114
143
 
115
144
  if command == C_REWIND or command == C_CONTINUE
145
+
116
146
  @current_child_id = 0
117
- else
118
- step = lookup_step(command)
147
+
148
+ elsif command and command.match "^#{C_JUMP}"
149
+
150
+ @current_child_id = step
151
+ @current_child_id = 0 if @current_child_id < 0
152
+
153
+ @current_child_id = @children.length - 1 \
154
+ if @current_child_id >= @children.length
155
+
156
+ else # C_SKIP or C_BACK
157
+
119
158
  @current_child_id = @current_child_id + step
120
159
 
121
160
  @current_child_id = 0 if @current_child_id < 0
@@ -148,87 +187,151 @@ module OpenWFE
148
187
  #
149
188
  # takes care of cancelling the current child if necessary
150
189
  #
151
- def cancel ()
190
+ def cancel
152
191
  get_expression_pool.cancel(@current_child_fei) \
153
192
  if @current_child_fei
154
- super()
193
+ super
155
194
  end
156
195
 
157
196
  #
158
- # returns false, the child class LoopExpression does return true.
197
+ # Returns false, the child class LoopExpression does return true.
159
198
  #
160
199
  def is_loop
161
- return false
200
+ false
162
201
  end
163
202
 
164
203
  protected
165
204
 
166
- def lookup_step (command)
167
-
168
- return 1 if not command
169
-
170
- step = 1
171
-
172
- ss = command.split()
173
-
174
- if ss.length > 1
175
- step = Integer(ss[1])
176
- end
177
-
178
- step = -step if OpenWFE::starts_with(command, C_BACK)
179
-
180
- return step
181
- end
182
-
205
+ #
206
+ # Makes sure that only flow expression are left in the cursor
207
+ # children list (text and comment nodes get discarded).
208
+ #
183
209
  def clean_children_list
184
210
 
185
211
  c = @children
186
212
  @children = []
187
213
  c.each do |child|
188
214
  @children << child \
189
- if child.kind_of? OpenWFE::FlowExpressionId
215
+ if child.kind_of?(OpenWFE::FlowExpressionId)
190
216
  end
191
217
  end
192
218
 
219
+ #
220
+ # Looks up the value in the command field.
221
+ #
193
222
  def lookup_command_field (workitem)
194
223
 
195
- return lookup_attribute(A_COMMAND_FIELD, workitem, F_COMMAND)
224
+ lookup_attribute(A_COMMAND_FIELD, workitem, F_COMMAND)
196
225
  end
197
226
 
227
+ #
228
+ # Returns the command and the step
229
+ #
198
230
  def lookup_command (command_field, workitem)
199
231
 
200
232
  command = workitem.attributes[command_field]
201
- command = command.strip() if command
202
233
 
203
- return command
234
+ return [ nil, 1 ] unless command
235
+ #
236
+ # this corresponds to the "just one step forward" default
237
+
238
+ command, step = command.strip.split
239
+
240
+ step = if step
241
+ step.to_i
242
+ else
243
+ 1
244
+ end
245
+
246
+ step = -step if command == C_BACK
247
+
248
+ [ command, step ]
204
249
  end
205
250
 
251
+ #
252
+ # Fetches the value of the 'disallow' cursor attribute.
253
+ #
206
254
  def lookup_disallow (workitem)
207
255
 
208
- return lookup_comma_list_attribute(A_DISALLOW, workitem)
256
+ lookup_comma_list_attribute(A_DISALLOW, workitem)
209
257
  end
210
258
  end
211
259
 
212
260
  #
213
261
  # The 'loop' expression is like 'cursor' but it doesn't exit until
214
- # it's broken.
262
+ # it's broken (with 'break' or 'cancel').
215
263
  #
216
264
  class LoopExpression < CursorExpression
217
265
 
218
266
  names :loop
219
267
 
220
268
  def is_loop
221
- return true
269
+ true
222
270
  end
223
271
  end
224
272
 
225
273
  #
226
- # 'skip', 'continue', and the like
274
+ # This class implements the following expressions : back, break,
275
+ # cancel, continue, jump, rewind, skip.
276
+ #
277
+ # They are generally used inside of a 'cursor' (CursorExpression) or
278
+ # a 'loop' (LoopExpression), they can be used outside, but their result
279
+ # (the value of the field '\_\_cursor_command__' will be used as soon as the
280
+ # flow enters a cursor or a loop).
281
+ #
282
+ # In fact, this expression is only a nice wrapper that sets the
283
+ # value of the field "\_\_cursor_command__" to its name ('back' for example)
284
+ # plus to the 'step' attribute value.
285
+ #
286
+ # For example <skip step="3"/> simply sets the value of the field
287
+ # '\_\_cursor_command__' to 'skip 3'.
288
+ #
289
+ # (The field \_\_cursor_command__ is, by default, read and
290
+ # obeyed by the 'cursor' expression).
291
+ #
292
+ # With Ruby process definitions, you can directly write :
293
+ #
294
+ # skip 2
295
+ # jump "0"
296
+ #
297
+ # instead of
298
+ #
299
+ # skip :step => "2"
300
+ # jump :step => "0"
301
+ #
302
+ # Likewise, in an XML process definition, you can write
303
+ #
304
+ # <skip>2</skip>
305
+ #
306
+ # although that might still look lighter (it's longer though) :
307
+ #
308
+ # <skip step="2"/>
309
+ #
310
+ #
311
+ # About the command themselves :
312
+ #
313
+ # * back : will go back from the number of given steps, 1 by default
314
+ # * break : will exit the cursor (or the loop)
315
+ # * cancel : an alias for 'break'
316
+ # * continue : will exit the cursor, if in a loop, will get back at step 0
317
+ # * jump : will move the cursor (or loop) to an absolute given position (count starts at 0)
318
+ # * rewind : an alias for continue
319
+ # * skip : skips the given number of steps
320
+ #
321
+ #
322
+ # All those command support an 'if' attribute to restrict their execution :
323
+ #
324
+ # cursor do
325
+ # go_to_shop
326
+ # check_prices
327
+ # _break :if => "${price} > ${f:current_cash}"
328
+ # buy_stuff
329
+ # end
227
330
  #
228
331
  class CursorCommandExpression < FlowExpression
229
332
  include ConditionMixin
230
333
 
231
- names :back, :skip, :continue, :break, :cancel, :rewind
334
+ names :back, :skip, :continue, :break, :cancel, :rewind, :jump
232
335
 
233
336
  def apply (workitem)
234
337
 
@@ -240,15 +343,17 @@ module OpenWFE
240
343
 
241
344
  command = @fei.expression_name
242
345
 
243
- step = lookup_attribute(A_STEP, workitem, "1")
346
+ step = lookup_attribute(A_STEP, workitem)
347
+ step = fetch_text_content(workitem) unless step
348
+ step = 1 unless step
244
349
  step = Integer(step)
245
350
 
246
- command = "#{command} #{step}" if step != 1
351
+ command = "#{command} #{step}" #if step != 1
247
352
 
248
353
  workitem.attributes[F_COMMAND] = command
249
354
  end
250
355
 
251
- reply_to_parent(workitem)
356
+ reply_to_parent workitem
252
357
  end
253
358
  end
254
359