ruote 2.3.0.1 → 2.3.0.2

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.
Files changed (148) hide show
  1. data/CHANGELOG.txt +23 -0
  2. data/CREDITS.txt +4 -0
  3. data/LICENSE.txt +1 -1
  4. data/lib/ruote.rb +2 -0
  5. data/lib/ruote/context.rb +2 -1
  6. data/lib/ruote/dashboard.rb +169 -13
  7. data/lib/ruote/dboard/mutation.rb +282 -0
  8. data/lib/ruote/dboard/process_error.rb +1 -1
  9. data/lib/ruote/dboard/process_status.rb +61 -48
  10. data/lib/ruote/engine.rb +1 -1
  11. data/lib/ruote/exp/command.rb +1 -1
  12. data/lib/ruote/exp/commanded.rb +1 -1
  13. data/lib/ruote/exp/condition.rb +2 -1
  14. data/lib/ruote/exp/fe_add_branches.rb +1 -1
  15. data/lib/ruote/exp/fe_apply.rb +1 -1
  16. data/lib/ruote/exp/fe_await.rb +97 -48
  17. data/lib/ruote/exp/fe_cancel_process.rb +1 -1
  18. data/lib/ruote/exp/fe_command.rb +2 -3
  19. data/lib/ruote/exp/fe_concurrence.rb +162 -66
  20. data/lib/ruote/exp/fe_concurrent_iterator.rb +25 -7
  21. data/lib/ruote/exp/fe_cron.rb +1 -1
  22. data/lib/ruote/exp/fe_cursor.rb +10 -11
  23. data/lib/ruote/exp/fe_define.rb +1 -1
  24. data/lib/ruote/exp/fe_echo.rb +1 -1
  25. data/lib/ruote/exp/fe_equals.rb +1 -1
  26. data/lib/ruote/exp/fe_error.rb +1 -1
  27. data/lib/ruote/exp/fe_filter.rb +1 -1
  28. data/lib/ruote/exp/fe_forget.rb +1 -1
  29. data/lib/ruote/exp/fe_given.rb +1 -1
  30. data/lib/ruote/exp/fe_if.rb +87 -7
  31. data/lib/ruote/exp/fe_inc.rb +1 -1
  32. data/lib/ruote/exp/fe_iterator.rb +1 -1
  33. data/lib/ruote/exp/fe_listen.rb +1 -1
  34. data/lib/ruote/exp/fe_lose.rb +1 -1
  35. data/lib/ruote/exp/fe_noop.rb +1 -1
  36. data/lib/ruote/exp/fe_on_error.rb +1 -1
  37. data/lib/ruote/exp/fe_once.rb +1 -1
  38. data/lib/ruote/exp/fe_participant.rb +49 -16
  39. data/lib/ruote/exp/fe_read.rb +1 -1
  40. data/lib/ruote/exp/fe_redo.rb +1 -1
  41. data/lib/ruote/exp/fe_ref.rb +1 -1
  42. data/lib/ruote/exp/fe_registerp.rb +1 -1
  43. data/lib/ruote/exp/fe_reserve.rb +1 -1
  44. data/lib/ruote/exp/fe_restore.rb +1 -7
  45. data/lib/ruote/exp/fe_save.rb +1 -1
  46. data/lib/ruote/exp/fe_sequence.rb +1 -1
  47. data/lib/ruote/exp/fe_set.rb +1 -1
  48. data/lib/ruote/exp/fe_stall.rb +1 -1
  49. data/lib/ruote/exp/fe_subprocess.rb +1 -1
  50. data/lib/ruote/exp/fe_that.rb +1 -1
  51. data/lib/ruote/exp/fe_undo.rb +1 -1
  52. data/lib/ruote/exp/fe_unregisterp.rb +1 -1
  53. data/lib/ruote/exp/fe_wait.rb +1 -1
  54. data/lib/ruote/exp/flow_expression.rb +117 -8
  55. data/lib/ruote/exp/iterator.rb +1 -1
  56. data/lib/ruote/exp/ro_attributes.rb +1 -1
  57. data/lib/ruote/exp/ro_filters.rb +1 -1
  58. data/lib/ruote/exp/ro_on_x.rb +4 -2
  59. data/lib/ruote/exp/ro_persist.rb +1 -1
  60. data/lib/ruote/exp/ro_timers.rb +1 -1
  61. data/lib/ruote/exp/ro_variables.rb +1 -1
  62. data/lib/ruote/extract.rb +125 -0
  63. data/lib/ruote/fei.rb +10 -73
  64. data/lib/ruote/id/mnemo_wfid_generator.rb +1 -1
  65. data/lib/ruote/id/wfid_generator.rb +1 -1
  66. data/lib/ruote/log/default_history.rb +17 -3
  67. data/lib/ruote/log/fancy_printing.rb +12 -32
  68. data/lib/ruote/log/storage_history.rb +1 -1
  69. data/lib/ruote/log/wait_logger.rb +15 -7
  70. data/lib/ruote/merge.rb +123 -0
  71. data/lib/ruote/observer.rb +1 -1
  72. data/lib/ruote/part/block_participant.rb +1 -1
  73. data/lib/ruote/part/code_participant.rb +1 -1
  74. data/lib/ruote/part/engine_participant.rb +1 -1
  75. data/lib/ruote/part/local_participant.rb +9 -1
  76. data/lib/ruote/part/no_op_participant.rb +1 -1
  77. data/lib/ruote/part/null_participant.rb +1 -1
  78. data/lib/ruote/part/participant.rb +1 -1
  79. data/lib/ruote/part/rev_participant.rb +1 -1
  80. data/lib/ruote/part/smtp_participant.rb +1 -1
  81. data/lib/ruote/part/storage_participant.rb +18 -1
  82. data/lib/ruote/part/template.rb +1 -1
  83. data/lib/ruote/reader.rb +1 -1
  84. data/lib/ruote/reader/json.rb +1 -1
  85. data/lib/ruote/reader/radial.rb +4 -4
  86. data/lib/ruote/reader/ruby_dsl.rb +1 -1
  87. data/lib/ruote/reader/xml.rb +1 -1
  88. data/lib/ruote/receiver/base.rb +13 -1
  89. data/lib/ruote/storage/base.rb +8 -14
  90. data/lib/ruote/storage/composite_storage.rb +1 -1
  91. data/lib/ruote/storage/fs_storage.rb +1 -1
  92. data/lib/ruote/storage/hash_storage.rb +2 -1
  93. data/lib/ruote/svc/dispatch_pool.rb +29 -18
  94. data/lib/ruote/svc/dollar_sub.rb +5 -8
  95. data/lib/ruote/svc/error_handler.rb +1 -1
  96. data/lib/ruote/svc/expression_map.rb +1 -1
  97. data/lib/ruote/svc/participant_list.rb +8 -5
  98. data/lib/ruote/svc/tracker.rb +154 -56
  99. data/lib/ruote/svc/treechecker.rb +1 -1
  100. data/lib/ruote/tree_dot.rb +1 -1
  101. data/lib/ruote/util/deep.rb +4 -2
  102. data/lib/ruote/util/filter.rb +1 -1
  103. data/lib/ruote/util/hashdot.rb +1 -1
  104. data/lib/ruote/util/look.rb +1 -1
  105. data/lib/ruote/util/lookup.rb +1 -1
  106. data/lib/ruote/util/misc.rb +51 -1
  107. data/lib/ruote/util/mpatch.rb +1 -1
  108. data/lib/ruote/util/ometa.rb +1 -1
  109. data/lib/ruote/util/subprocess.rb +1 -1
  110. data/lib/ruote/util/time.rb +3 -3
  111. data/lib/ruote/util/tree.rb +43 -4
  112. data/lib/ruote/version.rb +2 -2
  113. data/lib/ruote/worker.rb +30 -18
  114. data/lib/ruote/workitem.rb +1 -1
  115. data/ruote.gemspec +6 -2
  116. data/test/functional/base.rb +0 -1
  117. data/test/functional/concurrent_base.rb +1 -1
  118. data/test/functional/eft_14_cursor.rb +42 -52
  119. data/test/functional/eft_16_if.rb +24 -16
  120. data/test/functional/eft_18_concurrent_iterator.rb +31 -1
  121. data/test/functional/eft_6_concurrence.rb +149 -34
  122. data/test/functional/ft_10_dollar.rb +14 -30
  123. data/test/functional/ft_12_launchitem.rb +15 -0
  124. data/test/functional/ft_1_process_status.rb +62 -13
  125. data/test/functional/ft_20_storage_participant.rb +25 -0
  126. data/test/functional/ft_38_participant_more.rb +1 -1
  127. data/test/functional/ft_42_storage_copy.rb +1 -3
  128. data/test/functional/ft_43_participant_on_reply.rb +63 -5
  129. data/test/functional/ft_66_flank.rb +41 -0
  130. data/test/functional/ft_6_on_cancel.rb +9 -18
  131. data/test/functional/ft_71_retries.rb +25 -12
  132. data/test/functional/ft_79_attach.rb +138 -0
  133. data/test/functional/ft_7_tags.rb +27 -0
  134. data/test/functional/ft_80_pause_on_apply.rb +64 -0
  135. data/test/functional/ft_81_mutation.rb +417 -0
  136. data/test/functional/ft_82_await_attribute.rb +84 -0
  137. data/test/functional/ft_83_trackers.rb +79 -0
  138. data/test/functional/storage.rb +3 -4
  139. data/test/unit/ut_12_wait_logger.rb +41 -3
  140. data/test/unit/ut_15_util.rb +30 -0
  141. data/test/unit/ut_17_merge.rb +54 -53
  142. data/test/unit/ut_1_fei.rb +2 -2
  143. data/test/unit/ut_24_radial_reader.rb +7 -0
  144. data/test/unit/ut_26_deep.rb +14 -0
  145. data/test/unit/ut_5_tree.rb +38 -28
  146. metadata +206 -169
  147. data/couch_url.txt +0 -1
  148. data/lib/ruote/exp/merge.rb +0 -134
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2013, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2013, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -114,9 +114,8 @@ module Ruote::Exp
114
114
 
