openwferu 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. data/{README → README.txt} +16 -13
  2. data/bin/validate-workflow.rb +46 -22
  3. data/examples/README.txt +8 -0
  4. data/examples/homeworkreview.rb +66 -0
  5. data/examples/quotereporter.rb +154 -0
  6. data/lib/{openwferu.rb → openwfe.rb} +6 -8
  7. data/lib/{ru → openwfe}/contextual.rb +11 -3
  8. data/lib/{ru → openwfe/engine}/engine.rb +50 -36
  9. data/lib/{ru/participant.rb → openwfe/engine/file_persisted_engine.rb} +21 -22
  10. data/lib/openwfe/expool/expressionpool.rb +534 -0
  11. data/lib/openwfe/expool/expstorage.rb +184 -0
  12. data/lib/openwfe/expool/journalexpstorage.rb +312 -0
  13. data/lib/openwfe/expool/yamlexpstorage.rb +127 -0
  14. data/lib/{ru → openwfe/expressions}/environment.rb +19 -14
  15. data/lib/{ru → openwfe/expressions}/expressionmap.rb +48 -21
  16. data/lib/{ru → openwfe/expressions}/fe_concurrence.rb +111 -35
  17. data/lib/openwfe/expressions/fe_cursor.rb +236 -0
  18. data/lib/{ru → openwfe/expressions}/fe_define.rb +5 -5
  19. data/lib/openwfe/expressions/fe_fqv.rb +99 -0
  20. data/lib/openwfe/expressions/fe_iterator.rb +182 -0
  21. data/lib/{ru/fe_misc.rb → openwfe/expressions/fe_losfor.rb} +14 -56
  22. data/lib/openwfe/expressions/fe_misc.rb +102 -0
  23. data/lib/{ru → openwfe/expressions}/fe_participant.rb +25 -14
  24. data/lib/{ru → openwfe/expressions}/fe_raw.rb +39 -75
  25. data/lib/{ru/fe_base.rb → openwfe/expressions/fe_sequence.rb} +40 -35
  26. data/lib/{ru → openwfe/expressions}/fe_subprocess.rb +30 -14
  27. data/lib/{ru → openwfe/expressions}/fe_time.rb +59 -31
  28. data/lib/{ru → openwfe/expressions}/fe_utils.rb +42 -26
  29. data/lib/{ru → openwfe/expressions}/fe_value.rb +20 -14
  30. data/lib/openwfe/expressions/flowexpression.rb +434 -0
  31. data/lib/openwfe/expressions/raw_prog.rb +391 -0
  32. data/lib/openwfe/expressions/raw_xml.rb +128 -0
  33. data/lib/openwfe/flowexpressionid.rb +148 -0
  34. data/lib/{ru → openwfe}/logging.rb +10 -6
  35. data/lib/{osocket.rb → openwfe/osocket.rb} +36 -35
  36. data/lib/{otime.rb → openwfe/otime.rb} +71 -21
  37. data/lib/openwfe/participants/atomparticipants.rb +144 -0
  38. data/lib/openwfe/participants/enoparticipant.rb +73 -0
  39. data/lib/openwfe/participants/participant.rb +85 -0
  40. data/lib/{ru → openwfe/participants}/participantmap.rb +40 -12
  41. data/lib/{ru → openwfe/participants}/participants.rb +41 -12
  42. data/lib/openwfe/participants/soapparticipants.rb +96 -0
  43. data/lib/{controlclient.rb → openwfe/rest/controlclient.rb} +12 -13
  44. data/lib/{definitions.rb → openwfe/rest/definitions.rb} +3 -3
  45. data/lib/{exception.rb → openwfe/rest/exception.rb} +3 -3
  46. data/lib/{restclient.rb → openwfe/rest/restclient.rb} +13 -22
  47. data/lib/{worklistclient.rb → openwfe/rest/worklistclient.rb} +33 -46
  48. data/lib/openwfe/rest/xmlcodec.rb +575 -0
  49. data/lib/{ru → openwfe}/rudefinitions.rb +32 -4
  50. data/lib/{ru → openwfe}/service.rb +20 -8
  51. data/lib/openwfe/storage/yamlfilestorage.rb +159 -0
  52. data/lib/{ru → openwfe/util}/dollar.rb +10 -8
  53. data/lib/openwfe/util/lru_cache.rb +149 -0
  54. data/lib/{ru → openwfe/util}/scheduler.rb +18 -10
  55. data/lib/{ru → openwfe/util}/schedulers.rb +7 -7
  56. data/lib/{utils.rb → openwfe/utils.rb} +93 -9
  57. data/lib/openwfe/workitem.rb +366 -0
  58. data/lib/openwfe/worklist/worklists.rb +175 -0
  59. data/test/README.txt +27 -0
  60. data/test/atomtest.rb +99 -0
  61. data/test/crontest.rb +58 -0
  62. data/test/dollartest.rb +3 -3
  63. data/test/feitest.rb +42 -14
  64. data/test/file_persistence_test.rb +93 -0
  65. data/test/flowtestbase.rb +72 -26
  66. data/test/ft_0.rb +1 -97
  67. data/test/ft_0b_sequence.rb +33 -0
  68. data/test/ft_0c_testname.rb +29 -0
  69. data/test/ft_10_loop.rb +48 -0
  70. data/test/ft_11_ppd.rb +292 -0
  71. data/test/ft_12_blockparticipant.rb +45 -0
  72. data/test/ft_13_eno.rb +51 -0
  73. data/test/ft_14_subprocess.rb +90 -0
  74. data/test/ft_14b_subprocess.rb +40 -0
  75. data/test/ft_15_iterator.rb +70 -0
  76. data/test/ft_16_fqv.rb +57 -0
  77. data/test/ft_1_unset.rb +25 -1
  78. data/test/ft_2_concurrence.rb +10 -5
  79. data/test/ft_3_equals.rb +35 -1
  80. data/test/ft_4_misc.rb +16 -1
  81. data/test/ft_5_time.rb +26 -1
  82. data/test/ft_6_lambda.rb +2 -1
  83. data/test/{ft_7_losfor.rb → ft_7_lose.rb} +41 -35
  84. data/test/ft_8_forget.rb +46 -0
  85. data/test/ft_9_cursor.rb +94 -0
  86. data/test/journal_persistence_test.rb +147 -0
  87. data/test/misctest.rb +13 -9
  88. data/test/rake_ptest.rb +18 -0
  89. data/test/rake_qtest.rb +43 -0
  90. data/test/{fulltest.rb → rake_test.rb} +2 -2
  91. data/test/raw_prog_test.rb +236 -0
  92. data/test/rest_test.rb +189 -0
  93. data/test/rutest_utils.rb +1 -1
  94. data/test/timetest.rb +42 -34
  95. metadata +125 -82
  96. data/lib/codec.rb +0 -573
  97. data/lib/flowexpressionid.rb +0 -139
  98. data/lib/ru/expressionpool.rb +0 -382
  99. data/lib/ru/expressionstorage.rb +0 -99
  100. data/lib/ru/flowexpression.rb +0 -272
  101. data/lib/ru/ruutils.rb +0 -70
  102. data/lib/test.rb +0 -222
  103. data/lib/workitem.rb +0 -249
  104. data/test/quicktest.rb +0 -21
