ruote 2.2.0 → 2.3.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.
Files changed (305) hide show
  1. data/CHANGELOG.txt +166 -1
  2. data/CREDITS.txt +36 -17
  3. data/LICENSE.txt +1 -1
  4. data/README.rdoc +1 -7
  5. data/Rakefile +38 -29
  6. data/TODO.txt +93 -52
  7. data/lib/ruote-fs.rb +3 -0
  8. data/lib/ruote.rb +5 -1
  9. data/lib/ruote/context.rb +140 -35
  10. data/lib/ruote/dashboard.rb +1247 -0
  11. data/lib/ruote/{engine → dboard}/process_error.rb +22 -2
  12. data/lib/ruote/dboard/process_status.rb +587 -0
  13. data/lib/ruote/engine.rb +6 -871
  14. data/lib/ruote/exp/command.rb +7 -2
  15. data/lib/ruote/exp/commanded.rb +2 -2
  16. data/lib/ruote/exp/condition.rb +38 -13
  17. data/lib/ruote/exp/fe_add_branches.rb +1 -1
  18. data/lib/ruote/exp/fe_apply.rb +1 -1
  19. data/lib/ruote/exp/fe_await.rb +357 -0
  20. data/lib/ruote/exp/fe_cancel_process.rb +17 -3
  21. data/lib/ruote/exp/fe_command.rb +8 -4
  22. data/lib/ruote/exp/fe_concurrence.rb +218 -18
  23. data/lib/ruote/exp/fe_concurrent_iterator.rb +71 -10
  24. data/lib/ruote/exp/fe_cron.rb +3 -10
  25. data/lib/ruote/exp/fe_cursor.rb +14 -4
  26. data/lib/ruote/exp/fe_define.rb +3 -1
  27. data/lib/ruote/exp/fe_echo.rb +1 -1
  28. data/lib/ruote/exp/fe_equals.rb +1 -1
  29. data/lib/ruote/exp/fe_error.rb +1 -1
  30. data/lib/ruote/exp/fe_filter.rb +163 -4
  31. data/lib/ruote/exp/fe_forget.rb +21 -4
  32. data/lib/ruote/exp/fe_given.rb +1 -1
  33. data/lib/ruote/exp/fe_if.rb +1 -1
  34. data/lib/ruote/exp/fe_inc.rb +102 -35
  35. data/lib/ruote/exp/fe_iterator.rb +47 -12
  36. data/lib/ruote/exp/fe_listen.rb +96 -11
  37. data/lib/ruote/exp/fe_lose.rb +31 -4
  38. data/lib/ruote/exp/fe_noop.rb +1 -1
  39. data/lib/ruote/exp/fe_on_error.rb +109 -0
  40. data/lib/ruote/exp/fe_once.rb +10 -19
  41. data/lib/ruote/exp/fe_participant.rb +90 -28
  42. data/lib/ruote/exp/fe_read.rb +69 -0
  43. data/lib/ruote/exp/fe_redo.rb +3 -2
  44. data/lib/ruote/exp/fe_ref.rb +57 -27
  45. data/lib/ruote/exp/fe_registerp.rb +1 -3
  46. data/lib/ruote/exp/fe_reserve.rb +1 -1
  47. data/lib/ruote/exp/fe_restore.rb +6 -6
  48. data/lib/ruote/exp/fe_save.rb +12 -19
  49. data/lib/ruote/exp/fe_sequence.rb +38 -2
  50. data/lib/ruote/exp/fe_set.rb +143 -40
  51. data/lib/ruote/exp/{fe_let.rb → fe_stall.rb} +7 -38
  52. data/lib/ruote/exp/fe_subprocess.rb +8 -2
  53. data/lib/ruote/exp/fe_that.rb +1 -1
  54. data/lib/ruote/exp/fe_undo.rb +40 -4
  55. data/lib/ruote/exp/fe_unregisterp.rb +1 -3
  56. data/lib/ruote/exp/fe_wait.rb +12 -25
  57. data/lib/ruote/exp/{flowexpression.rb → flow_expression.rb} +375 -229
  58. data/lib/ruote/exp/iterator.rb +2 -2
  59. data/lib/ruote/exp/merge.rb +78 -17
  60. data/lib/ruote/exp/ro_attributes.rb +46 -36
  61. data/lib/ruote/exp/ro_filters.rb +34 -8
  62. data/lib/ruote/exp/ro_on_x.rb +431 -0
  63. data/lib/ruote/exp/ro_persist.rb +19 -7
  64. data/lib/ruote/exp/ro_timers.rb +123 -0
  65. data/lib/ruote/exp/ro_variables.rb +90 -29
  66. data/lib/ruote/fei.rb +57 -3
  67. data/lib/ruote/fs.rb +3 -0
  68. data/lib/ruote/id/mnemo_wfid_generator.rb +30 -7
  69. data/lib/ruote/id/wfid_generator.rb +17 -38
  70. data/lib/ruote/log/default_history.rb +23 -9
  71. data/lib/ruote/log/fancy_printing.rb +265 -0
  72. data/lib/ruote/log/storage_history.rb +23 -13
  73. data/lib/ruote/log/wait_logger.rb +224 -17
  74. data/lib/ruote/observer.rb +82 -0
  75. data/lib/ruote/part/block_participant.rb +65 -28
  76. data/lib/ruote/part/code_participant.rb +81 -0
  77. data/lib/ruote/part/engine_participant.rb +7 -2
  78. data/lib/ruote/part/local_participant.rb +221 -21
  79. data/lib/ruote/part/no_op_participant.rb +1 -1
  80. data/lib/ruote/part/null_participant.rb +1 -1
  81. data/lib/ruote/part/participant.rb +50 -0
  82. data/lib/ruote/part/rev_participant.rb +178 -0
  83. data/lib/ruote/part/smtp_participant.rb +2 -2
  84. data/lib/ruote/part/storage_participant.rb +228 -60
  85. data/lib/ruote/part/template.rb +1 -1
  86. data/lib/ruote/participant.rb +2 -0
  87. data/lib/ruote/reader.rb +205 -68
  88. data/lib/ruote/reader/json.rb +49 -0
  89. data/lib/ruote/reader/radial.rb +303 -0
  90. data/lib/ruote/reader/ruby_dsl.rb +44 -9
  91. data/lib/ruote/reader/xml.rb +11 -8
  92. data/lib/ruote/receiver/base.rb +98 -45
  93. data/lib/ruote/storage/base.rb +104 -35
  94. data/lib/ruote/storage/composite_storage.rb +50 -60
  95. data/lib/ruote/storage/fs_storage.rb +25 -34
  96. data/lib/ruote/storage/hash_storage.rb +38 -36
  97. data/lib/ruote/svc/dispatch_pool.rb +104 -35
  98. data/lib/ruote/svc/dollar_sub.rb +10 -8
  99. data/lib/ruote/svc/error_handler.rb +108 -52
  100. data/lib/ruote/svc/expression_map.rb +3 -3
  101. data/lib/ruote/svc/participant_list.rb +160 -55
  102. data/lib/ruote/svc/tracker.rb +31 -31
  103. data/lib/ruote/svc/treechecker.rb +28 -16
  104. data/lib/ruote/tree_dot.rb +1 -1
  105. data/lib/ruote/util/deep.rb +143 -0
  106. data/lib/ruote/util/filter.rb +125 -18
  107. data/lib/ruote/util/hashdot.rb +15 -13
  108. data/lib/ruote/util/look.rb +1 -1
  109. data/lib/ruote/util/lookup.rb +60 -22
  110. data/lib/ruote/util/misc.rb +63 -18
  111. data/lib/ruote/util/mpatch.rb +53 -0
  112. data/lib/ruote/util/ometa.rb +1 -2
  113. data/lib/ruote/util/process_observer.rb +177 -0
  114. data/lib/ruote/util/subprocess.rb +1 -1
  115. data/lib/ruote/util/time.rb +2 -2
  116. data/lib/ruote/util/tree.rb +64 -2
  117. data/lib/ruote/version.rb +3 -2
  118. data/lib/ruote/worker.rb +421 -92
  119. data/lib/ruote/workitem.rb +157 -22
  120. data/ruote.gemspec +15 -9
  121. data/test/bm/ci.rb +0 -2
  122. data/test/bm/ici.rb +0 -2
  123. data/test/bm/load_26c.rb +0 -3
  124. data/test/bm/mega.rb +0 -2
  125. data/test/functional/base.rb +57 -43
  126. data/test/functional/concurrent_base.rb +16 -13
  127. data/test/functional/ct_0_concurrence.rb +7 -11
  128. data/test/functional/ct_1_iterator.rb +9 -11
  129. data/test/functional/ct_2_cancel.rb +28 -17
  130. data/test/functional/eft_0_flow_expression.rb +35 -0
  131. data/test/functional/eft_10_cancel_process.rb +1 -1
  132. data/test/functional/eft_11_wait.rb +13 -13
  133. data/test/functional/eft_12_listen.rb +199 -66
  134. data/test/functional/eft_13_iterator.rb +95 -29
  135. data/test/functional/eft_14_cursor.rb +74 -24
  136. data/test/functional/eft_15_loop.rb +7 -7
  137. data/test/functional/eft_16_if.rb +1 -1
  138. data/test/functional/eft_17_equals.rb +1 -1
  139. data/test/functional/eft_18_concurrent_iterator.rb +156 -68
  140. data/test/functional/eft_19_reserve.rb +15 -15
  141. data/test/functional/eft_1_echo.rb +1 -1
  142. data/test/functional/eft_20_save.rb +51 -9
  143. data/test/functional/eft_21_restore.rb +1 -1
  144. data/test/functional/eft_22_noop.rb +1 -1
  145. data/test/functional/eft_23_apply.rb +1 -1
  146. data/test/functional/eft_24_add_branches.rb +7 -8
  147. data/test/functional/eft_25_command.rb +1 -1
  148. data/test/functional/eft_26_error.rb +11 -11
  149. data/test/functional/eft_27_inc.rb +111 -67
  150. data/test/functional/eft_28_once.rb +16 -16
  151. data/test/functional/eft_29_cron.rb +9 -9
  152. data/test/functional/eft_2_sequence.rb +23 -4
  153. data/test/functional/eft_30_ref.rb +36 -24
  154. data/test/functional/eft_31_registerp.rb +24 -24
  155. data/test/functional/eft_32_lose.rb +46 -20
  156. data/test/functional/eft_34_given.rb +1 -1
  157. data/test/functional/eft_35_filter.rb +161 -7
  158. data/test/functional/eft_36_read.rb +97 -0
  159. data/test/functional/{eft_0_process_definition.rb → eft_37_process_definition.rb} +4 -4
  160. data/test/functional/eft_38_on_error.rb +195 -0
  161. data/test/functional/eft_39_stall.rb +35 -0
  162. data/test/functional/eft_3_participant.rb +77 -22
  163. data/test/functional/eft_40_await.rb +297 -0
  164. data/test/functional/eft_4_set.rb +110 -11
  165. data/test/functional/eft_5_subprocess.rb +27 -5
  166. data/test/functional/eft_6_concurrence.rb +299 -60
  167. data/test/functional/eft_7_forget.rb +24 -22
  168. data/test/functional/eft_8_undo.rb +52 -15
  169. data/test/functional/eft_9_redo.rb +18 -20
  170. data/test/functional/ft_0_worker.rb +122 -13
  171. data/test/functional/ft_10_dollar.rb +77 -16
  172. data/test/functional/ft_11_recursion.rb +9 -9
  173. data/test/functional/ft_12_launchitem.rb +7 -9
  174. data/test/functional/ft_13_variables.rb +125 -22
  175. data/test/functional/ft_14_re_apply.rb +112 -56
  176. data/test/functional/ft_15_timeout.rb +64 -33
  177. data/test/functional/ft_16_participant_params.rb +59 -6
  178. data/test/functional/ft_17_conditional.rb +68 -2
  179. data/test/functional/ft_18_kill.rb +48 -30
  180. data/test/functional/ft_19_participant_code.rb +67 -0
  181. data/test/functional/ft_1_process_status.rb +222 -150
  182. data/test/functional/ft_20_storage_participant.rb +445 -44
  183. data/test/functional/ft_21_forget.rb +21 -26
  184. data/test/functional/ft_22_process_definitions.rb +8 -6
  185. data/test/functional/ft_23_load_defs.rb +29 -5
  186. data/test/functional/ft_24_block_participant.rb +199 -20
  187. data/test/functional/ft_25_receiver.rb +98 -46
  188. data/test/functional/ft_26_participant_rtimeout.rb +34 -26
  189. data/test/functional/ft_27_var_indirection.rb +40 -5
  190. data/test/functional/ft_28_null_noop_participants.rb +5 -5
  191. data/test/functional/ft_29_part_template.rb +2 -2
  192. data/test/functional/ft_2_errors.rb +106 -74
  193. data/test/functional/ft_30_smtp_participant.rb +7 -7
  194. data/test/functional/ft_31_part_blocking.rb +11 -11
  195. data/test/functional/ft_32_scope.rb +50 -0
  196. data/test/functional/ft_33_participant_subprocess_priority.rb +3 -3
  197. data/test/functional/ft_34_cursor_rewind.rb +14 -14
  198. data/test/functional/ft_35_add_service.rb +67 -9
  199. data/test/functional/ft_36_storage_history.rb +92 -24
  200. data/test/functional/ft_37_default_history.rb +35 -23
  201. data/test/functional/ft_38_participant_more.rb +189 -32
  202. data/test/functional/ft_39_wait_for.rb +25 -25
  203. data/test/functional/ft_3_participant_registration.rb +235 -107
  204. data/test/functional/ft_40_wait_logger.rb +105 -18
  205. data/test/functional/ft_41_participants.rb +13 -12
  206. data/test/functional/ft_42_storage_copy.rb +12 -12
  207. data/test/functional/ft_43_participant_on_reply.rb +85 -11
  208. data/test/functional/ft_44_var_participant.rb +5 -5
  209. data/test/functional/ft_45_participant_accept.rb +3 -3
  210. data/test/functional/ft_46_launch_single.rb +17 -17
  211. data/test/functional/ft_47_wfids.rb +41 -0
  212. data/test/functional/ft_48_lose.rb +19 -25
  213. data/test/functional/ft_49_engine_on_error.rb +54 -70
  214. data/test/functional/ft_4_cancel.rb +84 -26
  215. data/test/functional/ft_50_engine_config.rb +4 -4
  216. data/test/functional/ft_51_misc.rb +12 -12
  217. data/test/functional/ft_52_case.rb +17 -17
  218. data/test/functional/ft_53_engine_on_terminate.rb +18 -21
  219. data/test/functional/ft_54_patterns.rb +18 -16
  220. data/test/functional/ft_55_engine_participant.rb +55 -55
  221. data/test/functional/ft_56_filter_attribute.rb +90 -52
  222. data/test/functional/ft_57_rev_participant.rb +252 -0
  223. data/test/functional/ft_58_workitem.rb +150 -0
  224. data/test/functional/ft_59_pause.rb +329 -0
  225. data/test/functional/ft_5_on_error.rb +430 -77
  226. data/test/functional/ft_60_code_participant.rb +65 -0
  227. data/test/functional/ft_61_trailing_fields.rb +34 -0
  228. data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
  229. data/test/functional/ft_63_participants_221.rb +458 -0
  230. data/test/functional/ft_64_stash.rb +41 -0
  231. data/test/functional/ft_65_timers.rb +313 -0
  232. data/test/functional/ft_66_flank.rb +133 -0
  233. data/test/functional/ft_67_radial_misc.rb +34 -0
  234. data/test/functional/ft_68_reput.rb +72 -0
  235. data/test/functional/ft_69_worker_info.rb +56 -0
  236. data/test/functional/ft_6_on_cancel.rb +189 -36
  237. data/test/functional/ft_70_take_and_discard_attributes.rb +94 -0
  238. data/test/functional/ft_71_retries.rb +144 -0
  239. data/test/functional/ft_72_on_terminate.rb +60 -0
  240. data/test/functional/ft_73_raise_msg.rb +107 -0
  241. data/test/functional/ft_74_respark.rb +106 -0
  242. data/test/functional/ft_75_context.rb +66 -0
  243. data/test/functional/ft_76_observer.rb +53 -0
  244. data/test/functional/ft_77_process_observer.rb +157 -0
  245. data/test/functional/ft_78_part_participant.rb +37 -0
  246. data/test/functional/ft_7_tags.rb +238 -50
  247. data/test/functional/ft_8_participant_consumption.rb +27 -21
  248. data/test/functional/ft_9_subprocesses.rb +48 -18
  249. data/test/functional/restart_base.rb +4 -6
  250. data/test/functional/rt_0_wait.rb +10 -10
  251. data/test/functional/rt_1_listen.rb +6 -6
  252. data/test/functional/rt_2_errors.rb +12 -12
  253. data/test/functional/rt_3_once.rb +17 -12
  254. data/test/functional/rt_4_cron.rb +17 -17
  255. data/test/functional/rt_5_timeout.rb +13 -13
  256. data/test/functional/signals.rb +103 -0
  257. data/test/functional/storage.rb +730 -0
  258. data/test/functional/storage_helper.rb +48 -35
  259. data/test/functional/test.rb +6 -2
  260. data/test/misc/idle.rb +21 -0
  261. data/test/misc/light.rb +29 -0
  262. data/test/path_helper.rb +1 -1
  263. data/test/test.rb +2 -5
  264. data/test/test_helper.rb +13 -0
  265. data/test/unit/test.rb +1 -4
  266. data/test/unit/ut_0_ruby_reader.rb +25 -9
  267. data/test/unit/ut_10_participants.rb +47 -0
  268. data/test/unit/ut_11_lookup.rb +59 -2
  269. data/test/unit/ut_12_wait_logger.rb +123 -0
  270. data/test/unit/ut_14_is_uri.rb +1 -1
  271. data/test/unit/ut_15_util.rb +1 -1
  272. data/test/unit/ut_16_reader.rb +136 -14
  273. data/test/unit/ut_17_merge.rb +155 -0
  274. data/test/unit/ut_19_part_template.rb +1 -1
  275. data/test/unit/ut_1_fei.rb +11 -2
  276. data/test/unit/ut_20_composite_storage.rb +27 -1
  277. data/test/unit/{ut_21_participant_list.rb → ut_21_svc_participant_list.rb} +2 -3
  278. data/test/unit/ut_22_filter.rb +231 -10
  279. data/test/unit/ut_23_svc_tracker.rb +48 -0
  280. data/test/unit/ut_24_radial_reader.rb +458 -0
  281. data/test/unit/ut_25_process_status.rb +143 -0
  282. data/test/unit/ut_26_deep.rb +131 -0
  283. data/test/unit/ut_2_dashboard.rb +114 -0
  284. data/test/unit/ut_3_worker.rb +54 -0
  285. data/test/unit/ut_4_expmap.rb +1 -1
  286. data/test/unit/ut_5_tree.rb +23 -23
  287. data/test/unit/ut_6_condition.rb +71 -29
  288. data/test/unit/ut_7_workitem.rb +18 -4
  289. data/test/unit/ut_8_tree_to_dot.rb +1 -1
  290. data/test/unit/ut_9_xml_reader.rb +1 -1
  291. metadata +142 -63
  292. data/jruby_issue.txt +0 -32
  293. data/lib/ruote/engine/process_status.rb +0 -403
  294. data/lib/ruote/log/pretty.rb +0 -165
  295. data/lib/ruote/log/test_logger.rb +0 -204
  296. data/lib/ruote/util/serializer.rb +0 -103
  297. data/phil.txt +0 -14
  298. data/test/functional/eft_33_let.rb +0 -31
  299. data/test/functional/ft_19_alias.rb +0 -33
  300. data/test/functional/ft_47_wfid_generator.rb +0 -54
  301. data/test/unit/storage.rb +0 -403
  302. data/test/unit/storages.rb +0 -37
  303. data/test/unit/ut_13_serializer.rb +0 -65
  304. data/test/unit/ut_18_engine.rb +0 -47
  305. data/test/unit/ut_3_wait_logger.rb +0 -39
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, 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
@@ -30,8 +30,13 @@ module Ruote::Exp
30
30
  #