115
115
  fei = lookup_variable(ref)
116
116
 
117
- target = Ruote::FlowExpressionId.is_a_fei?(fei) ?
117
+ target = Ruote.is_a_fei?(fei) ?
118
118
  Ruote::Exp::FlowExpression.fetch(@context, fei) : nil
119
-
120
119
  target = target.is_a?(Ruote::Exp::CommandedExpression) ?
121
120
  target : nil
122
121
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2013, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -22,8 +22,7 @@
22
22
  # Made in Japan.
23
23
  #++
24
24
 
25
-
26
- require 'ruote/exp/merge'
25
+ require 'ruote/merge'
27
26
 
28
27
 
29
28
  module Ruote::Exp
@@ -94,6 +93,25 @@ module Ruote::Exp
94
93
  #
95
94
  # :wait_for can be shortened to :wf.
96
95
  #
96
+ #
97
+ # === :over_if (and :over_unless) attribute
98
+ #
99
+ # Like the :count attribute controls how many branches have to reply before
100
+ # a concurrence ends, the :over attribute is used to specify a condition
101
+ # upon which the concurrence will [prematurely] end.
102
+ #
103
+ # concurrence :over_if => '${f:over}'
104
+ # alpha
105
+ # bravo
106
+ # charly
107
+ # end
108
+ #
109
+ # will end the concurrence as soon as one of the branches replies with a
110
+ # workitem whose field 'over' is set to true. (the remaining branches will
111
+ # get cancelled unless :remaining => :forget is set).
112
+ #
113
+ # :over_unless needs no explanation.
114
+ #
97
115
  # === :remaining