@@ -1,6 +1,6 @@
1
1
  #
2
2
  #--
3
- # Copyright (c) 2006, John Mettraux, OpenWFE.org
3
+ # Copyright (c) 2006-2007, John Mettraux, OpenWFE.org
4
4
  # All rights reserved.
5
5
  #
6
6
  # Redistribution and use in source and binary forms, with or without
@@ -39,17 +39,17 @@
39
39
  # John Mettraux at openwfe.org
40
40
  #
41
41
 
42
- require 'workitem'
43
- require 'flowexpressionid'
44
- require 'ru/flowexpression'
45
- require 'ru/fe_utils'
42
+ require 'openwfe/workitem'
43
+ require 'openwfe/flowexpressionid'
44
+ require 'openwfe/expressions/flowexpression'
45
+ require 'openwfe/expressions/fe_utils'
46
46
 
47
47
 
48
48
  #
49
49
  # expressions like 'set' and 'unset' and their utility methods
50
50
  #
51
51
 
52
- module OpenWFEru
52
+ module OpenWFE
53
53
 
54
54
  class SetValueExpression < FlowExpression
55
55
 
@@ -57,7 +57,7 @@ module OpenWFEru
57
57
 
58
58
  if @children.length < 1
59
59
  workitem.attributes[FIELD_RESULT] = \