31
31
  module CommandMixin
32
32
 
33
+ # Field name '__command__', where one can place a command.
34
+ #
33
35
  F_COMMAND = '__command__'
34
- ATT_COMMANDS = %w[ break rewind over stop ]
36
+
37
+ # break_if, break_unless, rewind_if, rewind_unless, ...
38
+ #
39
+ ATT_COMMANDS = %w[ break rewind reset over stop ]
35
40
 
36
41
  protected
37
42
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, 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
@@ -58,7 +58,7 @@ module Ruote::Exp
58
58
  h.command_workitem = workitem
59
59
  h.command_workitem['fei'] = h.children.first
60
60
 
61
- do_persist || return
61
+ do_persist or return
62
62
 
63
63
  @context.storage.put_msg('cancel', 'fei' => h.children.first)
64
64
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, 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
@@ -52,8 +52,8 @@ module Ruote::Exp
52
52
 
53
53
  def self.apply?(sif, sunless)
54
54
 
55
- return (true?(sif)) if sif
56
- return ( ! true?(sunless)) if sunless
55
+ return (true?(sif)) if sif != nil
56
+ return ( ! true?(sunless)) if sunless != nil
57
57
 
58
58
  true
59
59
  end
@@ -65,9 +65,8 @@ module Ruote::Exp
65
65
  conditional = unescape(conditional.to_s)
