ruote-maestrodev 2.2.1

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 (265) hide show
  1. data/CHANGELOG.txt +290 -0
  2. data/CREDITS.txt +99 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.rdoc +88 -0
  5. data/Rakefile +108 -0
  6. data/TODO.txt +488 -0
  7. data/lib/ruote.rb +7 -0
  8. data/lib/ruote/context.rb +194 -0
  9. data/lib/ruote/engine.rb +1062 -0
  10. data/lib/ruote/engine/process_error.rb +122 -0
  11. data/lib/ruote/engine/process_status.rb +448 -0
  12. data/lib/ruote/exp/command.rb +87 -0
  13. data/lib/ruote/exp/commanded.rb +69 -0
  14. data/lib/ruote/exp/condition.rb +227 -0
  15. data/lib/ruote/exp/fe_add_branches.rb +138 -0
  16. data/lib/ruote/exp/fe_apply.rb +154 -0
  17. data/lib/ruote/exp/fe_cancel_process.rb +78 -0
  18. data/lib/ruote/exp/fe_command.rb +156 -0
  19. data/lib/ruote/exp/fe_concurrence.rb +321 -0
  20. data/lib/ruote/exp/fe_concurrent_iterator.rb +219 -0
  21. data/lib/ruote/exp/fe_cron.rb +141 -0
  22. data/lib/ruote/exp/fe_cursor.rb +324 -0
  23. data/lib/ruote/exp/fe_define.rb +112 -0
  24. data/lib/ruote/exp/fe_echo.rb +60 -0
  25. data/lib/ruote/exp/fe_equals.rb +115 -0
  26. data/lib/ruote/exp/fe_error.rb +82 -0
  27. data/lib/ruote/exp/fe_filter.rb +648 -0
  28. data/lib/ruote/exp/fe_forget.rb +88 -0
  29. data/lib/ruote/exp/fe_given.rb +154 -0
  30. data/lib/ruote/exp/fe_if.rb +127 -0
  31. data/lib/ruote/exp/fe_inc.rb +205 -0
  32. data/lib/ruote/exp/fe_iterator.rb +234 -0
  33. data/lib/ruote/exp/fe_let.rb +75 -0
  34. data/lib/ruote/exp/fe_listen.rb +304 -0
  35. data/lib/ruote/exp/fe_lose.rb +110 -0
  36. data/lib/ruote/exp/fe_noop.rb +45 -0
  37. data/lib/ruote/exp/fe_once.rb +215 -0
  38. data/lib/ruote/exp/fe_participant.rb +287 -0
  39. data/lib/ruote/exp/fe_read.rb +69 -0
  40. data/lib/ruote/exp/fe_redo.rb +82 -0
  41. data/lib/ruote/exp/fe_ref.rb +152 -0
  42. data/lib/ruote/exp/fe_registerp.rb +110 -0
  43. data/lib/ruote/exp/fe_reserve.rb +126 -0
  44. data/lib/ruote/exp/fe_restore.rb +102 -0
  45. data/lib/ruote/exp/fe_save.rb +72 -0
  46. data/lib/ruote/exp/fe_sequence.rb +59 -0
  47. data/lib/ruote/exp/fe_set.rb +154 -0
  48. data/lib/ruote/exp/fe_subprocess.rb +211 -0
  49. data/lib/ruote/exp/fe_that.rb +92 -0
  50. data/lib/ruote/exp/fe_undo.rb +67 -0
  51. data/lib/ruote/exp/fe_unregisterp.rb +69 -0
  52. data/lib/ruote/exp/fe_wait.rb +95 -0
  53. data/lib/ruote/exp/flowexpression.rb +886 -0
  54. data/lib/ruote/exp/iterator.rb +81 -0
  55. data/lib/ruote/exp/merge.rb +118 -0
  56. data/lib/ruote/exp/ro_attributes.rb +212 -0
  57. data/lib/ruote/exp/ro_filters.rb +136 -0
  58. data/lib/ruote/exp/ro_persist.rb +154 -0
  59. data/lib/ruote/exp/ro_variables.rb +189 -0
  60. data/lib/ruote/exp/ro_vf.rb +68 -0
  61. data/lib/ruote/fei.rb +260 -0
  62. data/lib/ruote/id/mnemo_wfid_generator.rb +43 -0
  63. data/lib/ruote/id/wfid_generator.rb +81 -0
  64. data/lib/ruote/log/default_history.rb +122 -0
  65. data/lib/ruote/log/pretty.rb +176 -0
  66. data/lib/ruote/log/storage_history.rb +159 -0
  67. data/lib/ruote/log/test_logger.rb +208 -0
  68. data/lib/ruote/log/wait_logger.rb +64 -0
  69. data/lib/ruote/part/block_participant.rb +137 -0
  70. data/lib/ruote/part/code_participant.rb +81 -0
  71. data/lib/ruote/part/engine_participant.rb +189 -0
  72. data/lib/ruote/part/local_participant.rb +138 -0
  73. data/lib/ruote/part/no_op_participant.rb +60 -0
  74. data/lib/ruote/part/null_participant.rb +54 -0
  75. data/lib/ruote/part/rev_participant.rb +169 -0
  76. data/lib/ruote/part/smtp_participant.rb +116 -0
  77. data/lib/ruote/part/storage_participant.rb +392 -0
  78. data/lib/ruote/part/template.rb +84 -0
  79. data/lib/ruote/participant.rb +7 -0
  80. data/lib/ruote/reader.rb +278 -0
  81. data/lib/ruote/reader/json.rb +49 -0
  82. data/lib/ruote/reader/radial.rb +290 -0
  83. data/lib/ruote/reader/ruby_dsl.rb +186 -0
  84. data/lib/ruote/reader/xml.rb +99 -0
  85. data/lib/ruote/receiver/base.rb +212 -0
  86. data/lib/ruote/storage/base.rb +364 -0
  87. data/lib/ruote/storage/composite_storage.rb +121 -0
  88. data/lib/ruote/storage/fs_storage.rb +139 -0
  89. data/lib/ruote/storage/hash_storage.rb +211 -0
  90. data/lib/ruote/svc/dispatch_pool.rb +158 -0
  91. data/lib/ruote/svc/dollar_sub.rb +298 -0
  92. data/lib/ruote/svc/error_handler.rb +138 -0
  93. data/lib/ruote/svc/expression_map.rb +97 -0
  94. data/lib/ruote/svc/participant_list.rb +397 -0
  95. data/lib/ruote/svc/tracker.rb +172 -0
  96. data/lib/ruote/svc/treechecker.rb +141 -0
  97. data/lib/ruote/tree_dot.rb +85 -0
  98. data/lib/ruote/util/filter.rb +525 -0
  99. data/lib/ruote/util/hashdot.rb +79 -0
  100. data/lib/ruote/util/look.rb +128 -0
  101. data/lib/ruote/util/lookup.rb +127 -0
  102. data/lib/ruote/util/misc.rb +167 -0
  103. data/lib/ruote/util/ometa.rb +71 -0
  104. data/lib/ruote/util/serializer.rb +103 -0
  105. data/lib/ruote/util/subprocess.rb +88 -0
  106. data/lib/ruote/util/time.rb +100 -0
  107. data/lib/ruote/util/tree.rb +58 -0
  108. data/lib/ruote/version.rb +29 -0
  109. data/lib/ruote/worker.rb +386 -0
  110. data/lib/ruote/workitem.rb +394 -0
  111. data/phil.txt +14 -0
  112. data/ruote.gemspec +44 -0
  113. data/test/bm/ci.rb +55 -0
  114. data/test/bm/ici.rb +71 -0
  115. data/test/bm/juuman.rb +54 -0
  116. data/test/bm/launch_bench.rb +37 -0
  117. data/test/bm/load_26c.rb +97 -0
  118. data/test/bm/mega.rb +64 -0
  119. data/test/bm/seq_thousand.rb +31 -0
  120. data/test/bm/t.rb +35 -0
  121. data/test/functional/base.rb +247 -0
  122. data/test/functional/concurrent_base.rb +98 -0
  123. data/test/functional/crunner.rb +31 -0
  124. data/test/functional/ct_0_concurrence.rb +65 -0
  125. data/test/functional/ct_1_iterator.rb +67 -0
  126. data/test/functional/ct_2_cancel.rb +81 -0
  127. data/test/functional/eft_0_process_definition.rb +65 -0
  128. data/test/functional/eft_10_cancel_process.rb +46 -0
  129. data/test/functional/eft_11_wait.rb +109 -0
  130. data/test/functional/eft_12_listen.rb +500 -0
  131. data/test/functional/eft_13_iterator.rb +342 -0
  132. data/test/functional/eft_14_cursor.rb +456 -0
  133. data/test/functional/eft_15_loop.rb +69 -0
  134. data/test/functional/eft_16_if.rb +183 -0
  135. data/test/functional/eft_17_equals.rb +55 -0
  136. data/test/functional/eft_18_concurrent_iterator.rb +410 -0
  137. data/test/functional/eft_19_reserve.rb +136 -0
  138. data/test/functional/eft_1_echo.rb +68 -0
  139. data/test/functional/eft_20_save.rb +116 -0
  140. data/test/functional/eft_21_restore.rb +61 -0
  141. data/test/functional/eft_22_noop.rb +28 -0
  142. data/test/functional/eft_23_apply.rb +168 -0
  143. data/test/functional/eft_24_add_branches.rb +98 -0
  144. data/test/functional/eft_25_command.rb +28 -0
  145. data/test/functional/eft_26_error.rb +77 -0
  146. data/test/functional/eft_27_inc.rb +280 -0
  147. data/test/functional/eft_28_once.rb +135 -0
  148. data/test/functional/eft_29_cron.rb +64 -0
  149. data/test/functional/eft_2_sequence.rb +58 -0
  150. data/test/functional/eft_30_ref.rb +155 -0
  151. data/test/functional/eft_31_registerp.rb +130 -0
  152. data/test/functional/eft_32_lose.rb +93 -0
  153. data/test/functional/eft_33_let.rb +31 -0
  154. data/test/functional/eft_34_given.rb +123 -0
  155. data/test/functional/eft_35_filter.rb +375 -0
  156. data/test/functional/eft_36_read.rb +95 -0
  157. data/test/functional/eft_3_participant.rb +149 -0
  158. data/test/functional/eft_4_set.rb +296 -0
  159. data/test/functional/eft_5_subprocess.rb +163 -0
  160. data/test/functional/eft_6_concurrence.rb +304 -0
  161. data/test/functional/eft_7_forget.rb +61 -0
  162. data/test/functional/eft_8_undo.rb +114 -0
  163. data/test/functional/eft_9_redo.rb +138 -0
  164. data/test/functional/ft_0_worker.rb +65 -0
  165. data/test/functional/ft_10_dollar.rb +304 -0
  166. data/test/functional/ft_11_recursion.rb +109 -0
  167. data/test/functional/ft_12_launchitem.rb +43 -0
  168. data/test/functional/ft_13_variables.rb +151 -0
  169. data/test/functional/ft_14_re_apply.rb +324 -0
  170. data/test/functional/ft_15_timeout.rb +226 -0
  171. data/test/functional/ft_16_participant_params.rb +98 -0
  172. data/test/functional/ft_17_conditional.rb +102 -0
  173. data/test/functional/ft_18_kill.rb +138 -0
  174. data/test/functional/ft_19_participant_code.rb +67 -0
  175. data/test/functional/ft_1_process_status.rb +796 -0
  176. data/test/functional/ft_20_storage_participant.rb +543 -0
  177. data/test/functional/ft_21_forget.rb +153 -0
  178. data/test/functional/ft_22_process_definitions.rb +90 -0
  179. data/test/functional/ft_23_load_defs.rb +79 -0
  180. data/test/functional/ft_24_block_participant.rb +235 -0
  181. data/test/functional/ft_25_receiver.rb +207 -0
  182. data/test/functional/ft_26_participant_rtimeout.rb +179 -0
  183. data/test/functional/ft_27_var_indirection.rb +128 -0
  184. data/test/functional/ft_28_null_noop_participants.rb +51 -0
  185. data/test/functional/ft_29_part_template.rb +60 -0
  186. data/test/functional/ft_2_errors.rb +380 -0
  187. data/test/functional/ft_30_smtp_participant.rb +122 -0
  188. data/test/functional/ft_31_part_blocking.rb +72 -0
  189. data/test/functional/ft_33_participant_subprocess_priority.rb +32 -0
  190. data/test/functional/ft_34_cursor_rewind.rb +101 -0
  191. data/test/functional/ft_35_add_service.rb +56 -0
  192. data/test/functional/ft_36_storage_history.rb +150 -0
  193. data/test/functional/ft_37_default_history.rb +109 -0
  194. data/test/functional/ft_38_participant_more.rb +193 -0
  195. data/test/functional/ft_39_wait_for.rb +136 -0
  196. data/test/functional/ft_3_participant_registration.rb +574 -0
  197. data/test/functional/ft_40_wait_logger.rb +62 -0
  198. data/test/functional/ft_41_participants.rb +91 -0
  199. data/test/functional/ft_42_storage_copy.rb +71 -0
  200. data/test/functional/ft_43_participant_on_reply.rb +87 -0
  201. data/test/functional/ft_44_var_participant.rb +35 -0
  202. data/test/functional/ft_45_participant_accept.rb +64 -0
  203. data/test/functional/ft_46_launch_single.rb +83 -0
  204. data/test/functional/ft_47_wfid_generator.rb +54 -0
  205. data/test/functional/ft_48_lose.rb +112 -0
  206. data/test/functional/ft_49_engine_on_error.rb +201 -0
  207. data/test/functional/ft_4_cancel.rb +132 -0
  208. data/test/functional/ft_50_engine_config.rb +22 -0
  209. data/test/functional/ft_51_misc.rb +67 -0
  210. data/test/functional/ft_52_case.rb +134 -0
  211. data/test/functional/ft_53_engine_on_terminate.rb +95 -0
  212. data/test/functional/ft_54_patterns.rb +104 -0
  213. data/test/functional/ft_55_engine_participant.rb +303 -0
  214. data/test/functional/ft_56_filter_attribute.rb +259 -0
  215. data/test/functional/ft_57_rev_participant.rb +252 -0
  216. data/test/functional/ft_58_workitem.rb +69 -0
  217. data/test/functional/ft_59_pause.rb +343 -0
  218. data/test/functional/ft_5_on_error.rb +384 -0
  219. data/test/functional/ft_60_code_participant.rb +45 -0
  220. data/test/functional/ft_61_trailing_fields.rb +34 -0
  221. data/test/functional/ft_62_exp_name_and_dollar_substitution.rb +35 -0
  222. data/test/functional/ft_6_on_cancel.rb +221 -0
  223. data/test/functional/ft_7_tags.rb +177 -0
  224. data/test/functional/ft_8_participant_consumption.rb +124 -0
  225. data/test/functional/ft_9_subprocesses.rb +146 -0
  226. data/test/functional/restart_base.rb +34 -0
  227. data/test/functional/rt_0_wait.rb +55 -0
  228. data/test/functional/rt_1_listen.rb +56 -0
  229. data/test/functional/rt_2_errors.rb +56 -0
  230. data/test/functional/rt_3_once.rb +70 -0
  231. data/test/functional/rt_4_cron.rb +64 -0
  232. data/test/functional/rt_5_timeout.rb +60 -0
  233. data/test/functional/rtest.rb +8 -0
  234. data/test/functional/storage_helper.rb +93 -0
  235. data/test/functional/test.rb +44 -0
  236. data/test/functional/vertical.rb +46 -0
  237. data/test/path_helper.rb +15 -0
  238. data/test/test.rb +13 -0
  239. data/test/test_helper.rb +28 -0
  240. data/test/unit/storage.rb +428 -0
  241. data/test/unit/storages.rb +37 -0
  242. data/test/unit/test.rb +28 -0
  243. data/test/unit/ut_0_ruby_reader.rb +223 -0
  244. data/test/unit/ut_11_lookup.rb +122 -0
  245. data/test/unit/ut_13_serializer.rb +65 -0
  246. data/test/unit/ut_14_is_uri.rb +28 -0
  247. data/test/unit/ut_15_util.rb +57 -0
  248. data/test/unit/ut_16_reader.rb +225 -0
  249. data/test/unit/ut_18_engine.rb +47 -0
  250. data/test/unit/ut_19_part_template.rb +86 -0
  251. data/test/unit/ut_1_fei.rb +165 -0
  252. data/test/unit/ut_20_composite_storage.rb +74 -0
  253. data/test/unit/ut_21_svc_participant_list.rb +46 -0
  254. data/test/unit/ut_22_filter.rb +1094 -0
  255. data/test/unit/ut_23_svc_tracker.rb +48 -0
  256. data/test/unit/ut_24_radial_reader.rb +332 -0
  257. data/test/unit/ut_25_merge.rb +113 -0
  258. data/test/unit/ut_3_wait_logger.rb +39 -0
  259. data/test/unit/ut_4_expmap.rb +20 -0
  260. data/test/unit/ut_5_tree.rb +54 -0
  261. data/test/unit/ut_6_condition.rb +303 -0
  262. data/test/unit/ut_7_workitem.rb +99 -0
  263. data/test/unit/ut_8_tree_to_dot.rb +72 -0
  264. data/test/unit/ut_9_xml_reader.rb +61 -0
  265. metadata +504 -0
