xpflow 0.1b

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 (74) hide show
  1. data/bin/xpflow +96 -0
  2. data/lib/colorado.rb +198 -0
  3. data/lib/json/add/core.rb +243 -0
  4. data/lib/json/add/rails.rb +8 -0
  5. data/lib/json/common.rb +423 -0
  6. data/lib/json/editor.rb +1369 -0
  7. data/lib/json/ext.rb +28 -0
  8. data/lib/json/pure/generator.rb +442 -0
  9. data/lib/json/pure/parser.rb +320 -0
  10. data/lib/json/pure.rb +15 -0
  11. data/lib/json/version.rb +8 -0
  12. data/lib/json.rb +62 -0
  13. data/lib/mime/types.rb +881 -0
  14. data/lib/mime-types.rb +3 -0
  15. data/lib/restclient/abstract_response.rb +106 -0
  16. data/lib/restclient/exceptions.rb +193 -0
  17. data/lib/restclient/net_http_ext.rb +55 -0
  18. data/lib/restclient/payload.rb +235 -0
  19. data/lib/restclient/raw_response.rb +34 -0
  20. data/lib/restclient/request.rb +316 -0
  21. data/lib/restclient/resource.rb +169 -0
  22. data/lib/restclient/response.rb +24 -0
  23. data/lib/restclient.rb +174 -0
  24. data/lib/xpflow/bash.rb +341 -0
  25. data/lib/xpflow/bundle.rb +113 -0
  26. data/lib/xpflow/cmdline.rb +249 -0
  27. data/lib/xpflow/collection.rb +122 -0
  28. data/lib/xpflow/concurrency.rb +79 -0
  29. data/lib/xpflow/data.rb +393 -0
  30. data/lib/xpflow/dsl.rb +816 -0
  31. data/lib/xpflow/engine.rb +574 -0
  32. data/lib/xpflow/ensemble.rb +135 -0
  33. data/lib/xpflow/events.rb +56 -0
  34. data/lib/xpflow/experiment.rb +65 -0
  35. data/lib/xpflow/exts/facter.rb +30 -0
  36. data/lib/xpflow/exts/g5k.rb +931 -0
  37. data/lib/xpflow/exts/g5k_use.rb +50 -0
  38. data/lib/xpflow/exts/gui.rb +140 -0
  39. data/lib/xpflow/exts/model.rb +155 -0
  40. data/lib/xpflow/graph.rb +1603 -0
  41. data/lib/xpflow/graph_xpflow.rb +251 -0
  42. data/lib/xpflow/import.rb +196 -0
  43. data/lib/xpflow/library.rb +349 -0
  44. data/lib/xpflow/logging.rb +153 -0
  45. data/lib/xpflow/manager.rb +147 -0
  46. data/lib/xpflow/nodes.rb +1250 -0
  47. data/lib/xpflow/runs.rb +773 -0
  48. data/lib/xpflow/runtime.rb +125 -0
  49. data/lib/xpflow/scope.rb +168 -0
  50. data/lib/xpflow/ssh.rb +186 -0
  51. data/lib/xpflow/stat.rb +50 -0
  52. data/lib/xpflow/stdlib.rb +381 -0
  53. data/lib/xpflow/structs.rb +369 -0
  54. data/lib/xpflow/taktuk.rb +193 -0
  55. data/lib/xpflow/templates/ssh-config.basic +14 -0
  56. data/lib/xpflow/templates/ssh-config.inria +18 -0
  57. data/lib/xpflow/templates/ssh-config.proxy +13 -0
  58. data/lib/xpflow/templates/taktuk +6590 -0
  59. data/lib/xpflow/templates/utils/batch +4 -0
  60. data/lib/xpflow/templates/utils/bootstrap +12 -0
  61. data/lib/xpflow/templates/utils/hostname +3 -0
  62. data/lib/xpflow/templates/utils/ping +3 -0
  63. data/lib/xpflow/templates/utils/rsync +12 -0
  64. data/lib/xpflow/templates/utils/scp +17 -0
  65. data/lib/xpflow/templates/utils/scp_many +8 -0
  66. data/lib/xpflow/templates/utils/ssh +3 -0
  67. data/lib/xpflow/templates/utils/ssh-interactive +4 -0
  68. data/lib/xpflow/templates/utils/taktuk +19 -0
  69. data/lib/xpflow/threads.rb +187 -0
  70. data/lib/xpflow/utils.rb +569 -0
  71. data/lib/xpflow/visual.rb +230 -0
  72. data/lib/xpflow/with_g5k.rb +7 -0
  73. data/lib/xpflow.rb +349 -0
  74. metadata +135 -0