66
66
 
67
67
  REGEXES.each do |method, regex|
68
- if m = regex.match(conditional)
69
- return self.send(method, m)
70
- end
68
+ m = regex.match(conditional)
69
+ return self.send(method, m) if m
71
70
  end
72
71
 
73
72
  evl(conditional) ? true : false
@@ -77,6 +76,13 @@ module Ruote::Exp
77
76
  raise ConditionError.new(conditional)
78
77
  end
79
78
 
79
+ # Returns true if the given conditional string evaluates to false.
80
+ #
81
+ def self.false?(conditional)
82
+
83
+ ( ! true?(conditional))
84
+ end
85
+
80
86
  # Evaluates the given [conditional] code string and returns the
81
87
  # result.
82
88
  #
@@ -95,13 +101,11 @@ module Ruote::Exp
95
101
 
96
102
  def self.parse(conditional)
97
103
 
98
- Rufus::TreeChecker.parse(conditional)
104
+ Ruote.parse_ruby(conditional)
99
105
 
100
- rescue NoMethodError => nme
106
+ rescue SyntaxError => se
101
107
 
102
- raise NoMethodError.new(
103
- "/!\\ please upgrade your rufus-treechecker gem /!\\"
104
- )
108
+ [ :str, conditional ]
105
109
 
