ruote 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+