ruote 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +166 -1
- data/CREDITS.txt +36 -17
- data/LICENSE.txt +1 -1
- data/README.rdoc +1 -7
- data/Rakefile +38 -29
- data/TODO.txt +93 -52
- data/lib/ruote-fs.rb +3 -0
- data/lib/ruote.rb +5 -1
- data/lib/ruote/context.rb +140 -35
- data/lib/ruote/dashboard.rb +1247 -0
- data/lib/ruote/{engine → dboard}/process_error.rb +22 -2
- data/lib/ruote/dboard/process_status.rb +587 -0
- data/lib/ruote/engine.rb +6 -871
- data/lib/ruote/exp/command.rb +7 -2
- data/lib/ruote/exp/commanded.rb +2 -2
- data/lib/ruote/exp/condition.rb +38 -13
- data/lib/ruote/exp/fe_add_branches.rb +1 -1
- data/lib/ruote/exp/fe_apply.rb +1 -1
- data/lib/ruote/exp/fe_await.rb +357 -0
- data/lib/ruote/exp/fe_cancel_process.rb +17 -3
- data/lib/ruote/exp/fe_command.rb +8 -4
- data/lib/ruote/exp/fe_concurrence.rb +218 -18
- data/lib/ruote/exp/fe_concurrent_iterator.rb +71 -10
- data/lib/ruote/exp/fe_cron.rb +3 -10
- data/lib/ruote/exp/fe_cursor.rb +14 -4
- data/lib/ruote/exp/fe_define.rb +3 -1
- data/lib/ruote/exp/fe_echo.rb +1 -1
- data/lib/ruote/exp/fe_equals.rb +1 -1
- data/lib/ruote/exp/fe_error.rb +1 -1
- data/lib/ruote/exp/fe_filter.rb +163 -4
- data/lib/ruote/exp/fe_forget.rb +21 -4
- data/lib/ruote/exp/fe_given.rb +1 -1
- data/lib/ruote/exp/fe_if.rb +1 -1
- data/lib/ruote/exp/fe_inc.rb +102 -35
- data/lib/ruote/exp/fe_iterator.rb +47 -12
- data/lib/ruote/exp/fe_listen.rb +96 -11
- data/lib/ruote/exp/fe_lose.rb +31 -4
- data/lib/ruote/exp/fe_noop.rb +1 -1
- data/lib/ruote/exp/fe_on_error.rb +109 -0
- data/lib/ruote/exp/fe_once.rb +10 -19
- data/lib/ruote/exp/fe_participant.rb +90 -28
- data/lib/ruote/exp/fe_read.rb +69 -0
- data/lib/ruote/exp/fe_redo.rb +3 -2
- data/lib/ruote/exp/fe_ref.rb +57 -27
- data/lib/ruote/exp/fe_registerp.rb +1 -3
- data/lib/ruote/exp/fe_reserve.rb +1 -1
- data/lib/ruote/exp/fe_restore.rb +6 -6
- data/lib/ruote/exp/fe_save.rb +12 -19
- data/lib/ruote/exp/fe_sequence.rb +38 -2
- data/lib/ruote/exp/fe_set.rb +143 -40
- data/lib/ruote/exp/{fe_let.rb → fe_stall.rb} +7 -38
- data/lib/ruote/exp/fe_subprocess.rb +8 -2
- data/lib/ruote/exp/fe_that.rb +1 -1
- data/lib/ruote/exp/fe_undo.rb +40 -4
- data/lib/ruote/exp/fe_unregisterp.rb +1 -3
- data/lib/ruote/exp/fe_wait.rb +12 -25
- data/lib/ruote/exp/{flowexpression.rb → flow_expression.rb} +375 -229
- data/lib/ruote/exp/iterator.rb +2 -2
- data/lib/ruote/exp/merge.rb +78 -17
- data/lib/ruote/exp/ro_attributes.rb +46 -36
- data/lib/ruote/exp/ro_filters.rb +34 -8
- data/lib/ruote/exp/ro_on_x.rb +431 -0
- data/lib/ruote/exp/ro_persist.rb +19 -7
- data/lib/ruote/exp/ro_timers.rb +123 -0
- data/lib/ruote/exp/ro_variables.rb +90 -29
- data/lib/ruote/fei.rb +57 -3
- data/lib/ruote/fs.rb +3 -0
- data/lib/ruote/id/mnemo_wfid_generator.rb +30 -7
- data/lib/ruote/id/wfid_generator.rb +17 -38
- data/lib/ruote/log/default_history.rb +23 -9
- data/lib/ruote/log/fancy_printing.rb +265 -0
- data/lib/ruote/log/storage_history.rb +23 -13
- data/lib/ruote/log/wait_logger.rb +224 -17
- data/lib/ruote/observer.rb +82 -0
- data/lib/ruote/part/block_participant.rb +65 -28
- data/lib/ruote/part/code_participant.rb +81 -0
- data/lib/ruote/part/engine_participant.rb +7 -2
- data/lib/ruote/part/local_participant.rb +221 -21
- data/lib/ruote/part/no_op_participant.rb +1 -1
- data/lib/ruote/part/null_participant.rb +1 -1
- data/lib/ruote/part/participant.rb +50 -0
- data/lib/ruote/part/rev_participant.rb +178 -0
- data/lib/ruote/part/smtp_participant.rb +2 -2
- data/lib/ruote/part/storage_participant.rb +228 -60
- data/lib/ruote/part/template.rb +1 -1
- data/lib/ruote/participant.rb +2 -0
- data/lib/ruote/reader.rb +205 -68
- data/lib/ruote/reader/json.rb +49 -0
- data/lib/ruote/reader/radial.rb +303 -0
- data/lib/ruote/reader/ruby_dsl.rb +44 -9
- data/lib/ruote/reader/xml.rb +11 -8
- data/lib/ruote/receiver/base.rb +98 -45
- data/lib/ruote/storage/base.rb +104 -35
- data/lib/ruote/storage/composite_storage.rb +50 -60
- data/lib/ruote/storage/fs_storage.rb +25 -34
- data/lib/ruote/storage/hash_storage.rb +38 -36
- data/lib/ruote/svc/dispatch_pool.rb +104 -35
- data/lib/ruote/svc/dollar_sub.rb +10 -8
- data/lib/ruote/svc/error_handler.rb +108 -52
- data/lib/ruote/svc/expression_map.rb +3 -3
- data/lib/ruote/svc/participant_list.rb +160 -55
- data/lib/ruote/svc/tracker.rb +31 -31
- data/lib/ruote/svc/treechecker.rb +28 -16
- data/lib/ruote/tree_dot.rb +1 -1
- data/lib/ruote/util/deep.rb +143 -0
- data/lib/ruote/util/filter.rb +125 -18
- data/lib/ruote/util/hashdot.rb +15 -13
- data/lib/ruote/util/look.rb +1 -1
- data/lib/ruote/util/lookup.rb +60 -22
- data/lib/ruote/util/misc.rb +63 -18
- data/lib/ruote/util/mpatch.rb +53 -0
- data/lib/ruote/util/ometa.rb +1 -2
- data/lib/ruote/util/process_observer.rb +177 -0
- data/lib/ruote/util/subprocess.rb +1 -1
- data/lib/ruote/util/time.rb +2 -2
- data/lib/ruote/util/tree.rb +64 -2
- data/lib/ruote/version.rb +3 -2
- data/lib/ruote/worker.rb +421 -92
- data/lib/ruote/workitem.rb +157 -22
- data/ruote.gemspec +15 -9
- data/test/bm/ci.rb +0 -2
- data/test/bm/ici.rb +0 -2
- data/test/bm/load_26c.rb +0 -3
- data/test/bm/mega.rb +0 -2
- data/test/functional/base.rb +57 -43
- data/test/functional/concurrent_base.rb +16 -13
- data/test/functional/ct_0_concurrence.rb +7 -11
- data/test/functional/ct_1_iterator.rb +9 -11
- data/test/functional/ct_2_cancel.rb +28 -17
- data/test/functional/eft_0_flow_expression.rb +35 -0
- data/test/functional/eft_10_cancel_process.rb +1 -1
- data/test/functional/eft_11_wait.rb +13 -13
- data/test/functional/eft_12_listen.rb +199 -66
- data/test/functional/eft_13_iterator.rb +95 -29
- data/test/functional/eft_14_cursor.rb +74 -24
- data/test/functional/eft_15_loop.rb +7 -7
- data/test/functional/eft_16_if.rb +1 -1
- data/test/functional/eft_17_equals.rb +1 -1
- data/test/functional/eft_18_concurrent_iterator.rb +156 -68
- data/test/functional/eft_19_reserve.rb +15 -15
- data/test/functional/eft_1_echo.rb +1 -1
- data/test/functional/eft_20_save.rb +51 -9
- data/test/functional/eft_21_restore.rb +1 -1
- data/test/functional/eft_22_noop.rb +1 -1
- data/test/functional/eft_23_apply.rb +1 -1
- data/test/functional/eft_24_add_branches.rb +7 -8
- data/test/functional/eft_25_command.rb +1 -1
- data/test/functional/eft_26_error.rb +11 -11
- data/test/functional/eft_27_inc.rb +111 -67
- data/test/functional/eft_28_once.rb +16 -16
- data/test/functional/eft_29_cron.rb +9 -9
- data/test/functional/eft_2_sequence.rb +23 -4
- data/test/functional/eft_30_ref.rb +36 -24
- data/test/functional/eft_31_registerp.rb +24 -24
- data/test/functional/eft_32_lose.rb +46 -20
- data/test/functional/eft_34_given.rb +1 -1
- data/test/functional/eft_35_filter.rb +161 -7
- data/test/functional/eft_36_read.rb +97 -0
- data/test/functional/{eft_0_process_definition.rb → eft_37_process_definition.rb} +4 -4
- data/test/functional/eft_38_on_error.rb +195 -0
- data/test/functional/eft_39_stall.rb +35 -0
- data/test/functional/eft_3_participant.rb +77 -22
- data/test/functional/eft_40_await.rb +297 -0
- data/test/functional/eft_4_set.rb +110 -11
- data/test/functional/eft_5_subprocess.rb +27 -5
- data/test/functional/eft_6_concurrence.rb +299 -60
- data/test/functional/eft_7_forget.rb +24 -22
- data/test/functional/eft_8_undo.rb +52 -15
- data/test/functional/eft_9_redo.rb +18 -20
- data/test/functional/ft_0_worker.rb +122 -13
- data/test/functional/ft_10_dollar.rb +77 -16
- data/test/functional/ft_11_recursion.rb +9 -9
- data/test/functional/ft_12_launchitem.rb +7 -9
- data/test/functional/ft_13_variables.rb +125 -22
- data/test/functional/ft_14_re_apply.rb +112 -56
- data/test/functional/ft_15_timeout.rb +64 -33
- data/test/functional/ft_16_participant_params.rb +59 -6
- data/test/functional/ft_17_conditional.rb +68 -2
- data/test/functional/ft_18_kill.rb +48 -30
- data/test/functional/ft_19_participant_code.rb +67 -0
- data/test/functional/ft_1_process_status.rb +222 -150
- data/test/functional/ft_20_storage_participant.rb +445 -44
- data/test/functional/ft_21_forget.rb +21 -26
- data/test/functional/ft_22_process_definitions.rb +8 -6
- data/test/functional/ft_23_load_defs.rb +29 -5
- data/test/functional/ft_24_block_participant.rb +199 -20
- data/test/functional/ft_25_receiver.rb +98 -46
- data/test/functional/ft_26_participant_rtimeout.rb +34 -26
- data/test/functional/ft_27_var_indirection.rb +40 -5
- data/test/functional/ft_28_null_noop_participants.rb +5 -5
- data/test/functional/ft_29_part_template.rb +2 -2
- data/test/functional/ft_2_errors.rb +106 -74
- data/test/functional/ft_30_smtp_participant.rb +7 -7
- data/test/functional/ft_31_part_blocking.rb +11 -11
- data/test/functional/ft_32_scope.rb +50 -0
- data/test/functional/ft_33_participant_subprocess_priority.rb +3 -3
- data/test/functional/ft_34_cursor_rewind.rb +14 -14
- data/test/functional/ft_35_add_service.rb +67 -9
- data/test/functional/ft_36_storage_history.rb +92 -24
- data/test/functional/ft_37_default_history.rb +35 -23
- data/test/functional/ft_38_participant_more.rb +189 -32
- data/test/functional/ft_39_wait_for.rb +25 -25
- data/test/functional/ft_3_participant_registration.rb +235 -107
- data/test/functional/ft_40_wait_logger.rb +105 -18
- data/test/functional/ft_41_participants.rb +13 -12
- data/test/functional/ft_42_storage_copy.rb +12 -12
- data/test/functional/ft_43_participant_on_reply.rb +85 -11
- data/test/functional/ft_44_var_participant.rb +5 -5
- data/test/functional/ft_45_participant_accept.rb +3 -3
- data/test/functional/ft_46_launch_single.rb +17 -17
- data/test/functional/ft_47_wfids.rb +41 -0
- data/test/functional/ft_48_lose.rb +19 -25
- data/test/functional/ft_49_engine_on_error.rb +54 -70
- data/test/functional/ft_4_cancel.rb +84 -26
- data/test/functional/ft_50_engine_config.rb +4 -4
- data/test/functional/ft_51_misc.rb +12 -12
- data/test/functional/ft_52_case.rb +17 -17
- data/test/functional/ft_53_engine_on_terminate.rb +18 -21
- data/test/functional/ft_54_patterns.rb +18 -16
- data/test/functional/ft_55_engine_participant.rb +55 -55
- data/test/functional/ft_56_filter_attribute.rb +90 -52
- data/test/functional/ft_57_rev_participant.rb +252 -0
- data/test/functional/ft_58_workitem.rb +150 -0
- data/test/functional/ft_59_pause.rb +329 -0
- data/test/functional/ft_5_on_error.rb +430 -77
- data/test/functional/ft_60_code_participant.rb +65 -0
- data/test/functional/ft_61_trailing_fields.rb +34 -0
- data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
- data/test/functional/ft_63_participants_221.rb +458 -0
- data/test/functional/ft_64_stash.rb +41 -0
- data/test/functional/ft_65_timers.rb +313 -0
- data/test/functional/ft_66_flank.rb +133 -0
- data/test/functional/ft_67_radial_misc.rb +34 -0
- data/test/functional/ft_68_reput.rb +72 -0
- data/test/functional/ft_69_worker_info.rb +56 -0
- data/test/functional/ft_6_on_cancel.rb +189 -36
- data/test/functional/ft_70_take_and_discard_attributes.rb +94 -0
- data/test/functional/ft_71_retries.rb +144 -0
- data/test/functional/ft_72_on_terminate.rb +60 -0
- data/test/functional/ft_73_raise_msg.rb +107 -0
- data/test/functional/ft_74_respark.rb +106 -0
- data/test/functional/ft_75_context.rb +66 -0
- data/test/functional/ft_76_observer.rb +53 -0
- data/test/functional/ft_77_process_observer.rb +157 -0
- data/test/functional/ft_78_part_participant.rb +37 -0
- data/test/functional/ft_7_tags.rb +238 -50
- data/test/functional/ft_8_participant_consumption.rb +27 -21
- data/test/functional/ft_9_subprocesses.rb +48 -18
- data/test/functional/restart_base.rb +4 -6
- data/test/functional/rt_0_wait.rb +10 -10
- data/test/functional/rt_1_listen.rb +6 -6
- data/test/functional/rt_2_errors.rb +12 -12
- data/test/functional/rt_3_once.rb +17 -12
- data/test/functional/rt_4_cron.rb +17 -17
- data/test/functional/rt_5_timeout.rb +13 -13
- data/test/functional/signals.rb +103 -0
- data/test/functional/storage.rb +730 -0
- data/test/functional/storage_helper.rb +48 -35
- data/test/functional/test.rb +6 -2
- data/test/misc/idle.rb +21 -0
- data/test/misc/light.rb +29 -0
- data/test/path_helper.rb +1 -1
- data/test/test.rb +2 -5
- data/test/test_helper.rb +13 -0
- data/test/unit/test.rb +1 -4
- data/test/unit/ut_0_ruby_reader.rb +25 -9
- data/test/unit/ut_10_participants.rb +47 -0
- data/test/unit/ut_11_lookup.rb +59 -2
- data/test/unit/ut_12_wait_logger.rb +123 -0
- data/test/unit/ut_14_is_uri.rb +1 -1
- data/test/unit/ut_15_util.rb +1 -1
- data/test/unit/ut_16_reader.rb +136 -14
- data/test/unit/ut_17_merge.rb +155 -0
- data/test/unit/ut_19_part_template.rb +1 -1
- data/test/unit/ut_1_fei.rb +11 -2
- data/test/unit/ut_20_composite_storage.rb +27 -1
- data/test/unit/{ut_21_participant_list.rb → ut_21_svc_participant_list.rb} +2 -3
- data/test/unit/ut_22_filter.rb +231 -10
- data/test/unit/ut_23_svc_tracker.rb +48 -0
- data/test/unit/ut_24_radial_reader.rb +458 -0
- data/test/unit/ut_25_process_status.rb +143 -0
- data/test/unit/ut_26_deep.rb +131 -0
- data/test/unit/ut_2_dashboard.rb +114 -0
- data/test/unit/ut_3_worker.rb +54 -0
- data/test/unit/ut_4_expmap.rb +1 -1
- data/test/unit/ut_5_tree.rb +23 -23
- data/test/unit/ut_6_condition.rb +71 -29
- data/test/unit/ut_7_workitem.rb +18 -4
- data/test/unit/ut_8_tree_to_dot.rb +1 -1
- data/test/unit/ut_9_xml_reader.rb +1 -1
- metadata +142 -63
- data/jruby_issue.txt +0 -32
- data/lib/ruote/engine/process_status.rb +0 -403
- data/lib/ruote/log/pretty.rb +0 -165
- data/lib/ruote/log/test_logger.rb +0 -204
- data/lib/ruote/util/serializer.rb +0 -103
- data/phil.txt +0 -14
- data/test/functional/eft_33_let.rb +0 -31
- data/test/functional/ft_19_alias.rb +0 -33
- data/test/functional/ft_47_wfid_generator.rb +0 -54
- data/test/unit/storage.rb +0 -403
- data/test/unit/storages.rb +0 -37
- data/test/unit/ut_13_serializer.rb +0 -65
- data/test/unit/ut_18_engine.rb +0 -47
- data/test/unit/ut_3_wait_logger.rb +0 -39
data/lib/ruote/exp/command.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
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
|
-
|
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
|
|
data/lib/ruote/exp/commanded.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
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
|
61
|
+
do_persist or return
|
62
62
|
|
63
63
|
@context.storage.put_msg('cancel', 'fei' => h.children.first)
|
64
64
|
|
data/lib/ruote/exp/condition.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
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
|
-
|
69
|
-
|
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
|
-
|
104
|
+
Ruote.parse_ruby(conditional)
|
99
105
|
|
100
|
-
rescue
|
106
|
+
rescue SyntaxError => se
|
101
107
|
|
102
|
-
|
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
|
-
|
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
|
-
|
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-
|
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
|
data/lib/ruote/exp/fe_apply.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2005-
|
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
|
+
|