106
110
  rescue => e
107
111
 
@@ -147,9 +151,16 @@ module Ruote::Exp
147
151
  return evl(tree[1]).send(tree[2], evl(tree.last.last))
148
152
  end
149
153
 
150
- return flatten(tree) if tree[0] == :call
154
+ if (c = flatten_and_compare(tree)) != nil
155
+ return c
156
+ end
157
+
158
+ if tree[0] == :call
159
+ return flatten(tree)
160
+ end
151
161
 
152
162
  raise ArgumentError
163
+ # TODO : consider returning false
153
164
 
154
165
  #require 'ruby2ruby'
155
166
  #Ruby2Ruby.new.process(Sexp.from_array(tree))
@@ -157,7 +168,21 @@ module Ruote::Exp
157
168
  # it's nice but "Loan/Grant" becomes "(Loan / Grant)"
158
169
  end
159
170
 
160
- KEYWORDS = %w[ call const arglist ].collect { |w| w.to_sym }
171
+ def self.flatten_and_compare(tree)
172
+
173
+ ftree = tree.flatten
174
+ comparator = (ftree & COMPARATORS).first
175
+
176
+ return nil unless comparator
177
+
178
+ icomparator = ftree.index(comparator)
179
+ left = ftree[0..icomparator - 1]
180
+ right = ftree[icomparator + 1..-1]
181
+
182
+ evl("#{flatten(left).inspect} #{comparator} #{flatten(right).inspect}")
183
+ end
184
+
185
+ KEYWORDS = %w[ call const arglist str ].collect { |w| w.to_sym }
161
186
 