98
116
  #
99
117
  # As said for :count, the remaining branches get cancelled. By setting
@@ -152,23 +170,23 @@ module Ruote::Exp
152
170
  #
153
171
  # === :merge_type
154
172
  #
155
- # ==== :override
173
+ # ==== :merge_type => :override (default)
156
174
  #
157
175
  # By default, the merge type is set to 'override', which means that the
158
176
  # 'winning' workitem's payload supplants all other workitems' payloads.
159
177
  #
160
- # ==== :mix
178
+ # ==== :merge_type => :mix
161
179
  #
162
180
  # Setting :merge_type to :mix, will actually attempt to merge field by field,
163
181
  # making sure that the field value of the winner(s) are used.
164
182
  #
165
- # ==== :isolate
183
+ # ==== :merge_type => :isolate
166
184
  #
167
185
  # :isolate will rearrange the resulting workitem payload so that there is
168
186
  # a new field for each branch. The name of each field is the index of the
169
187
  # branch from '0' to ...
170
188
  #
171
- # ==== :stack
189
+ # ==== :merge_type => :stack
172
190
  #
173
191
  # :stack will stack the workitems coming back from the concurrence branches
174
192
  # in an array whose order is determined by the :merge attributes. The array
@@ -194,7 +212,7 @@ module Ruote::Exp
194
212
  # This could prove useful for participant having to deal with multiple merge