60
- OpenWFEru::lookup_value(self, workitem)
60
+ OpenWFE::lookup_value(self, workitem)
61
61
  reply(workitem)
62
62
  return
63
63
  end
@@ -69,7 +69,9 @@ module OpenWFEru
69
69
  return
70
70
  end
71
71
 
72
- workitem.attributes[FIELD_RESULT] = child.to_s
72
+ #workitem.attributes[FIELD_RESULT] = child.to_s
73
+ workitem.attributes[FIELD_RESULT] = \
74
+ OpenWFE::fetch_text_content(self, workitem)
73
75
 
74
76
  reply(workitem)
75
77
  end
@@ -98,7 +100,7 @@ module OpenWFEru
98
100
 
99
101
  def handle_child (child, workitem)
100
102
 
101
- child = get_expression_pool().fetch(child)
103
+ child, _fei = get_expression_pool().fetch(child)
102
104
 
103
105
  if child.is_definition?
104
106
  fei = get_expression_pool().evaluate(child, workitem)
@@ -118,7 +120,7 @@ module OpenWFEru
118
120
  # return child
119
121
  # end
120
122
  # end
121
- # return OpenWFEru::lookup_value(self, workitem)
123
+ # return OpenWFE::lookup_value(self, workitem)
122
124
  #end
123
125
  end
124
126
 
@@ -148,14 +150,14 @@ module OpenWFEru
148
150
 
149
151
  def apply (workitem)
150
152
 
151
- value_a = OpenWFEru::lookup_value(self, workitem)
152
- value_b = OpenWFEru::lookup_value(self, workitem, 'other')
153
+ value_a = OpenWFE::lookup_value(self, workitem)
154
+ value_b = OpenWFE::lookup_value(self, workitem, 'other')
153
155
 
154
156
  result = compare(value_a, value_b)
155
157
 
156
158
  ldebug { "apply() result is '#{result}' #{@fei.to_debug_s}" }
157
159
 
158
- OpenWFEru::set_result(workitem, result)
160
+ OpenWFE::set_result(workitem, result)
159
161
 
160
162
  reply_to_parent(workitem)
161
163
  end
@@ -175,12 +177,14 @@ module OpenWFEru
175
177
  protected
176
178
 
177
179
  def compare (a, b)
180
+ #ldebug { "compare() #{fei.to_debug_s}" }
181
+ #ldebug { "compare() '#{a}' == '#{b}'" }
178
182
  return a == b
179
183
  end
180
184
  end
181
185
 
182
186
  #
183
- # <if/>
187
+ # <if/>
184
188
  #
185
189
  class IfExpression < FlowExpression
186
190
 
@@ -209,6 +213,8 @@ module OpenWFEru
209
213
 
210
214
  @condition_replied = true
211
215
 
216
+ store_itself()
217
+
212
218
  if result
213
219
  apply_consequence(1, workitem)
214
220
  else