162
187
  def self.flatten(tree)
163
188
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, 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-2011, John Mettraux, jmettraux@gmail.com
2
+ # Copyright (c) 2005-2012, 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
@@ -0,0 +1,357 @@
1
+ #--
2
+ # Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+ # Made in Japan.
23
+ #++
24
+
25
+
26
+ require 'ruote/exp/condition'
27
+
28
+
29
+ module Ruote::Exp
30
+
31
+ #
32
+ # The 'await' expression is the successor of the 'listen' expression
33
+ # (Ruote::Exp::ListenExpression). It's been introduced in ruote 2.3.0.
34
+ #
35
+ # Hopefully it has a simpler syntax than 'listen'. The major difference
36
+ # between listen and await is that await, by default, listens only
37
+ # to events in the same process instance.
38
+ #
39
+ # This expression blocks until an event occurs somewhere else in the same
40
+ # process instance.
41
+ #
42
+ # concurrence do
43
+ # sequence do
44
+ # participant 'alice'
45
+ # await :left_tag => 'a'
46
+ # participant 'bob'
47
+ # end
48
+ # sequence :tag => 'a' do
49
+ # participant 'charly'
50
+ # participant 'doug'
51
+ # end
52
+ # sequence do
53
+ # participant 'eric'
54
+ # end
55
+ # end
56
+ #
57
+ # In this example, the flow between alice and bob, will block until 'doug'
58
+ # has replied (Yes, this example could have been written using
59
+ # :left_participant => 'doug').
60
+ #
61
+ # == modes
62
+ #
63
+ # 'await', like 'listen' works in two mode, "once" and "multiple times".
64
+ #
65
+ # In the 'once' mode, the await expression blocks the flow until the workitem
66
+ # (somewhere else in the process instance) leaves the alice participant:
67
+ #
68
+ # sequence do
69
+ # await :left_participant => 'alice'
70
+ # participant 'eric'
71
+ # end
72
+ #
73
+ # In the 'multiple times' mode, the await expression triggers its children
74
+ # expressions each time a matching event occurs. It never replies to its
75
+ # parent expression. Here, the participant 'post_alice' will receive a
76
+ # workitem each time, somewhere else in the process
77
+ #
78
+ # await :left_participant => 'alice' do
79
+ # participant 'post_alice'
80
+ # end
81
+ #
82
+ # Note, that, unlike "listen" in previous versions of ruote, it's OK
83
+ # to consider the children of "await" as part of an implicit sequence:
84
+ #
85
+ # await :left_participant => 'alice' do
86
+ # participant 'bob'
87
+ # participant 'charly'
88
+ # end
89
+ #
90
+ # Bob and charly will be applied in sequence.
91
+ #
92
+ # == tag, participant or error events
93
+ #
94
+ # Await listens to 3 types of events: tag, participant and error events.
95
+ #
96
+ # Here is a assortment of examples:
97
+ #
98
+ # await :in_participant => 'alice'
99
+ # await :reached_participant => 'alice'
100
+ # await :out_participant => 'alice'
101
+ # await :left_participant => 'alice'
102
+ #
103
+ # await :participant => 'alice'
104
+ # await :participants => 'alice' # looks better with an array
105
+ #
106
+ # # implicit OR with arrays:
107
+ # #
108
+ # await :in_participant => /^al/
109
+ # await :in_participant => %w[ alice alfred ]
110
+ # await :in_participant => [ /^al/, /fred$/ ]
111
+ #
112
+ # await :in_tag => 'phase2'
113
+ # await :reached_tag => 'phase2'
114
+ # await :out_tag => 'phase2'
115
+ # await :left_tag => 'phase2'
116
+ #
117
+ # await :tags => 'phase2'
118
+ #
119
+ # await :error
120
+ # await :error => 'ArgumentError'
121
+ # await :error => 'RuntimeError, ArgumentError'
122
+ # await :error => %w[ RuntimeError ArgumentError ]
123
+ #
124
+ # Basically, the attribute is composed of a left part and a right part.
125
+ # The right part is one of "in", "reached" or "out", "left". "in" and
126
+ # "reached" are equivalent, as are "out" and "left".
127
+ #
128
+ # The right part is "tag" or "participant".
129
+ #
130
+ # "error" can be used alone.
131
+ #
132
+ # When "tags" and "participant(s)" are used alone, they are synonymous with
133
+ # "reached_tag" and "reached_participant" respectively.
134
+ #
135
+ # === absolute tags
136
+ #
137
+ # It's OK to specify absolute tags, like in:
138
+ #
139
+ # pdef = Ruote.define do
140
+ # concurrence do
141
+ # sequence do
142
+ # await :tag => 'a/b'
143
+ # echo 'a/b'
144
+ # end
145
+ # sequence :tag => 'a' do
146
+ # noop
147
+ # sequence :tag => 'b' do
148
+ # echo 'b'
149
+ # end
150
+ # end
151
+ # end
152
+ # end
153
+ #
154
+ # == :where condition
155
+ #
156
+ # The "await" expression accepts an optional attribute which adds another
157
+ # guard which is checked to determine if the trigger should occur or not.
158
+ #
159
+ # pdef = Ruote.process_definition do
160
+ # concurrence :wait_for => 1 do
161
+ # await :left_participant => 'a', :where => "${task} == 'sing'" do
162
+ # echo 'sing-a'
163
+ # end
164
+ # await :left_participant => 'a' do
165
+ # echo 'any-a'
166
+ # end
167
+ # concurrence do
168
+ # participant 'a', :task => 'talk'
169
+ # participant 'a', :task => 'sing'
170
+ # end
171
+ # end
172
+ # end
173
+ #
174
+ # In this example, the message 'sing-a' will be echoed only once (twice for
175
+ # 'any-a').
176
+ #
177
+ #
178
+ # == :global => false by default
179
+ #
180
+ # Unlike the 'listen' expression, 'await', by default, only triggers for
181
+ # events in the same process instance. To react on events whatever the
182
+ # process instance, :global => true (or "true") can be used.
183
+ #
184
+ # await :left_tag => 'phase1', :global => true do
185
+ # participant 'supervisor', :msg => 'phase1 over'
186
+ # end
187
+ #
188
+ #
189
+ # == :merge => nil/ignore
190
+ #
191
+ # In the listen expression, the default is for the event's workitem to
192
+ # get merged into the waiting workitem. With 'await', the default is
193
+ # the event's workitem completely overriding the awaiting workitem.
194
+ #
195
+ # Using the :merge attribute, other behaviours are possible.
196
+ #
197
+ # await :left_tag => 'phase3', :merge => 'ignore'
198
+ # await :left_tag => 'phase3', :merge => 'drop'
199
+ # # the event's workitem is ignored, the awaiting workitem is used
200
+ #
201
+ # await :left_tag => 'phase3', :merge => 'override'
202
+ # # the event's workitem is used, this is the default
203
+ #
204
+ # await :left_tag => 'phase3', :merge => 'incoming'
205
+ # # a hash merge happens, the incoming (event) workitem wins
206
+ # # workitem = awaiting.merge(incoming)
207
+ #
208
+ # await :left_tag => 'phase3', :merge => 'awaiting'
209
+ # # a hash merge happens, the awaiting workitem wins
210
+ # # workitem = incoming.merge(awaiting)
211
+ #
212
+ # Note: the :where guard is always about the event's workitem (not the
213
+ # workitem as it reached the 'await' expression).
214
+ #
215
+ class AwaitExpression < FlowExpression
216
+
217
+ names :await
218
+
219
+ INS = %w[ in entered reached]
220
+ OUTS = %w[ out left ]
221
+
222
+ SPLIT_R = /^(#{(INS + OUTS).join('|')})_(tag|participant)s?$/
223
+ SINGLE_R = /^(tag)s|(participant|error)s?$/ # not 'tag' alone
224
+
225
+ def apply
226
+
227
+ #
228
+ # gathering info
229
+
230
+ direction, type, value = attributes.collect { |k, v|
231
+ if m = SPLIT_R.match(k)
232
+ [ m[1], m[2], v ]
233
+ elsif m = SINGLE_R.match(k)
234
+ [ 'in', m[1] || m[2], v ]
235
+ else
236
+ nil
237
+ end
238
+ }.compact.first
239
+
240
+ raise ArgumentError.new(
241
+ "couldn't determine which event to listen to from: " +
242
+ attributes.inspect
243
+ ) unless direction
244
+
245
+ global = (attribute(:global).to_s == 'true')
246
+ global = false if type == 'error'
247
+
248
+ h.amerge = attribute(:merge).to_s
249
+
250
+ action = if type == 'tag'
251
+ INS.include?(direction) ? 'entered_tag' : 'left_tag'
252
+ elsif type == 'participant'
253
+ INS.include?(direction) ? 'dispatch' : 'receive'
254
+ else # error
255
+ 'error_intercepted'
256
+ end
257
+
258
+ persist_or_raise
259
+
260
+ #
261
+ # adding a new tracker
262
+
263
+ @context.tracker.add_tracker(
264
+ global ? nil : h.fei['wfid'],
265
+ action,
266
+ Ruote.to_storage_id(h.fei),
267
+ determine_condition(type, value),
268
+ { 'action' => 'reply',
269
+ 'fei' => h.fei,
270
+ 'workitem' => 'replace',
271
+ 'flavour' => 'await' })
272
+ end
273
+
274
+ def reply(workitem)
275
+
276
+ #
277
+ # :where guard
278
+
279
+ where = attribute(:where, workitem)
280
+ return if where && Condition.false?(where)
281
+
282
+ #
283
+ # merge
284
+
285
+ wi = h.applied_workitem.dup
286
+
287
+ wi['fields'] = case h.amerge
288
+ when 'ignore', 'drop' then wi['fields']
289
+ when 'incoming' then wi['fields'].merge(workitem['fields'])
290
+ when 'awaiting' then workitem['fields'].merge(wi['fields'])
291
+ else workitem['fields'] # 'override'
292
+ end
293
+
294
+ #
295
+ # actual trigger
296
+
297
+ if tree_children.any?
298
+
299
+ i, t = if tree_children.size == 1
300
+ [ "#{h.fei['expid']}_0", tree_children[0] ]
301
+ else
302
+ [ h.fei['expid'], [ 'sequence', {}, tree_children ] ]
303
+ end
304
+
305
+ launch_sub(i, t, :forget => true, :workitem => wi)
306
+
307
+ else
308
+
309
+ reply_to_parent(wi)
310
+ end
311
+ end
312
+
313
+ protected
314
+
315
+ # Overriding the parent's #reply_to_parent to make sure the tracker is
316
+ # removed before (expression terminating, no need for it to track anything
317
+ # anymore).
318
+ #
319
+ def reply_to_parent(workitem)
320
+
321
+ @context.tracker.remove_tracker(h.fei)
322
+
323
+ super(workitem)
324
+ end
325
+
326
+ # Matches Ruby class names, like "Ruote::ForcedError" or "::ArgumentError"
327
+ #
328
+ KLASS_R = /^(::)?([A-Z][a-z]+)+(::([A-Z][a-z]+)+)*$/
329
+
330
+ # Builds the condition used by the tracker service to filter msgs.
331
+ #
332
+ def determine_condition(type, value)
333
+
334
+ value = Ruote.comma_split(value)
335
+
336
+ if type == 'participant'
337
+
338
+ { 'participant_name' => value }
339
+
340
+ elsif type == 'error'
341
+
342
+ # array or comma string or string ?
343
+
344
+ h = { 'class' => [], 'message' => [] }
345
+
346
+ value.each { |e| (KLASS_R.match(e) ? h['class'] : h['message']) << e }
347
+
348
+ h.delete_if { |k, v| v == nil or v == [] }
349
+
350
+ else # 'tag'
351
+
352
+ { (value.first.to_s.match(/\//) ? 'full_tag' : 'tag') => value }
353
+ end
354
+ end
355
+ end
356
+ end
357
+