195
213
  # strategy results.
196
214
  #
197
- # ==== :union
215
+ # ==== :merge_type => :union
198
216
  #
199
217
  # (Available from ruote 2.3.0)
200
218
  #
@@ -214,7 +232,7 @@ module Ruote::Exp
214
232
  # Warning: duplicates in arrays present _before_ the merge will be removed
215
233
  # as well.
216
234
  #
217
- # ==== :concat
235
+ # ==== :merge_type => :concat
218
236
  #
219
237
  # (Available from ruote 2.3.0)
220
238
  #
@@ -229,14 +247,14 @@ module Ruote::Exp
229
247
  # 'b' => [ 'x', 'y', 'y', 'z' ],
230
248
  # 'c' => { 'aa' => 'bb', 'cc' => 'dd' } }
231
249
  #
232
- # ==== :deep
250
+ # ==== :merge_type => :deep
233
251
  #
234
252
  # (Available from ruote 2.3.0)
235
253
  #
236
254
  # Identical to :concat but hashes are merged with deep_merge (ActiveSupport
237
255
  # flavour).
238
256
  #
239
- # ==== :ignore
257
+ # ==== :merge_type => :ignore
240
258
  #
241
259
  # (Available from ruote 2.3.0)
242
260
  #
@@ -246,33 +264,20 @@ module Ruote::Exp
246
264
  #
247
265
  # :merge_type can be shortened to :mt.
248
266
  #
249
- #
250
- # === :over_if (and :over_unless) attribute
251
- #
252
- # Like the :count attribute controls how many branches have to reply before
253
- # a concurrence ends, the :over attribute is used to specify a condition
254
- # upon which the concurrence will [prematurely] end.
255
- #
256
- # concurrence :over_if => '${f:over}'
257
- # alpha
258
- # bravo
259
- # charly
260
- # end
261
- #
262
- # will end the concurrence as soon as one of the branches replies with a
263
- # workitem whose field 'over' is set to true. (the remaining branches will
264
- # get cancelled unless :remaining => :forget is set).
265
- #
266
- # :over_unless needs no explanation.
267
- #
268
267
  class ConcurrenceExpression < FlowExpression
269
268
 
270
- include MergeMixin
271
-
272
269
  names :concurrence
273
270
 
274
271
  COUNT_R = /^-?\d+$/
275
272
 
273
+ # This method is used by some walking routines when analyzsing
274
+ # execution trees. Returns true for concurrence (and concurrent iterator).
275
+ #
276
+ def is_concurrent?
277
+
278
+ true
279
+ end
280
+
276
281
  def apply
277
282
 
278
283
  return do_reply_to_parent(h.applied_workitem) if tree_children.empty?
@@ -304,7 +309,14 @@ module Ruote::Exp
304
309
  [ :remaining, :rem, :r ],
305
310
  %w[ cancel forget wait ])
306
311
 
307
- h.workitems = (h.cmerge == 'first' || h.cmerge == 'last') ? [] : {}
312
+ #h.workitems = (h.cmerge == 'first' || h.cmerge == 'last') ? [] : {}
313
+ #
314
+ # now merging iteratively, not keeping track of all the workitems,
315
+ # but still able to deal with old flows with active h.workitems
316
+ #
317
+ h.workitems = [] if %w[ highest lowest ].include?(h.cmerge)
318
+ #
319
+ # still need to keep track of rank to get the right merging
308
320
 
309
321
  h.over = false
310
322
 
@@ -325,12 +337,6 @@ module Ruote::Exp
325
337
  # a copy of the workitem (so that history, coming afterwards,
326
338
  # doesn't see a modified version of the workitem)
327
339
 
328
- if h.cmerge == 'first' || h.cmerge == 'last'
329
- h.workitems << workitem
330
- else
331
- h.workitems[workitem['fei']['expid']] = workitem
332
- end
333
-
334
340
  if h.wait_for && tag = workitem['fields']['__left_tag__']
335
341
  h.wait_for.delete(tag)
336
342
  end
@@ -338,7 +344,11 @@ module Ruote::Exp
338
344
  over = h.over
339
345
  h.over = over || over?(workitem)
340
346
 
347
+ keep(workitem)
348
+ # is done after the over? determination for its looks at 'winner'
349
+
341
350
  if (not over) && h.over
351
+ #
342
352
  # just became 'over'
343
353
 
344
354
  reply_to_parent(nil)