@@ -0,0 +1,84 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, 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
+ require 'rufus/json'
26
+
27
+
28
+ module Ruote
29
+
30
+ #
31
+ # Template rendering helper.
32
+ #
33
+ # (Currently only used by the SmtpParticipant, could prove useful for
34
+ # custom participants)
35
+ #
36
+ # This module expects to find the ruote @context available (probably
37
+ # accessible thanks to the Ruote::LocalParticipant module, see
38
+ # Ruote::SmtpParticipant as an example).
39
+ #
40
+ module TemplateMixin
41
+
42
+ # Do the rendering.
43
+ #
44
+ def render_template(template, flow_expression, workitem)
45
+
46
+ template = (File.read(template) rescue nil) if is_a_file?(template)
47
+
48
+ return render_default_template(workitem) unless template
49
+
50
+ template = template.to_s
51
+ workitem = workitem.to_h if workitem.respond_to?(:to_h)
52
+
53
+ @context.dollar_sub.s(template, flow_expression, workitem)
54
+ end
55
+
56
+ # Simply returns a pretty-printed view of the workitem
57
+ #
58
+ def render_default_template(workitem)
59
+
60
+ workitem = workitem.to_h if workitem.respond_to?(:to_h)
61
+
62
+ s = []
63
+ s << "workitem for #{workitem['participant_name']}"
64
+ s << ''
65
+ s << Rufus::Json.pretty_encode(workitem['fei'])
66
+ s << ''
67
+ workitem['fields'].keys.sort.each do |key|
68
+ s << " - '#{key}' ==> #{Rufus::Json.encode(workitem['fields'][key])}"
69
+ end
70
+ s.join("\n")
71
+ end
72
+
73
+ protected
74
+
75
+ def is_a_file?(s)
76
+
77
+ return false unless s
78
+ return false if s.index("\n")
79
+
80
+ File.exist?(s)
81
+ end
82
+ end
83
+ end
84
+
@@ -0,0 +1,7 @@
1
+
2
+ require 'ruote/part/storage_participant'
3
+ require 'ruote/part/no_op_participant'
4
+ require 'ruote/part/null_participant'
5
+ require 'ruote/part/engine_participant'
6
+ require 'ruote/part/rev_participant'
7
+
@@ -0,0 +1,278 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, 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 'uri'
27
+ require 'open-uri'
28
+ require 'rufus/json'
29
+ require 'ruote/reader/xml'
30
+ require 'ruote/reader/json'
31
+ require 'ruote/reader/radial'
32
+ require 'ruote/reader/ruby_dsl' # just making sure it's loaded
33
+ require 'ruote/util/subprocess'
34
+
35
+
36
+ module Ruote
37
+
38
+ #
39
+ # A process definition reader.
40
+ #
41
+ # Can reader XML, JSON, Ruby (and more) process definition representations.
42
+ #
43
+ class Reader
44
+
45
+ # This error is emitted by the reader when it failed to read a process
46
+ # definition (passed as a string).
47
+ #
48
+ class Error < ArgumentError
49
+
50
+ attr_reader :definition
51
+ attr_reader :ruby, :radial, :xml, :json
52
+
53
+ def initialize(definition)
54
+ @definition = definition
55
+ end
56
+
57
+ def <<(args)
58
+ type, error = args
59
+ type = type.to_s.match(/^Ruote::(.+)Reader$/)[1].downcase
60
+ instance_variable_set("@#{type}", error)
61
+ end
62
+
63
+ # Returns the most likely error cause...
64
+ #
65
+ def cause
66
+ @ruby || @radial || @xml || @json
67
+ end
68
+
69
+ def inspect
70
+ s = "#<#{self.class}: "
71
+ [ @ruby, @radial, @xml, @json ].each { |e| s << e.inspect; s << ' ' }
72
+ s << '>'
73
+ s
74
+ end
75
+ end
76
+
77
+ def initialize(context)
78
+
79
+ @context = context
80
+ end
81
+
82
+ # Turns the input into a ruote syntax tree (raw process definition).
83
+ # This method is used by engine.launch(x) for example.
84
+ #
85
+ def read(definition)
86
+
87
+ return definition if Ruote.is_tree?(definition)
88
+
89
+ raise ArgumentError.new(
90
+ "cannot read process definitions of class #{definition.class}"
91
+ ) unless definition.is_a?(String)
92
+
93
+ if is_uri?(definition)
94
+
95
+ raise ArgumentError.new(
96
+ "remote process definitions are not allowed"
97
+ ) if Ruote::Reader.remote?(definition) && @context['remote_definition_allowed'] != true
98
+
99
+ return read(open(definition).read)
100
+ end
101
+
102
+ tree = nil
103
+ error = Error.new(definition)
104
+
105
+ [
106
+ Ruote::RubyReader, Ruote::RadialReader,
107
+ Ruote::XmlReader, Ruote::JsonReader
108
+ ].each do |reader|
109
+
110
+ next if tree
111
+ next unless reader.understands?(definition)
112
+
113
+ begin
114
+ tree = reader.read(definition, @context.treechecker)
115
+ rescue => e
116
+ error << [ reader, e ]
117
+ end
118
+ end
119
+
120
+ tree || raise(error)
121
+ end
122
+
123
+ # Class method for parsing process definition (XML, Ruby, from file or
124
+ # from a string, ...) to syntax trees. Used by ruote-fluo for example.
125
+ #
126
+ def self.read(d)
127
+
128
+ unless @reader
129
+
130
+ require 'ostruct'
131
+ require 'ruote/svc/treechecker'
132
+
133
+ @reader = Ruote::Reader.new(
134
+ OpenStruct.new('treechecker' => Ruote::TreeChecker.new({})))
135
+ end
136
+
137
+ @reader.read(d)
138
+ end
139
+
140
+ # Turns the given process definition tree (ruote syntax tree) to an XML
141
+ # String.
142
+ #
143
+ # Mainly used by ruote-fluo.
144
+ #
145
+ def self.to_xml(tree, options={})
146
+
147
+ require 'builder'
148
+
149
+ # TODO : deal with "participant 'toto'"
150
+
151
+ builder(options) do |xml|
152
+
153
+ atts = tree[1].dup
154
+
155
+ t = atts.find { |k, v| v == nil }
156
+ if t
157
+ atts.delete(t.first)
158
+ key = tree[0] == 'if' ? 'test' : 'ref'
159
+ atts[key] = t.first
160
+ end
161
+
162
+ atts = atts.inject({}) { |h, (k, v)| h[k.to_s.gsub(/\_/, '-')] = v; h }
163
+
164
+ if tree[2].empty?
165
+ xml.tag!(tree[0], atts)
166
+ else
167
+ xml.tag!(tree[0], atts) do
168
+ tree[2].each { |child| to_xml(child, options) }
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ # Turns the given process definition tree (ruote syntax tree) to a Ruby
175
+ # process definition (a String containing that ruby process definition).
176
+ #
177
+ # Mainly used by ruote-fluo.
178
+ #
179
+ def self.to_ruby(tree, level=0)
180
+
181
+ expname = tree[0]
182
+ expname = 'Ruote.process_definition' if level == 0 && expname == 'define'
183
+
184
+ s =
185
+ ' ' * level +
186
+ expname +
187
+ atts_to_x(tree[1]) { |k, v|
188
+ ":#{k} => #{v.inspect}"
189
+ }
190
+
191
+ return "#{s}\n" if tree[2].empty?
192
+
193
+ s << " do\n"
194
+ tree[2].each { |child| s << to_ruby(child, level + 1) }
195
+ s << "#{' ' * level}end\n"
196
+
197
+ s
198
+ end
199
+
200
+ def self.to_radial(tree, level=0)
201
+
202
+ s =
203
+ ' ' * level +
204
+ tree[0] +
205
+ atts_to_x(tree[1]) { |k, v|
206
+ "#{k}: #{v.inspect}"
207
+ }
208
+
209
+ return "#{s}\n" if tree[2].empty?
210
+
211
+ s << "\n"
212
+ tree[2].each { |child| s << to_radial(child, level + 1) }
213
+
214
+ s
215
+ end
216
+
217
+ # Turns the process definition tree (ruote syntax tree) to a JSON String.
218
+ #
219
+ def self.to_json(tree)
220
+
221
+ tree.to_json
222
+ end
223
+
224
+ # Returns true if the defintion is a remote URI
225
+ #
226
+ def self.remote?(definition)
227
+
228
+ u = URI.parse(definition)
229
+
230
+ (u.scheme != nil) && ( ! ('A'..'Z').include?(u.scheme))
231
+ end
232
+
233
+ protected
234
+
235
+ # Minimal test. Used by #read.
236
+ #
237
+ def is_uri?(s)
238
+
239
+ return false if s.index("\n")
240
+
241
+ ((URI.parse(s); true) rescue false)
242
+ end
243
+
244
+ # A convenience method when building XML
245
+ #
246
+ def self.builder(options={}, &block)
247
+
248
+ if b = options[:builder]
249
+ block.call(b)
250
+ else
251
+ b = Builder::XmlMarkup.new(:indent => (options[:indent] || 0))
252
+ options[:builder] = b
253
+ b.instruct! unless options[:instruct] == false
254
+ block.call(b)
255
+ b.target!
256
+ end
257
+ end
258
+
259
+ # As used by to_ruby and to_radial
260
+ #
261
+ def self.atts_to_x(atts, &block)
262
+
263
+ s = []
264
+
265
+ t = atts.find { |k, v| v == nil }
266
+ s << t.first.inspect if t
267
+
268
+ s = atts.inject(s) { |a, (k, v)|
269
+ #a << ":#{k} => #{v.inspect}" if t.nil? || k != t.first
270
+ a << block.call(k, v) if t.nil? || k != t.first
271
+ a
272
+ }.join(', ')
273
+
274
+ s.length > 0 ? " #{s}" : s
275
+ end
276
+ end
277
+ end
278
+
@@ -0,0 +1,49 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, 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
+ module Ruote
27
+
28
+ #
29
+ # Turns an XML string into a process definition tree.
30
+ #
31
+ module JsonReader
32
+
33
+ # Returns true if s seems to be a JSON string
34
+ #
35
+ def self.understands?(s)
36
+
37
+ s = s.strip
38
+ true
39
+ end
40
+
41
+ # Simply parses the JSON string
42
+ #
43
+ def self.read(s, opt=nil)
44
+
45
+ Rufus::Json.decode(s)
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,290 @@
1
+ #--
2
+ # Copyright (c) 2005-2011, 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
+ require 'parslet'
26
+
27
+
28
+ module Ruote
29
+
30
+ #
31
+ # Turning radial strings into ruote trees.
32
+ #
33
+ module RadialReader
34
+
35
+ #
36
+ # Turns radial strings into intermediate trees.
37
+ #
38
+ class Parser < Parslet::Parser
39
+
40
+ rule(:spaces) {
41
+ match('\s').repeat >>
42
+ (str('#') >> match('[^\n]').repeat >> str("\n").present?).maybe >>
43
+ match('\s').repeat
44
+ }
45
+ rule(:spaces?) { spaces.maybe }
46
+
47
+ rule(:comma) { spaces? >> str(',') >> spaces? }
48
+ rule(:digit) { match('[0-9]') }
49
+
50
+ rule(:text) { match('[^\s:,=\[\]\{\}#]').repeat(1).as(:text) }
51
+
52
+ rule(:number) {
53
+ (
54
+ str('-').maybe >> (
55
+ str('0') | (match('[1-9]') >> digit.repeat)
56
+ ) >> (
57
+ str('.') >> digit.repeat(1)
58
+ ).maybe >> (
59
+ match('[eE]') >> (str('+') | str('-')).maybe >> digit.repeat(1)
60
+ ).maybe
61
+ ).as(:number) >> match('[ \n,]').present?
62
+ }
63
+
64
+ rule(:string) {
65
+ str('"') >> (
66
+ str('\\') >> any | str('"').absent? >> any
67
+ ).repeat.as(:string) >> str('"') |
68
+ str("'") >> (
69
+ str('\\') >> any | str("'").absent? >> any
70
+ ).repeat.as(:string) >> str("'")
71
+ }
72
+
73
+ rule(:array) {
74
+ str('[') >> spaces? >>
75
+ (value >> (comma >> value).repeat).maybe.as(:array) >>
76
+ spaces? >> str(']')
77
+ }
78
+
79
+ rule(:object) {
80
+ str('{') >> spaces? >>
81
+ (entry >> (comma >> entry).repeat).maybe.as(:object) >>
82
+ spaces? >> str('}')
83
+ }
84
+
85
+ rule(:value) {
86
+ array | object |
87
+ string | number |
88
+ str('true').as(:true) | str('false').as(:false) |
89
+ str('null').as(:nil) | str('nil').as(:nil) |
90
+ text
91
+ }
92
+
93
+ rule(:entry) {
94
+ ((string | text).as(:key) >> spaces? >>
95
+ (str(':') | str('=>')) >> spaces? >>
96
+ value.as(:val)).as(:ent)
97
+ }
98
+
99
+ rule(:attribute) { (entry | value).as(:att) }
100
+
101
+ rule(:blanks) { match('[ \t]').repeat(1) }
102
+
103
+ rule(:blank_line) { blanks.maybe }
104
+ rule(:line) {
105
+ (
106
+ str(' ').repeat.as(:ind) >>
107
+ match('[^ \n#"\']').repeat(1).as(:exp) >>
108
+ (blanks >> attribute >> (comma >> attribute).repeat).as(:atts).maybe
109
+ ).as(:line)
110
+ }
111
+
112
+ rule(:comment) {
113
+ str(' ').repeat >>
114
+ (str('#') >> match('[^\n]').repeat).maybe >>
115
+ str("\n").present?
116
+ }
117
+
118
+ rule(:lines) {
119
+ (str("\n") >> (line | blank_line) >> comment.maybe).repeat
120
+ }
121
+
122
+ root(:lines)
123
+ end
124
+
125
+ #
126
+ # A helper class to store the temporary tree while it gets read.
127
+ #
128
+ class Node
129
+
130
+ attr_reader :parent, :indentation, :children
131
+
132
+ def initialize(indentation, expname, attributes)
133
+
134
+ @parent = nil
135
+ @indentation = indentation
136
+ @children = []
137
+
138
+ @expname = expname.gsub(/-/, '_')
139
+ @attributes = attributes
140
+ end
141
+
142
+ def parent=(node)
143
+
144
+ @parent = node
145
+ @parent.children << self
146
+ end
147
+
148
+ def to_a
149
+
150
+ [ @expname, @attributes, @children.collect { |c| c.to_a } ]
151
+ end
152
+ end
153
+
154
+ #
155
+ # Turns intermediate trees into ruote trees.
156
+ #
157
+ class Transformer < Parslet::Transform
158
+
159
+ class Attribute
160
+ attr_reader :key, :val
161
+ def initialize(key, val)
162
+ @key = key.to_s.gsub(/-/, '_')
163
+ @val = val
164
+ end
165
+ end
166
+ class Value < Attribute
167
+ def initialize(key)
168
+ @key = key
169
+ @val = nil
170
+ end
171
+ end
172
+
173
+ rule(:line => subtree(:line)) { line }
174
+
175
+ rule(:ind => simple(:i), :exp => simple(:e), :atts => subtree(:as)) {
176
+ atts = Array(as).inject({}) { |h, att| h[att.key] = att.val; h }
177
+ Node.new(i.to_s.length, e.to_s, atts)
178
+ }
179
+ rule(:ind => simple(:i), :exp => simple(:e)) {
180
+ Node.new(i.to_s.length, e.to_s, {})
181
+ }
182
+ rule(:ind => sequence(:i), :exp => simple(:e), :atts => subtree(:as)) {
183
+ atts = Array(as).inject({}) { |h, att| h[att.key] = att.val; h }
184
+ Node.new(0, e.to_s, atts)
185
+ }
186
+ rule(:ind => sequence(:i), :exp => simple(:e)) {
187
+ Node.new(0, e.to_s, {})
188
+ }
189
+
190
+ rule(:att => { :ent => { :key => subtree(:k), :val => subtree(:v) } }) {
191
+ Attribute.new(k, v)
192
+ }
193
+ rule(:att => subtree(:t)) {
194
+ Value.new(t)
195
+ }
196
+
197
+ rule(:text => simple(:te)) { te.to_s }
198
+ rule(:string => simple(:st)) { st.to_s }
199
+ rule(:number => simple(:n)) { n.match(/[eE\.]/) ? Float(n) : Integer(n) }
200
+ rule(:false => simple(:b)) { false }
201
+ rule(:true => simple(:b)) { true }
202
+ rule(:nil => simple(:n)) { nil }
203
+
204
+ rule(:array => subtree(:ar)) {
205
+ ar.is_a?(Array) ? ar : [ ar ]
206
+ }
207
+ rule(:object => subtree(:es)) {
208
+ (es.is_a?(Array) ? es : [ es ]).inject({}) { |h, e|
209
+ e = e[:ent]; h[e[:key]] = e[:val]; h
210
+ }
211
+ }
212
+ end
213
+
214
+ #
215
+ # Some kind of "root container", to avoid having to deal with nils
216
+ # and making the parsing code more complicated (hopefully).
217
+ #
218
+ class PreRoot < Node
219
+
220
+ def initialize(first_line)
221
+
222
+ @first_line = first_line
223
+
224
+ @parent = nil
225
+ @indentation = -1
226
+ @children = []
227
+ end
228
+
229
+ def to_a
230
+
231
+ raise ArgumentError.new(
232
+ "couldn't parse process definition out of >#{@first_line}<"
233
+ ) unless @children.first
234
+
235
+ @children.first.to_a
236
+ end
237
+ end
238
+
239
+ # Returns tree if s seems to contain a radial process definition
240
+ #
241
+ def self.understands?(s)
242
+
243
+ return false if s.match(/\n *end\b/)
244
+ return false if s.match(/\bRuote\.(process_definition|workflow_definition|define)\b/)
245
+ true
246
+ end
247
+
248
+ # The entry point : takes a radial string and returns, if possible,
249
+ # a ruote tree.
250
+ #
251
+ def self.read(s, opt=nil)
252
+
253
+ parser = Parser.new
254
+ transformer = Transformer.new
255
+
256
+ lines = parser.parse("\n#{s}\n")
257
+ nodes = transformer.apply(lines)
258
+
259
+ root = PreRoot.new("#{s.strip.split("\n").first}...")
260
+ current = root
261
+
262
+ nodes = [] unless nodes.is_a?(Array)
263
+ # force ArgumentError via empty PreRoot
264
+
265
+ nodes.each do |node|
266
+
267
+ parent = current
268
+
269
+ if node.indentation == current.indentation
270
+ parent = current.parent
271
+ elsif node.indentation < current.indentation
272
+ while node.indentation <= parent.indentation
273
+ parent = parent.parent
274
+ end
275
+ end
276
+
277
+ node.parent = parent
278
+ current = node
279
+ end
280
+
281
+ root.to_a
282
+
283
+ rescue Parslet::ParseFailed => e
284
+ class << e; attr_accessor :error_tree; end
285
+ e.error_tree = parser.root.error_tree
286
+ raise e
287
+ end
288
+ end
289
+ end
290
+