@@ -0,0 +1,434 @@
1
+ #
2
+ #--
3
+ # Copyright (c) 2006-2007, John Mettraux, OpenWFE.org
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # . Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # . Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # . Neither the name of the "OpenWFE" nor the names of its contributors may be
17
+ # used to endorse or promote products derived from this software without
18
+ # specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #++
32
+ #
33
+ # $Id: definitions.rb 2725 2006-06-02 13:26:32Z jmettraux $
34
+ #
35
+
36
+ #
37
+ # "made in Japan"
38
+ #
39
+ # John Mettraux at openwfe.org
40
+ #
41
+
42
+ require 'openwfe/utils'
43
+ require 'openwfe/logging'
44
+ require 'openwfe/contextual'
45
+ require 'openwfe/rudefinitions'
46
+ require 'openwfe/util/dollar'
47
+
48
+
49
+ module OpenWFE
50
+
51
+ #
52
+ # FlowExpression
53
+ #
54
+
55
+ #
56
+ # The base class for all OpenWFE flow expression classes.
57
+ # It gathers all the methods for attributes and variable lookup.
58
+ #
59
+ class FlowExpression
60
+ include Contextual, Logging, OwfeServiceLocator
61
+
62
+ attr_accessor \
63
+ :fei, \
64
+ :parent_id, \
65
+ :environment_id, \
66
+ :attributes, \
67
+ :children, \
68
+ :apply_time
69
+
70
+
71
+ def initialize (fei, parent_id, env_id, app_context, attributes)
72
+
73
+ super()
74
+ #
75
+ # very necessary as this class includes the MonitorMixin
76
+
77
+ @fei = fei
78
+ @parent_id = parent_id
79
+ @environment_id = env_id
80
+ @application_context = app_context
81
+ @attributes = attributes
82
+
83
+ @apply_time = nil
84
+
85
+ #ldebug do
86
+ # "initialize()\n"+
87
+ # "self : #{@fei}\n"+
88
+ # "parent : #{@parent_id}"
89
+ #end
90
+ end
91
+
92
+ #
93
+ # the two most important methods for flow expressions
94
+
95
+ #
96
+ # this default implementation immediately replies to the
97
+ # parent expression
98
+ #
99
+ def apply (workitem)
100
+ get_parent().reply(workitem) if @parent_id
101
+ end
102
+
103
+ #
104
+ # this default implementation immediately replies to the
105
+ # parent expression
106
+ #
107
+ def reply (workitem)
108
+ reply_to_parent(workitem)
109
+ end
110
+
111
+ #
112
+ # Triggers the reply to the parent expression (of course, via the
113
+ # expression pool).
114
+ # Expressions do call this method when their job is done and the flow
115
+ # should resume without them.
116
+ #
117
+ def reply_to_parent (workitem)
118
+ get_expression_pool.reply_to_parent(self, workitem)
119
+ end
120
+
121
+ #
122
+ # a default implementation for cancel :
123
+ # cancels all the children
124
+ # Attempts to return an InFlowWorkItem
125
+ #
126
+ def cancel ()
127
+
128
+ return nil if not @children
129
+
130
+ inflowitem = nil
131
+
132
+ @children.each do |child|
133
+
134
+ next if child.kind_of? String
135
+
136
+ i = get_expression_pool().cancel(child)
137
+ inflowitem = i if not inflowitem
138
+ end
139
+
140
+ return inflowitem
141
+ end
142
+
143
+ #
144
+ # some convenience methods
145
+
146
+ #
147
+ # Returns the parent expression (not as a FlowExpressionId but directly
148
+ # as the FlowExpression instance it is).
149
+ #
150
+ def get_parent ()
151
+ parent, parent_fei = get_expression_pool().fetch(@parent_id)
152
+ return parent
153
+ end
154
+
155
+ #
156
+ # Stores itself in the expression pool.
157
+ # It's very important for expressions in persisted context to save
158
+ # themselves as soon as their state changed.
159
+ # Else this information would be lost at engine restart or
160
+ # simply if the expression got swapped out of memory and reloaded later.
161
+ #
162
+ def store_itself ()
163
+ ldebug { "store_itself() for #{@fei.to_debug_s}" }
164
+ #ldebug { "store_itself() \n#{OpenWFE::caller_to_s(0, 6)}" }
165
+ get_expression_pool().update(self)
166
+ end
167
+
168
+ #
169
+ # Returns the environment instance this expression uses.
170
+ # An environment is a container (a scope) for variables in the process
171
+ # definition.
172
+ # Environments themselves are FlowExpression instances.
173
+ #
174
+ def get_environment ()
175
+ return nil if not @environment_id
176
+ env, fei = get_expression_pool().fetch(@environment_id)
177
+ return env
178
+ end
179
+
180
+ #
181
+ # Returns true if the expression's environment was generated
182
+ # for itself (usually DefineExpression do have such envs)
183
+ #
184
+ def owns_its_environment? ()
185
+
186
+ #ldebug { "owns_its_environment?() #{@fei.to_debug_s}" }
187
+
188
+ return false if not @environment_id
189
+
190
+ ei = @fei.dup()
191
+ vi = @environment_id.dup()
192
+
193
+ ei.expression_name = "neutral"
194
+ vi.expression_name = "neutral"
195
+
196
+ #ldebug do
197
+ # "owns_its_environment?()\n"+
198
+ # " exp #{ei.to_debug_s}\n"+
199
+ # " env #{vi.to_debug_s}"
200
+ #end
201
+
202
+ return ei == vi
203
+ end
204
+
205
+ #
206
+ # Sets a variable in the current environment. Is usually
207
+ # called by the 'set' expression.
208
+ #
209
+ # The variable name may be prefixed by / to indicate process level scope
210
+ # or by // to indicate engine level (global) scope.
211
+ #
212
+ def set_variable (varname, value)
213
+ get_environment()[varname] = value
214
+ end
215
+
216
+ #
217
+ # Looks up the value of a variable in the current environment.
218
+ # If not found locally will lookup at the process level and even
219
+ # further in the engine scope.
220
+ #
221
+ # The variable name may be prefixed by / to indicate process level scope
222
+ # or by // to indicate engine level (global) scope.
223
+ #
224
+ def lookup_variable (varname)
225
+ return get_environment()[varname]
226
+ end
227
+
228
+ #
229
+ # Unsets a variable in the current environment.
230
+ #
231
+ # The variable name may be prefixed by / to indicate process level scope
232
+ # or by // to indicate engine level (global) scope.
233
+ #
234
+ def delete_variable (varname)
235
+ get_environment().delete(varname)
236
+ end
237
+
238
+ #
239
+ # Looks up the value for an attribute of this expression.
240
+ #
241
+ # if the expression is
242
+ #
243
+ # <participant ref="toto" />
244
+ #
245
+ # then
246
+ #
247
+ # participant_expression.lookup_attribute("toto", wi)
248
+ #
249
+ # will yield "toto"
250
+ #
251
+ # The various methods for looking up attributes do perform dollar
252
+ # variable substitution.
253
+ # It's ok to pass a Symbol for the attribute name.
254
+ #
255
+ def lookup_attribute (attname, workitem, default=nil)
256
+
257
+ #attname = attname.to_s
258
+ attname = symbol_to_attname(attname) \
259
+ if attname.kind_of? Symbol
260
+
261
+ #ldebug { "lookup_attribute() '#{attname}' in #{@fei.to_debug_s}" }
262
+
263
+ text = @attributes[attname]
264
+
265
+ return default if not text
266
+ return OpenWFE::dosub(text, self, workitem)
267
+ end
268
+
269
+ #
270
+ # A convenience method for looking up a boolean value.
271
+ # It's ok to pass a Symbol for the attribute name.
272
+ #
273
+ def lookup_boolean_attribute (attname, workitem, default=false)
274
+ value = lookup_attribute(attname, workitem)
275
+ return default if not value
276
+ return value.downcase == 'true'
277
+ end
278
+
279
+ #
280
+ # Returns a hash of all the FlowExpression attributes with their
281
+ # values having undergone dollar variable substitution.
282
+ # If the attributes parameter is set (to an Array instance) then
283
+ # only the attributes named in that list will be looked up.
284
+ #
285
+ # It's ok to pass an array of Symbol instances for the attributes
286
+ # parameter.
287
+ #
288
+ def lookup_attributes (workitem, _attributes=nil)
289
+
290
+ result = {}
291
+
292
+ return result if not @attributes
293
+
294
+ _attributes = @attributes.keys if not _attributes
295
+
296
+ _attributes.each do |k|
297
+ k = k.to_s
298
+ v = @attributes[k]
299
+ result[k] = OpenWFE::dosub(v, self, workitem)
300
+ #ldebug do
301
+ # "lookup_attributes() added '#{k}' -> '#{result[k]}'"
302
+ #end
303
+ end
304
+
305
+ return result
306
+ end
307
+
308
+ def lookup_comma_list_attribute (attname, workitem, default=nil)
309
+
310
+ a = lookup_attribute(attname, workitem, default)
311
+
312
+ return nil if not a
313
+
314
+ result = []
315
+ a.split(',').each do |elt|
316
+ elt = elt.strip
317
+ result << elt if elt.length > 0
318
+ end
319
+ return result
320
+ end
321
+
322
+ #
323
+ # creates a new environment just for this expression
324
+ #
325
+ def new_environment ()
326
+
327
+ ldebug { "new_environment() for #{@fei.to_debug_s}" }
328
+
329
+ @environment_id = @fei.dup
330
+ @environment_id.expression_name = EN_ENVIRONMENT
331
+
332
+ parent_fei = nil
333
+ parent = nil
334
+
335
+ parent, _fei = get_expression_pool().fetch(@parent_id) \
336
+ if @parent_id
337
+
338
+ parent_fei = parent.environment_id if parent
339
+
340
+ env = Environment\
341
+ .new(@environment_id, parent_fei, nil, @application_context, nil)
342
+
343
+ ldebug { "new_environment() is #{env.fei.to_debug_s}" }
344
+
345
+ env.store_itself()
346
+ end
347
+
348
+ #
349
+ # takes care of removing all the children
350
+ #
351
+ def clean_children
352
+ @children.each do |children_fei|
353
+ get_expression_pool.remove(children_fei)
354
+ end
355
+ end
356
+
357
+ #
358
+ # currently only used by dollar.rb and its ${r:some_ruby_code},
359
+ # returns the binding in this flow expression
360
+ #
361
+ def get_binding
362
+ return binding()
363
+ end
364
+
365
+ #
366
+ # Used like the classical Ruby synchronize, but as the OpenWFE
367
+ # expression pool manages its own set of monitores, it's one of those
368
+ # monitors that is used. But the synchronize code looks like the class
369
+ # just included the MonitorMixin. No hassle.
370
+ #
371
+ def synchronize
372
+ get_expression_pool.get_monitor(@fei).synchronize do
373
+ yield
374
+ end
375
+ end
376
+
377
+ #
378
+ # some eye candy
379
+ #
380
+ def to_s
381
+ s = "* #{@fei.to_debug_s}"
382
+
383
+ if @parent_id
384
+ s << "\n `--p--> #{@parent_id.to_debug_s}"
385
+ end
386
+
387
+ if @environment_id
388
+ s << "\n `--e--> #{@environment_id.to_debug_s}"
389
+ end
390
+
391
+ if @children
392
+ @children.each do |c|
393
+ sc = if c.kind_of?(OpenWFE::FlowExpressionId)
394
+ c.to_debug_s
395
+ else
396
+ ">#{c.to_s}<"
397
+ end
398
+ s << "\n `--c--> #{sc}"
399
+ end
400
+ end
401
+
402
+ return s
403
+ end
404
+
405
+ protected
406
+
407
+ def symbol_to_attname (s)
408
+ attname = s.to_s
409
+ attname = OpenWFE::to_dash(attname)
410
+ return attname
411
+ end
412
+ end
413
+
414
+ #
415
+ # A parent class for CursorExpression and IteratorExpression.
416
+ # Takes care of removing templates before replying to the parent
417
+ # expression.
418
+ #
419
+ class WithTemplateExpression < FlowExpression
420
+
421
+ #
422
+ # this overriden method takes care of removing all the children
423
+ # (templates) before replying to its parent.
424
+ #
425
+ def reply_to_parent (workitem)
426
+ @children.each do |child|
427
+ get_expression_pool.remove(child)
428
+ end
429
+ super(workitem)
430
+ end
431
+ end
432
+
433
+ end
434
+