@@ -362,6 +372,42 @@ module Ruote::Exp
362
372
 
363
373
  protected
364
374
 
375
+ def keep(workitem)
376
+
377
+ h.workitems = h.workitems.values if h.workitems.is_a?(Hash)
378
+ # align legacy expressions on new simplified way
379
+
380
+ if h.workitems
381
+ #
382
+ # the old way (still used for highest / lowest)
383
+
384
+ h.workitems << workitem
385
+ return
386
+ end
387
+
388
+ #
389
+ # the new way, merging immediately
390
+
391
+ h.workitem_count = (h.workitem_count || 0) + 1
392
+
393
+ return if h.cmerge_type == 'ignore'
394
+
395
+ # preparing target and source in the right order for merging
396
+
397
+ target, source = h.workitem, workitem
398
+ if
399
+ h.cmerge == 'first' &&
400
+ ! %w[ stack union concat deep isolate ].include?(h.cmerge_type)
401
+ then
402
+ target, source = source, target
403
+ end
404
+ target, source = source, target if target && target.delete('winner')
405
+ target, source = source, target if source == nil
406
+
407
+ h.workitem = Ruote.merge_workitem(
408
+ workitem_index(workitem), target, source, h.cmerge_type)
409
+ end
410
+
365
411
  def apply_children
366
412
 
367
413
  # a) register children
@@ -393,7 +439,8 @@ module Ruote::Exp
393
439
  elsif h.wait_for
394
440
  h.wait_for.empty?
395
441
  else
396
- (h.workitems.size >= expected_count)
442
+ (workitem_count + 1 >= expected_count)
443
+ # the + 1 is necessary since #keep hasn't yet been called
397
444
  end
398
445
  end
399
446
 
@@ -425,13 +472,13 @@ module Ruote::Exp
425
472
 
426
473
  if h.remaining == 'wait'
427
474
 
428
- if h.workitems.size >= count_list_size
475
+ if workitem_count >= count_list_size
429
476
  #
430
477
  # all children have replied
431
478
 
432
- workitem = merge_all_workitems
479
+ h.workitem = final_merge
433
480
 
434
- do_unpersist && super(workitem, false)
481
+ do_unpersist && super(h.workitem, false)
435
482
 
436
483
  elsif h.children_cancelled == nil
437
484
  #
@@ -450,17 +497,17 @@ module Ruote::Exp
450
497
  #
451
498
  # remaining 'forget' and 'cancel' cases
452
499
 
453
- workitem = merge_all_workitems
500
+ h.workitem = final_merge
454
501
 
455
502
  if h.children.empty?
456
503
 
457
- do_unpersist && super(workitem, false)
504
+ do_unpersist && super(h.workitem, false)
458
505
 
459
506
  elsif h.remaining == 'cancel'
460
507
 
461
508
  if do_unpersist
462
509
 
463
- super(workitem, false)
510
+ super(h.workitem, false)
464
511
 
465
512
  h.children.each { |i| @context.storage.put_msg('cancel', 'fei' => i) }
466
513
  end
@@ -470,35 +517,84 @@ module Ruote::Exp
470
517
  h.variables = compile_variables
471
518
  h.forgotten = true
472
519
 
473
- do_persist && super(workitem, false)
520
+ do_persist && super(h.workitem, false)
474
521
  end
475
522
  end
476
523
 
477
524
  # Called by #reply_to_parent, returns the unique, merged, workitem that
478
525
  # will be fed back to the parent expression.
479
526
  #
480
- def merge_all_workitems
481
-
482
- return h.applied_workitem if h.workitems.size < 1
483
- return h.applied_workitem if h.cmerge_type == 'ignore'
484
-
485
- wis = case h.cmerge
486
- when 'first'
487
- h.workitems.reverse
488
- when 'last'
489
- h.workitems
490
- when 'highest', 'lowest'
491
- is = h.workitems.keys.sort.collect { |k| h.workitems[k] }
492
- h.cmerge == 'highest' ? is.reverse : is
527
+ def final_merge
528
+
529
+ wi = if h.workitem
530
+
531
+ h.workitem
532
+
533
+ elsif h.cmerge_type == 'ignore' || h.workitems.nil? || h.workitems.empty?
534
+
535
+ h.applied_workitem
536
+
537
+ else
538
+
539
+ wis = h.workitems
540
+
541
+ if %w[ highest lowest ].include?(h.cmerge)
542
+ wis = h.workitems.sort_by { |wi| wi['fei']['expid'] }
543
+ end
544
+
545
+ if
546
+ %w[ first highest ].include?(h.cmerge) &&
547
+ ! %w[ stack union concat deep ].include?(h.cmerge_type)
548
+ then
549
+ wis = wis.reverse
550
+ end
551
+
552
+ as, bs = wis.partition { |wi| wi.delete('winner') }
553
+ wis = bs + as
554
+ #
555
+ # the 'winner' is the workitem that triggered successfully the
556
+ # :over_if or :over_unless, let's take him precedence in the merge...
557
+
558
+ merge_workitems(wis, h.cmerge_type)
493
559
  end