data/lib/xpflow/dsl.rb ADDED
@@ -0,0 +1,816 @@
1
+ # encoding: UTF-8
2
+
3
+ #
4
+ # DSL implementation.
5
+ #
6
+
7
+ module XPFlow
8
+
9
+ class LibraryLink
10
+
11
+ constructor :process, :key, :parts
12
+
13
+ def method_missing(method, *args, &block)
14
+ new_parts = @parts + [ method.to_s ]
15
+ full_name = new_parts.join(".")
16
+ obj = @process.library.resolve_name(full_name)
17
+ if obj.nil?
18
+ raise "No such object '#{full_name}'"
19
+ end
20
+ if obj.is_a?(Library)
21
+ raise NoMethodError, "Library referencing requires no args" if args.length > 0
22
+ else
23
+ # activity/process
24
+ args = XPValue.flatten(args)
25
+ full_name = XPValue.flatten(full_name)
26
+ run = RunDSL.new(@process, @key, full_name, args, {}, block)
27
+ return @process.push(run)
28
+ end
29
+ return LibraryLink.new(@process, @key, new_parts)
30
+ end
31
+ end
32
+
33
+ class Key
34
+
35
+ def initialize(array)
36
+ @array = array
37
+ end
38
+
39
+ end
40
+
41
+ class DSL
42
+
43
+ def initialize(process, key)
44
+ @process = process
45
+ if key.nil?
46
+ @_key = []
47
+ elsif key.is_a?(Array)
48
+ @_key = key
49
+ elsif key.is_a?(String)
50
+ @_key = from_string(key)
51
+ else
52
+ raise "Unsupported key type"
53
+ end
54
+ @current_key = -1
55
+ @keys = []
56
+ end
57
+
58
+ def from_string(s) # string => Array
59
+ raise "error" unless s.start_with?("/")
60
+ arr = s.split("/"); arr.shift
61
+ return arr
62
+ end
63
+
64
+ def to_string(arr)
65
+ return "/" + arr.join("/")
66
+ end
67
+
68
+ def key
69
+ return to_string(@_key)
70
+ end
71
+
72
+ def new_key
73
+ @current_key += 1
74
+ key = @_key + [ @current_key ]
75
+ @keys.push(key)
76
+ return to_string(key)
77
+ end
78
+
79
+ def parse(*args, &block)
80
+ begin
81
+ $current_dsl.push(self)
82
+ self.instance_exec(*args, &block)
83
+ ensure
84
+ $current_dsl.pop
85
+ end
86
+ return self
87
+ end
88
+
89
+ def repr
90
+ {
91
+ :key => key()
92
+ }
93
+ end
94
+
95
+ end
96
+
97
+ $current_dsl = []
98
+
99
+ class DSLVariable
100
+
101
+ include Operations
102
+
103
+ attr_reader :key
104
+ constructor :key
105
+
106
+ def to_s
107
+ "Var[-@@@@-#{key}-@@@@-]"
108
+ end
109
+
110
+ def self.replace(s, scope)
111
+ out = s.gsub(/Var\[-@@@@-([\/\d]+)-@@@@-\]/) do |m|
112
+ key = $1
113
+ scope.get(key).to_s
114
+ end
115
+ return out
116
+ end
117
+
118
+ def to_ary
119
+ return 10.times.map do |i|
120
+ u = XPValue.flatten(self)
121
+ u.index(XPConst.new(i))
122
+ end
123
+ end
124
+
125
+ def as_s
126
+ return method_missing(:to_s)
127
+ end
128
+
129
+ def as_i
130
+ return method_missing(:to_i)
131
+ end
132
+
133
+ def method_missing(method, *args)
134
+ dsl = $current_dsl.last
135
+ raise "Fatal error" if dsl.nil?
136
+ raise "Arguments are unsupported" if args.length > 0
137
+ return dsl.get_of(self, method)
138
+ end
139
+
140
+ end
141
+
142
+ class RunDSL < DSL
143
+
144
+ constructor [ :process, :key ], :name, :args, :opts, :block
145
+
146
+ def repr
147
+ super.merge({
148
+ :type => :run,
149
+ :name => @name,
150
+ :args => @args,
151
+ :opts => @opts
152
+ })
153
+ end
154
+
155
+ def collect_meta(xxxx)
156
+ {
157
+
158
+ }
159
+ end
160
+
161
+ def as_run
162
+ return ActivityRun.new(key, @name, @args, @opts, @block)
163
+ end
164
+
165
+ end
166
+
167
+ class ReturnLoopDSL < DSL
168
+
169
+ constructor [ :process, :key ], :flag, :cond, :value
170
+
171
+ def as_run
172
+ return ReturnLoopRun.new(key, @flag, @cond, @value)
173
+ end
174
+ end
175
+
176
+ class CheckpointDSL < DSL
177
+
178
+ constructor [ :process, :key ], :name, :opts, :parent
179
+
180
+ def as_run
181
+ return CheckpointRun.new(new_key, @name, @opts, @parent)
182
+ end
183
+ end
184
+
185
+ class OtherwiseDSL < DSL
186
+
187
+ constructor [ :process, :key ]
188
+
189
+ end
190
+
191
+ class ListDSL < DSL
192
+
193
+ constructor [ :process, :key ], :list
194
+
195
+ def __list__
196
+ return @list
197
+ end
198
+
199
+ def __as_run__
200
+ return @list.map(&:as_run)
201
+ end
202
+
203
+ def push(x, inc = 0)
204
+ @list.push(x)
205
+ return DSLVariable.new(x.key)
206
+ end
207
+
208
+ def parse_and_push(dsl, *args, &block)
209
+ return push(dsl.parse(*args, &block))
210
+ end
211
+
212
+ def as_run
213
+ runs = __as_run__
214
+ return SequenceRun.new(key, runs)
215
+ end
216
+
217
+ def __workflow__(*args)
218
+ block, _ = @process.current_workflow
219
+ seq = SequenceDSL.new(@process, new_key)
220
+ return parse_and_push(seq, *args, &block)
221
+ end
222
+
223
+ ### DSL PART ###
224
+
225
+ def parallel(opts = {}, &block)
226
+ retries = opts[:retry]
227
+ if retries.nil?
228
+ dsl = ParallelDSL.new(@process, new_key)
229
+ return parse_and_push(dsl, &block)
230
+ else
231
+ try :retry => retries do
232
+ parallel(&block)
233
+ end
234
+ end
235
+ end
236
+
237
+ def any(&block)
238
+ one = XPValue.flatten(-1)
239
+ dsl = ManyDSL.new(@process, new_key, one)
240
+ return parse_and_push(dsl, &block)
241
+ end
242
+
243
+ def many(arg, &block)
244
+ n = XPValue.flatten(arg)
245
+ dsl = ManyDSL.new(@process, new_key, n)
246
+ return parse_and_push(dsl, &block)
247
+ end
248
+
249
+ def formany(arg, array, &block)
250
+ n = XPValue.flatten(arg)
251
+ array = XPValue.flatten(array)
252
+ dsl = ForManyDSL.new(@process, new_key, n, array)
253
+ return parse_and_push(dsl, &block)
254
+ end
255
+
256
+ def sequence(&block)
257
+ dsl = SequenceDSL.new(@process, new_key)
258
+ return parse_and_push(dsl, &block)
259
+ end
260
+
261
+ def seq(&block)
262
+ return sequence(&block)
263
+ end
264
+
265
+ def seqtry(&block)
266
+ dsl = SeqtryDSL.new(@process, new_key)
267
+ return parse_and_push(dsl, &block)
268
+ end
269
+
270
+ def foreach(array, opts = {}, &block)
271
+ array = XPValue.flatten(array)
272
+ opts = XPValue.flatten(opts)
273
+ dsl = ForEachDSL.new(@process, new_key, array, opts)
274
+ return parse_and_push(dsl, &block)
275
+ end
276
+
277
+ def forall(array, opts = {}, &block)
278
+ array = XPValue.flatten(array)
279
+ opts = XPValue.flatten(opts)
280
+ dsl = ForAllDSL.new(@process, new_key, array, opts)
281
+ return parse_and_push(dsl, &block)
282
+ end
283
+
284
+ def times(loops, &block)
285
+ loops = XPValue.flatten(loops)
286
+ dsl = TimesDSL.new(@process, new_key, loops)
287
+ return parse_and_push(dsl, &block)
288
+ end
289
+
290
+ def forany(array, &block)
291
+ one = XPValue.flatten(-1)
292
+ array = XPValue.flatten(array)
293
+ dsl = ForManyDSL.new(@process, new_key, one, array)
294
+ return parse_and_push(dsl, &block)
295
+ end
296
+
297
+ def on(condition, &block)
298
+ condition = XPValue.flatten(condition)
299
+ dsl = IfDSL.new(@process, new_key, condition)
300
+ return parse_and_push(dsl, &block)
301
+ end
302
+
303
+ def switch(*args, &block)
304
+ if args.length == 0
305
+ s = SwitchDSL.new(@process, new_key)
306
+ parse_and_push(s, &block)
307
+ elsif args.length == 1
308
+ s = BoundSwitchDSL.new(@process, new_key, XPValue.flatten(args.first))
309
+ parse_and_push(s, &block)
310
+ else
311
+ raise
312
+ end
313
+ end
314
+
315
+ def multi(&block)
316
+ dsl = MultiDSL.new(@process, new_key)
317
+ return parse_and_push(dsl, &block)
318
+ end
319
+
320
+ def try(opts = {}, &block)
321
+ opts = XPValue.flatten(opts)
322
+ dsl = TryDSL.new(@process, new_key, opts)
323
+ return parse_and_push(dsl, &block)
324
+ end
325
+
326
+ def result(path, opts = {}, &block)
327
+ # TODO: reimplement with macros!
328
+ opts = XPValue.flatten(opts)
329
+ path = XPValue.flatten(path)
330
+ dsl = ResultDSL.new(@process, new_key, path, opts)
331
+ return parse_and_push(dsl, &block)
332
+ end
333
+
334
+ def loop(opts = {}, &block)
335
+ opts = XPValue.flatten(opts)
336
+ dsl = LoopDSL.new(@process, new_key, opts)
337
+ return parse_and_push(dsl, &block)
338
+ end
339
+
340
+ def cache(opts = {}, &block)
341
+ dsl = CacheDSL.new(@process, new_key, opts)
342
+ return parse_and_push(dsl, &block)
343
+ end
344
+
345
+
346
+ def info(opts = {}, &block)
347
+ opts = XPValue.flatten(opts)
348
+ dsl = InfoDSL.new(@process, opts)
349
+ return parse_and_push(dsl, &block)
350
+ end
351
+
352
+ def run(arg, *args, &block)
353
+ # Kernel.puts "run: #{args} #{args.inspect}"
354
+ opts = XPFlow::parse_comment_opts(__FILE__)
355
+ name = nil
356
+ if arg.is_a?(Hash)
357
+ opts = opts.merge(arg)
358
+ name, args = args.first, args.tail
359
+ else
360
+ name = arg
361
+ end
362
+ raise 'No name given' if name.nil?
363
+ args = XPValue.flatten(args)
364
+ name = XPValue.flatten(name)
365
+ return push(RunDSL.new(@process, new_key, name, args, opts, block))
366
+ end
367
+
368
+ def rerun(name, *args, &block)
369
+ # TODO
370
+ try :retry => 100000 do # as many times as needed
371
+ run(name, *args, &block)
372
+ end
373
+ end
374
+
375
+ def sleep(t)
376
+ # this has to be present in DSL for some rather obscure reasons :)
377
+ return method_missing(:sleep, t)
378
+ end
379
+
380
+ def puts(*args)
381
+ # overloads the standard 'puts'
382
+ return method_missing(:log, *args)
383
+ end
384
+
385
+ def fail(*args)
386
+ # same here
387
+ return method_missing(:fail, *args)
388
+ end
389
+
390
+ def system(cmd)
391
+ # same here
392
+ return method_missing(:system, cmd)
393
+ end
394
+
395
+ def send(o, method, *args)
396
+ # same reason as sleep
397
+ return method_missing(:send, o, method, *args)
398
+ end
399
+
400
+ def method_missing(method, *args, &block)
401
+ # this is rather tricky:
402
+ # 1. DSL has predefined commands.
403
+ # 2. When no command matches we try to find "injected" activity, or activity
404
+ # the was injected into the DSL. That way we can move many DSL commands to activities.
405
+ # 3. When injected activities do not match, we try to match with a namespace. If there
406
+ # is a library with such a name we return a special variable. The only use for that
407
+ # is to be able to run activities like that: run g5k.reserve_nodes
408
+ # 4. If nothing matches, we raise an error.
409
+
410
+ # pp @process.library.traversal_graph
411
+
412
+ name = method.to_s
413
+ activity = @process.library.get_activity_or_nil(name)
414
+
415
+ if activity.is_a?(MacroDSL)
416
+ m = activity
417
+ seq = nil
418
+ raise "Macro must be provided with a workflow" if block.nil?
419
+ @process.with_workflow(block, args) do
420
+ seq = SequenceDSL.new(@process, new_key)
421
+ seq.parse(*args, &m.block)
422
+ push(seq)
423
+ end
424
+ return seq
425
+ end
426
+
427
+ if activity.nil? == false
428
+ args = XPValue.flatten(args)
429
+ name = XPValue.flatten(name)
430
+ opts = XPFlow::parse_comment_opts(__FILE__)
431
+ run = RunDSL.new(@process, new_key, name, args, opts, block)
432
+ return push(run)
433
+ end
434
+
435
+ library = @process.library.get_library_or_nil(name)
436
+
437
+ if library.nil? == false
438
+ raise NoMethodError, "Library referencing requires no args" if args.length > 0
439
+ return LibraryLink.new(@process, new_key, [ method.to_s ])
440
+ end
441
+
442
+ if name.end_with?('_of') and [ 1, 2 ].include?(args.length)
443
+ name = name.chomp('_of')
444
+ return self.get_of(args.first, name.to_sym, args[1])
445
+ end
446
+
447
+ raise NoMethodError, "Unknown or malformed DSL command or no such activity (:#{method})"
448
+ end
449
+
450
+ def _visit(*args)
451
+ pp caller
452
+ raise "Somebody did something stupid (see #{self.class})."
453
+ end
454
+
455
+ def experiment_scope(name = nil, &block)
456
+ # creates a new experiment scope
457
+ dsl = ExperimentDSL.new(@process, name)
458
+ return parse_and_push(dsl, &block)
459
+ end
460
+
461
+ ### END OF DSL ###
462
+
463
+ end
464
+
465
+ class SequenceDSL < ListDSL
466
+
467
+ def initialize(process, key)
468
+ super(process, key, [])
469
+ end
470
+
471
+ def self.repr(o)
472
+ return {
473
+ :key => o.key,
474
+ :type => :seq,
475
+ :body => o.__list__.map(&:repr)
476
+ }
477
+ end
478
+
479
+ def repr
480
+ return SequenceDSL.repr(self)
481
+ end
482
+
483
+ end
484
+
485
+ class ProcessDSL < SequenceDSL
486
+
487
+ attr_reader :args
488
+ attr_reader :name
489
+ attr_reader :library
490
+
491
+ def initialize(name, library, &block)
492
+ super(self, [])
493
+ @name = name
494
+ @library = library
495
+ @workflows = [] # a stack of current workflows used in macros
496
+ if block.nil?
497
+ raise "Block is nil?"
498
+ end
499
+ count = block.arity
500
+ if count >= 0
501
+ @args = count.times.map { |i| DSLVariable.new(new_key()) }
502
+ else
503
+ @args = 10.times.map { |i| DSLVariable.new(new_key()) }
504
+ end
505
+ self.parse(*@args, &block)
506
+ end
507
+
508
+ def checkpoint(*args)
509
+ name = nil
510
+ opts = {}
511
+ opts = args.pop if args.last.is_a?(Hash)
512
+ raise 'Wrong arguments' if args.length > 1
513
+ name = args.first if args.length == 1
514
+ push(CheckpointDSL.new(@process, new_key, name, opts, self))
515
+ end
516
+
517
+ def get_injection(name)
518
+ return @library.get_injection(name)
519
+ end
520
+
521
+ def as_process
522
+ keys = @args.map(&:key)
523
+ seq = self.as_run
524
+ return ProcessActivity.new(@name, keys, seq)
525
+ end
526
+
527
+ def repr
528
+ return {
529
+ :type => :process,
530
+ :name => @name,
531
+ :body => SequenceDSL.repr(self)
532
+ }
533
+ end
534
+
535
+ def with_workflow(m, args)
536
+ begin
537
+ @workflows.push([ m, args ])
538
+ yield
539
+ ensure
540
+ @workflows.pop
541
+ end
542
+ end
543
+
544
+ def current_workflow
545
+ raise "No current workflow" if @workflows.length == 0
546
+ return @workflows.last
547
+ end
548
+
549
+ end
550
+
551
+
552
+ class InnerDSL < SequenceDSL
553
+
554
+ alias :sequence_run :as_run
555
+
556
+ end
557
+
558
+ class WithParamsDSL < InnerDSL
559
+
560
+ def parse(&block)
561
+ args = @args.map { |x| DSLVariable.new(x) }
562
+ return super(*args, &block)
563
+ end
564
+
565
+ def repr
566
+ super.merge({
567
+ :args => @args
568
+ })
569
+ end
570
+
571
+ end
572
+
573
+
574
+ class SeqtryDSL < InnerDSL
575
+
576
+ constructor [ :process, :key ]
577
+
578
+ def as_run
579
+ return SeqtryRun.new(key, sequence_run.body)
580
+ end
581
+
582
+ end
583
+
584
+ class ExperimentDSL < InnerDSL
585
+
586
+ constructor [ :process ], :name
587
+
588
+ def as_run
589
+ return ExperimentRun.new(@process.get_key, @name, sequence_run)
590
+ end
591
+
592
+ end
593
+
594
+ class ForEachDSL < WithParamsDSL
595
+
596
+ constructor [ :process, :key ], :array, :opts
597
+
598
+ def init
599
+ @args = [ new_key() ] # iterator
600
+ end
601
+
602
+ def as_run
603
+ return ForEachRun.new(key, @array, @args.first, @opts, sequence_run)
604
+ end
605
+
606
+ def repr
607
+ super.merge({
608
+ :type => :foreach,
609
+ :array => @array
610
+ })
611
+ end
612
+
613
+ end
614
+
615
+ class ParallelDSL < InnerDSL
616
+
617
+ def as_run
618
+ return ParallelRun.new(key, __as_run__)
619
+ end
620
+ end
621
+
622
+ class TimesDSL < WithParamsDSL
623
+
624
+ constructor [ :process, :key ], :loops
625
+
626
+ def init
627
+ @args = [ new_key() ] # iterator
628
+ end
629
+
630
+ def as_run
631
+ return TimesRun.new(key, @loops, @args.first, sequence_run)
632
+ end
633
+ end
634
+
635
+ class ForAllDSL < WithParamsDSL
636
+
637
+ constructor [ :process, :key ], :array, :opts
638
+
639
+ def init
640
+ @args = [ new_key() ] # iterator
641
+ end
642
+
643
+ def as_run
644
+ return ForAllRun.new(key, @array, @args.first, @opts, sequence_run)
645
+ end
646
+ end
647
+
648
+ class ForManyDSL < WithParamsDSL
649
+
650
+ constructor [ :process, :key ], :number, :array
651
+
652
+ def init
653
+ @args = [ new_key() ] # iterator
654
+ end
655
+
656
+ def as_run
657
+ return ForManyRun.new(key, @number, @array, @args.first, sequence_run)
658
+ end
659
+
660
+ end
661
+
662
+ class ManyDSL < InnerDSL
663
+
664
+ constructor [ :process, :key ], :number
665
+
666
+ def as_run
667
+ return ManyRun.new(key, @number, __as_run__)
668
+ end
669
+
670
+ end
671
+
672
+ class TryDSL < InnerDSL
673
+
674
+ constructor [ :process, :key ], :opts
675
+
676
+ def as_run
677
+ return TryRun.new(key, @opts, sequence_run)
678
+ end
679
+
680
+ end
681
+
682
+ class ResultDSL < InnerDSL
683
+
684
+ constructor [ :process, :key ], :path, :opts
685
+
686
+ def as_run
687
+ return ResultRun.new(key, @path, @opts, sequence_run)
688
+ end
689
+
690
+ end
691
+
692
+ class CacheDSL < InnerDSL
693
+
694
+ constructor [ :process, :key ], :opts
695
+
696
+ def as_run
697
+ return CacheRun.new(key, @opts, sequence_run)
698
+ end
699
+
700
+ end
701
+
702
+ class InfoDSL < InnerDSL
703
+
704
+ constructor [ :process, :key ], :opts
705
+
706
+ def as_run
707
+ return InfoRun.new(key, @opts, sequence_run)
708
+ end
709
+ end
710
+
711
+
712
+ class IfDSL < SequenceDSL
713
+
714
+ constructor [ :process, :key ], :cond
715
+
716
+ def otherwise
717
+ push(OtherwiseDSL.new(@process, new_key))
718
+ end
719
+
720
+ def as_run
721
+ i = nil
722
+ @list.length.times do |j|
723
+ i = j if (@list[j].is_a?(OtherwiseDSL))
724
+ end
725
+ on_true = []
726
+ on_false = []
727
+ if i.nil?
728
+ on_true = @list
729
+ else
730
+ on_true = @list[0..(i-1)]
731
+ on_false = @list[(i+1)..-1]
732
+ raise if (on_true.length + on_false.length + 1) != @list.length
733
+ end
734
+ on_true = ListDSL.new(@process, new_key, on_true).as_run
735
+ on_false = ListDSL.new(@process, new_key, on_false).as_run
736
+ return IfRun.new(key, @cond, on_true, on_false)
737
+ end
738
+
739
+ end
740
+
741
+ class LoopDSL < WithParamsDSL
742
+
743
+ constructor [ :process, :key ], :opts
744
+
745
+ def init
746
+ @flag = new_key()
747
+ @iter = new_key()
748
+ @array = new_key()
749
+ @args = [ @iter, @array ]
750
+ end
751
+
752
+ def return_on(cond, value = nil)
753
+ cond = XPValue.flatten(cond)
754
+ value = XPValue.flatten(value)
755
+ push(ReturnLoopDSL.new(@process, key, @flag, cond, value))
756
+ end
757
+
758
+ def as_run
759
+ return LoopRun.new(key, @flag, @iter, @array, __as_run__, @opts)
760
+ end
761
+ end
762
+
763
+ class SwitchDSL < DSL
764
+
765
+ constructor [ :process, :key ], :cases => [], :default => nil
766
+
767
+ def on(cond, &block)
768
+ body = SequenceDSL.new(@process, new_key).parse(&block)
769
+ @cases.push([ XPValue.flatten(cond), body ])
770
+ end
771
+
772
+ def default(&block)
773
+ @default = SequenceDSL.new(@process, new_key).parse(&block)
774
+ end
775
+
776
+ def _cases_as_runs
777
+ return @cases.map { |c, b| [ c, b.as_run ] }
778
+ end
779
+
780
+ def _default_as_run
781
+ return nil if @default.nil?
782
+ return @default.as_run
783
+ end
784
+
785
+ def as_run
786
+ return SwitchRun.new(key, _cases_as_runs, _default_as_run)
787
+ end
788
+ end
789
+
790
+ class MultiDSL < SwitchDSL
791
+
792
+ def as_run
793
+ return MultiRun.new(key, _cases_as_runs, _default_as_run)
794
+ end
795
+ end
796
+
797
+ class BoundSwitchDSL < SwitchDSL
798
+
799
+ constructor [ :process, :key ], :cond
800
+
801
+ def as_run
802
+ return BoundSwitchRun.new(key, _cases_as_runs, _default_as_run, @cond)
803
+ end
804
+ end
805
+
806
+ class MacroDSL
807
+
808
+ # stores a block for workflow construction later
809
+
810
+ attr_reader :block
811
+
812
+ constructor :name, :engine, :block
813
+
814
+ end
815
+
816
+ end