494
560
 
495
- as, bs = wis.partition { |wi| wi.delete('winner') }
496
- wis = bs + as
497
- #
498
- # the 'winner' is the workitem that triggered successfully the
499
- # :over_if or :over_unless, let's take him precedence in the merge...
561
+ if h.cmerge_type == 'stack'
562
+ wi['fields']['stack_attributes'] = compile_atts
563
+ end
564
+
565
+ wi
566
+ end
567
+
568
+ # Returns the current count of workitem replies.
569
+ #
570
+ def workitem_count
500
571
 
501
- merge_workitems(wis, h.cmerge_type)
572
+ h.workitems ? h.workitems.size : (h.workitem_count || 0)
573
+ end
574
+
575
+ # Given a workitem, returns its index (highest to lowest in the tree
576
+ # children... z-index?).
577
+ #
578
+ # Is overriden by the concurrent-iterator.
579
+ #
580
+ def workitem_index(workitem)
581
+
582
+ Ruote.extract_child_id(workitem['fei'])
583
+ end
584
+
585
+ # Given a list of workitems and a merge_type, will merge according to
586
+ # the merge type.
587
+ #
588
+ # The return value is the merged workitem.
589
+ #
590
+ # (Still used when dealing with highest/lowest merge_type and legacy
591
+ # concurrence/citerator expressions)
592
+ #
593
+ def merge_workitems(workitems, merge_type)
594
+
595
+ workitems.inject(nil) do |t, wi|
596
+ Ruote.merge_workitem(workitem_index(wi), t, wi, merge_type)
597
+ end
502
598
  end
503
599
  end
504
600
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2013, John Mettraux, jmettraux@gmail.com
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -150,8 +150,8 @@ module Ruote::Exp
150
150
  # the concurrent_iterator accepts the same options for merging as its bigger
151
151
  # brother, the concurrence expression.
152
152
  #
153
- # :count, :merge (override, mix, isolate), remaining (cancel, forget) and
154
- # :over.
153
+ # :count, :merge (override, mix, isolate, stack, union, concat, deep, ignore),
154
+ # :remaining (cancel, forget) and :over.
155
155
  #
156
156
  #
157
157
  # == add branches
@@ -228,7 +228,11 @@ module Ruote::Exp
228
228
  end
229
229
 
230
230
  launch_sub(
231
- expid, subtree, :workitem => workitem, :variables => variables)
231
+ expid,
232
+ subtree,
233
+ :workitem => workitem,
234
+ :variables => variables,
235
+ :child_id => h.list_size - 1)
232
236
  end
233
237
  end
234
238
 
@@ -238,9 +242,10 @@ module Ruote::Exp
238
242
 
239
243
  add_branches(ab)
240
244
 
241
- if h.fei['wfid'] != workitem['fei']['wfid'] ||
242
- ( ! workitem['fei']['expid'].match(/^#{h.fei['expid']}_\d+$/))
243
-
245
+ if
246
+ h.fei['wfid'] != workitem['fei']['wfid'] ||
247
+ ( ! workitem['fei']['expid'].match(/^#{h.fei['expid']}_\d+$/))
248
+ then
244
249
  do_persist
245
250
  return
246
251
  end
@@ -275,6 +280,19 @@ module Ruote::Exp
275
280
 
276
281
  h.list_size
277
282
  end
283
+
284
+ # TODO
285
+ #
286
+ def workitem_index(workitem)
287
+
288
+ if %w[ highest lowest ].include?(h.cmerge)
289
+ nil
290
+ elsif m = workitem['fei']['subid'].match(/k(\d)+$/)
291
+ m[1].to_i
292
+ else
293
+ nil
294
+ end
295
+ end
278
296
  end
279
297
  end
280
298