bahuvrihi-tap 0.10.5 → 0.10.6
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rap +11 -25
- data/bin/tap +4 -18
- data/lib/tap.rb +1 -1
- data/lib/tap/constants.rb +1 -1
- data/lib/tap/exe.rb +1 -1
- data/lib/tap/generator/generators/file_task/templates/task.erb +1 -1
- data/lib/tap/parser.rb +189 -40
- data/lib/tap/support/configurable_class.rb +2 -2
- data/lib/tap/support/gems/rack.rb +1 -0
- data/lib/tap/support/templater.rb +1 -1
- data/lib/tap/task.rb +4 -0
- data/lib/tap/test/script_methods.rb +4 -5
- data/lib/tap/test/script_methods/regexp_escape.rb +3 -1
- data/lib/tap/test/script_methods/script_test.rb +24 -15
- metadata +1 -1
data/bin/rap
CHANGED
@@ -5,7 +5,18 @@ require "#{File.dirname(__FILE__)}/../lib/tap.rb"
|
|
5
5
|
|
6
6
|
# setup the environment
|
7
7
|
begin
|
8
|
+
|
9
|
+
# handle super options
|
10
|
+
$DEBUG = true if ARGV.delete('-d-')
|
8
11
|
env = Tap::Exe.instantiate
|
12
|
+
|
13
|
+
# add the DEFAULT_TASK_FILE if it exists
|
14
|
+
task_file = File.expand_path('tapfile.rb')
|
15
|
+
if File.exists?(task_file)
|
16
|
+
env.requires.unshift(task_file)
|
17
|
+
env.manifest(:tasks).search_paths << [Dir.pwd, task_file]
|
18
|
+
end
|
19
|
+
|
9
20
|
rescue(Tap::Env::ConfigError)
|
10
21
|
# catch errors and exit gracefully
|
11
22
|
# (errors usu from gem loading errors)
|
@@ -13,31 +24,6 @@ rescue(Tap::Env::ConfigError)
|
|
13
24
|
exit(1)
|
14
25
|
end
|
15
26
|
|
16
|
-
# parse super options
|
17
|
-
require 'tap/support/super_optparse'
|
18
|
-
Tap::Support::SuperOptionParser.new do |opts|
|
19
|
-
opts.on("-e", "--env [CONFIG:VALUE]", "set an env configuration") do |arg|
|
20
|
-
config, value = arg.split(":", 2)
|
21
|
-
env.config[config.to_sym] = value
|
22
|
-
end
|
23
|
-
|
24
|
-
opts.on("-a", "--app [CONFIG:VALUE]", "set an app configuration") do |arg|
|
25
|
-
config, value = arg.split(":", 2)
|
26
|
-
env.app.config[config.to_sym] = value
|
27
|
-
end
|
28
|
-
|
29
|
-
opts.on("-d", "set $DEBUG to true") do
|
30
|
-
$DEBUG = true
|
31
|
-
end
|
32
|
-
end.parse!
|
33
|
-
|
34
|
-
# add the DEFAULT_TASK_FILE if it exists
|
35
|
-
task_file = File.expand_path('tapfile.rb')
|
36
|
-
if File.exists?(task_file)
|
37
|
-
env.requires.unshift(task_file)
|
38
|
-
env.manifest(:tasks).search_paths << [Dir.pwd, task_file]
|
39
|
-
end
|
40
|
-
|
41
27
|
#
|
42
28
|
# setup after script
|
43
29
|
#
|
data/bin/tap
CHANGED
@@ -14,7 +14,11 @@ require "#{File.dirname(__FILE__)}/../lib/tap.rb"
|
|
14
14
|
|
15
15
|
# setup the environment
|
16
16
|
begin
|
17
|
+
|
18
|
+
# handle super options
|
19
|
+
$DEBUG = true if ARGV.delete('-d-')
|
17
20
|
env = Tap::Exe.instantiate
|
21
|
+
|
18
22
|
rescue(Tap::Env::ConfigError)
|
19
23
|
# catch errors and exit gracefully
|
20
24
|
# (errors usu from gem loading errors)
|
@@ -22,24 +26,6 @@ rescue(Tap::Env::ConfigError)
|
|
22
26
|
exit(1)
|
23
27
|
end
|
24
28
|
|
25
|
-
# parse super options
|
26
|
-
require 'tap/support/super_optparse'
|
27
|
-
Tap::Support::SuperOptionParser.new do |opts|
|
28
|
-
opts.on("-e", "--env [CONFIG:VALUE]", "set an env configuration") do |arg|
|
29
|
-
config, value = arg.split(":", 2)
|
30
|
-
env.config[config.to_sym] = value
|
31
|
-
end
|
32
|
-
|
33
|
-
opts.on("-a", "--app [CONFIG:VALUE]", "set an app configuration") do |arg|
|
34
|
-
config, value = arg.split(":", 2)
|
35
|
-
env.app.config[config.to_sym] = value
|
36
|
-
end
|
37
|
-
|
38
|
-
opts.on("-d", "set $DEBUG to true") do
|
39
|
-
$DEBUG = true
|
40
|
-
end
|
41
|
-
end.parse!
|
42
|
-
|
43
29
|
#
|
44
30
|
# setup after script
|
45
31
|
#
|
data/lib/tap.rb
CHANGED
data/lib/tap/constants.rb
CHANGED
data/lib/tap/exe.rb
CHANGED
@@ -8,7 +8,7 @@ module Tap
|
|
8
8
|
class << self
|
9
9
|
def instantiate(path=Dir.pwd, logger=Tap::App::DEFAULT_LOGGER, &block)
|
10
10
|
app = Tap::App.instance = Tap::App.new({:root => path}, logger)
|
11
|
-
exe = super(app, load_config(GLOBAL_CONFIG_FILE), app.logger)
|
11
|
+
exe = super(app, load_config(GLOBAL_CONFIG_FILE), app.logger, &block)
|
12
12
|
|
13
13
|
# add all gems if no gems are specified (Note this is VERY SLOW ~ 1/3 the overhead for tap)
|
14
14
|
if !File.exists?(Tap::Env::DEFAULT_CONFIG_FILE)
|
data/lib/tap/parser.rb
CHANGED
@@ -48,6 +48,15 @@ module Tap
|
|
48
48
|
/\A(--)?(\d*)#{Regexp.escape(l)}([\d,]*)#{Regexp.escape(r)}\z/
|
49
49
|
end
|
50
50
|
|
51
|
+
# The escape begin argument
|
52
|
+
ESCAPE_BEGIN = "-."
|
53
|
+
|
54
|
+
# The escape end argument
|
55
|
+
ESCAPE_END = ".-"
|
56
|
+
|
57
|
+
# The parser end flag
|
58
|
+
END_FLAG = "---"
|
59
|
+
|
51
60
|
# Matches any breaking arg (ex: '--', '--+', '--1:2')
|
52
61
|
BREAK = /\A--(\z|[\+\d\:\*\[\{\(])/
|
53
62
|
|
@@ -181,21 +190,26 @@ module Tap
|
|
181
190
|
# An array of task declarations.
|
182
191
|
attr_reader :tasks
|
183
192
|
|
184
|
-
#
|
185
|
-
#
|
186
|
-
attr_reader :
|
193
|
+
# An array of integers indicating which tasks
|
194
|
+
# should be set as globals.
|
195
|
+
attr_reader :globals
|
196
|
+
|
197
|
+
# The internal rounds data; an array of integers mapping to tasks
|
198
|
+
# by index. The integers signify the round the corresponding
|
199
|
+
# task should be assigned to; a nil entry indicates the task
|
200
|
+
# should not be enqued to a round.
|
201
|
+
attr_reader :rounds_map
|
187
202
|
|
188
203
|
# The internal workflow data; an array of [type, targets] pairs
|
189
|
-
#
|
190
|
-
#
|
191
|
-
|
192
|
-
# by target rather than by source.
|
193
|
-
attr_reader :workflows
|
204
|
+
# mapping to tasks by index. The entries signify the workflow
|
205
|
+
# type and targets assigned to the corresponding task.
|
206
|
+
attr_reader :workflow_map
|
194
207
|
|
195
208
|
def initialize(argv=nil)
|
196
209
|
@tasks = []
|
197
|
-
@
|
198
|
-
@
|
210
|
+
@globals = []
|
211
|
+
@rounds_map = []
|
212
|
+
@workflow_map = []
|
199
213
|
|
200
214
|
case argv
|
201
215
|
when String, Array
|
@@ -206,11 +220,85 @@ module Tap
|
|
206
220
|
# Iterates through the argv splitting out task and workflow definitions.
|
207
221
|
# Task definitions are split out (with configurations) along round and/or
|
208
222
|
# workflow break lines. Rounds and workflows are dynamically parsed;
|
209
|
-
# tasks may be reassigned to rounds
|
210
|
-
#
|
223
|
+
# tasks may be reassigned to different rounds or workflows by later
|
224
|
+
# arguments.
|
211
225
|
#
|
212
|
-
#
|
226
|
+
# Parse is non-destructive to argv. If a string argv is provided, parse
|
227
|
+
# splits it into an array using Shellwords.
|
228
|
+
#
|
229
|
+
# ==== Round Assignment
|
230
|
+
# Tasks can be defined and set to a round using the following:
|
231
|
+
#
|
232
|
+
# break assigns task(s) to round
|
233
|
+
# -- next 0
|
234
|
+
# --+ next 1
|
235
|
+
# --++ next 2
|
236
|
+
# --+2 next 2
|
237
|
+
# --+2[1,2,3] 1,2,3 2
|
238
|
+
#
|
239
|
+
# Here all task (except c) are parsed into round 0, then the
|
240
|
+
# final argument reassigns e to round 3.
|
241
|
+
#
|
242
|
+
# p = Parser.new "a -- b --+ c -- d -- e --+3[4]"
|
243
|
+
# p.rounds # => [[0,1,3],[2], nil, [4]]
|
244
|
+
#
|
245
|
+
# ==== Workflow Assignment
|
246
|
+
# All simple workflow patterns except switch can be specified within
|
247
|
+
# the parse syntax (switch is the exception because there is no good
|
248
|
+
# way to define a block from an array).
|
249
|
+
#
|
250
|
+
# break pattern source(s) target(s)
|
251
|
+
# --: sequence last next
|
252
|
+
# --[] fork last next
|
253
|
+
# --{} merge next last
|
254
|
+
# --() sync_merge next last
|
255
|
+
#
|
256
|
+
# example meaning
|
257
|
+
# --1:2 1.sequence(2)
|
258
|
+
# --1:2:3 1.sequence(2,3)
|
259
|
+
# --:2: last.sequence(2,next)
|
260
|
+
# --[] last.fork(next)
|
261
|
+
# --1{2,3,4} 1.merge(2,3,4)
|
262
|
+
# --(2,3,4) last.sync_merge(2,3,4)
|
213
263
|
#
|
264
|
+
# Note how all of the bracketed styles behave similarly; they are
|
265
|
+
# parsed with essentially the same code, only reversing the source
|
266
|
+
# and target in the case of merges.
|
267
|
+
#
|
268
|
+
# Here a and b are sequenced inline. Task c is assigned to no
|
269
|
+
# workflow until the final argument which sequenced b and c.
|
270
|
+
#
|
271
|
+
# p = Parser.new "a --: b -- c --1:2"
|
272
|
+
# p.tasks # => [["a"], ["b"], ["c"]]
|
273
|
+
# p.workflow(:sequence) # => [[0,1],[1,2]]
|
274
|
+
#
|
275
|
+
# ==== Globals
|
276
|
+
# Global instances of task (used, for example, by dependencies) may
|
277
|
+
# be assigned in the parse syntax as well. The break for a global
|
278
|
+
# is '--*'.
|
279
|
+
#
|
280
|
+
# p = Parser.new "a -- b --* global_name --config for --global"
|
281
|
+
# p.globals # => [2]
|
282
|
+
#
|
283
|
+
# ==== Escapes and End Flags
|
284
|
+
# Breaks can be escaped by enclosing them in '-.' and '.-' delimiters;
|
285
|
+
# any number of arguments may be enclosed within the escape. After the
|
286
|
+
# end delimiter, breaks are active once again.
|
287
|
+
#
|
288
|
+
# p = Parser.new "a -- b -- c"
|
289
|
+
# p.tasks # => [["a"], ["b"], ["c"]]
|
290
|
+
#
|
291
|
+
# p = Parser.new "a -. -- b .- -- c"
|
292
|
+
# p.tasks # => [["a", "--", "b"], ["c"]]
|
293
|
+
#
|
294
|
+
# Parsing continues until the end of argv, or a an end flag '---' is
|
295
|
+
# reached. The end flag may also be escaped.
|
296
|
+
#
|
297
|
+
# p = Parser.new "a -- b --- c"
|
298
|
+
# p.tasks # => [["a"], ["b"]]
|
299
|
+
#
|
300
|
+
#--
|
301
|
+
# === Examples
|
214
302
|
# Parse two tasks, with inputs and configs at separate times. Both
|
215
303
|
# are assigned to round 0.
|
216
304
|
#
|
@@ -249,7 +337,7 @@ module Tap
|
|
249
337
|
# using Shellwords):
|
250
338
|
#
|
251
339
|
# p = Parser.new "a --: b --: c --: d"
|
252
|
-
# p.tasks
|
340
|
+
# p.tasks # => [["a"], ["b"], ["c"], ["d"]]
|
253
341
|
# p.workflow(:sequence) # => [[0,1],[1,2],[2,3]]
|
254
342
|
#
|
255
343
|
# p.parse "1[2,3]"
|
@@ -257,19 +345,62 @@ module Tap
|
|
257
345
|
# p.workflow(:fork) # => [[1,[2,3]]]
|
258
346
|
#
|
259
347
|
# p.parse "e --{2,3}"
|
260
|
-
# p.tasks
|
348
|
+
# p.tasks # => [["a"], ["b"], ["c"], ["d"], ["e"]]
|
261
349
|
# p.workflow(:sequence) # => [[0,1]]
|
262
350
|
# p.workflow(:fork) # => [[1,[2,3]]]
|
263
351
|
# p.workflow(:merge) # => [[4,[2,3]]]
|
264
352
|
#
|
353
|
+
# Use escapes ('-.' and '.-') to bring breaks into a task array. Any
|
354
|
+
# number of breaks/args may occur within an escape sequence; breaks
|
355
|
+
# are re-activated after the stop-escape:
|
356
|
+
#
|
357
|
+
# p = Parser.new "a -. -- b -- .- c -- d"
|
358
|
+
# p.tasks # => [["a", "--", "b", "--", "c"], ["d"]]
|
359
|
+
#
|
360
|
+
# Use the stop delimiter to stop parsing (the unparsed argv is
|
361
|
+
# returned by parse):
|
362
|
+
#
|
363
|
+
# argv = ["a", "--", "b", "---", "args", "after", "stop"]
|
364
|
+
# p = Parser.new
|
365
|
+
# p.parse(argv) # => ["args", "after", "stop"]
|
366
|
+
# p.tasks # => [["a"], ["b"]]
|
367
|
+
#
|
265
368
|
def parse(argv)
|
369
|
+
parse!(argv.kind_of?(String) ? argv : argv.dup)
|
370
|
+
end
|
371
|
+
|
372
|
+
# Same as parse, but removes parsed args from argv.
|
373
|
+
def parse!(argv)
|
266
374
|
if argv.kind_of?(String)
|
267
375
|
argv = Shellwords.shellwords(argv)
|
268
376
|
end
|
269
377
|
|
270
|
-
|
378
|
+
round_index = 0
|
271
379
|
current = []
|
272
|
-
|
380
|
+
escape = false
|
381
|
+
while !argv.empty?
|
382
|
+
arg = argv.shift
|
383
|
+
|
384
|
+
# add escaped arguments
|
385
|
+
if escape
|
386
|
+
if arg == ESCAPE_END
|
387
|
+
escape = false
|
388
|
+
else
|
389
|
+
current << arg
|
390
|
+
end
|
391
|
+
|
392
|
+
next
|
393
|
+
end
|
394
|
+
|
395
|
+
# begin escaping if necessary
|
396
|
+
if arg == ESCAPE_BEGIN
|
397
|
+
escape = true
|
398
|
+
next
|
399
|
+
end
|
400
|
+
|
401
|
+
# break if the end flag is reached
|
402
|
+
break if arg == END_FLAG
|
403
|
+
|
273
404
|
# add all non-breaking args to the
|
274
405
|
# current argv array. this should
|
275
406
|
# include all lookups, inputs, and
|
@@ -282,7 +413,8 @@ module Tap
|
|
282
413
|
# unless the current argv is empty,
|
283
414
|
# append and start a new argv
|
284
415
|
unless current.empty?
|
285
|
-
|
416
|
+
add_task(current, round_index)
|
417
|
+
round_index = 0
|
286
418
|
current = []
|
287
419
|
end
|
288
420
|
|
@@ -290,32 +422,36 @@ module Tap
|
|
290
422
|
# and add to the appropriate collection
|
291
423
|
case arg
|
292
424
|
when ROUND
|
293
|
-
|
294
|
-
indicies.each {|index|
|
295
|
-
|
425
|
+
round_index, indicies = parse_round($3, $6)
|
426
|
+
indicies.each {|index| rounds_map[index] = round_index }
|
427
|
+
next
|
428
|
+
|
296
429
|
when SEQUENCE
|
297
430
|
indicies = parse_sequence($2)
|
298
431
|
while indicies.length > 1
|
299
|
-
|
300
|
-
set_workflow(:sequence, source_index, indicies[0])
|
432
|
+
set_workflow(:sequence, indicies.shift, indicies[0])
|
301
433
|
end
|
302
434
|
|
303
|
-
|
435
|
+
when INSTANCE then globals << parse_instance($2)
|
304
436
|
when FORK then set_workflow(:fork, *parse_bracket($2, $3))
|
305
437
|
when MERGE then set_reverse_workflow(:merge, *parse_bracket($2, $3))
|
306
438
|
when SYNC_MERGE then set_reverse_workflow(:sync_merge, *parse_bracket($2, $3))
|
307
439
|
else raise ArgumentError, "invalid break argument: #{arg}"
|
308
440
|
end
|
441
|
+
|
442
|
+
round_index = nil
|
309
443
|
end
|
310
444
|
|
311
445
|
unless current.empty?
|
312
|
-
add_task(current,
|
446
|
+
add_task(current, round_index)
|
313
447
|
end
|
448
|
+
|
449
|
+
argv
|
314
450
|
end
|
315
451
|
|
316
452
|
# Returns an array of [type, targets] objects; the index of
|
317
453
|
# each entry corresponds to the task on which to build the
|
318
|
-
# workflow
|
454
|
+
# workflow.
|
319
455
|
#
|
320
456
|
# If a type is specified, the output is ordered differently;
|
321
457
|
# The return is an array of [source, targets] for the
|
@@ -326,7 +462,7 @@ module Tap
|
|
326
462
|
# recollect reverse types
|
327
463
|
|
328
464
|
workflows = []
|
329
|
-
|
465
|
+
workflow_map.each_with_index do |entry, source|
|
330
466
|
next if entry == nil
|
331
467
|
|
332
468
|
workflows[source] = case entry[0]
|
@@ -353,7 +489,7 @@ module Tap
|
|
353
489
|
#
|
354
490
|
def rounds
|
355
491
|
collected_rounds = []
|
356
|
-
@
|
492
|
+
@rounds_map.each_with_index do |round_index, index|
|
357
493
|
(collected_rounds[round_index] ||= []) << index unless round_index == nil
|
358
494
|
end
|
359
495
|
|
@@ -379,11 +515,18 @@ module Tap
|
|
379
515
|
end
|
380
516
|
|
381
517
|
def build(app)
|
382
|
-
|
383
|
-
|
384
|
-
#
|
385
|
-
|
386
|
-
yield(
|
518
|
+
instances = []
|
519
|
+
|
520
|
+
# instantiate and assign globals
|
521
|
+
globals.each do |index|
|
522
|
+
task, args = yield(tasks[index])
|
523
|
+
task.class.instance = task
|
524
|
+
instances[index] = [task, args]
|
525
|
+
end
|
526
|
+
|
527
|
+
# instantiate the remaining task classes
|
528
|
+
tasks.each_with_index do |args, index|
|
529
|
+
instances[index] ||= yield(args)
|
387
530
|
end
|
388
531
|
|
389
532
|
# build the workflow
|
@@ -403,12 +546,19 @@ module Tap
|
|
403
546
|
queues = rounds.collect do |round|
|
404
547
|
round.each do |index|
|
405
548
|
task, args = instances[index]
|
549
|
+
instances[index] = nil
|
406
550
|
task.enq(*args)
|
407
551
|
end
|
408
552
|
|
409
553
|
app.queue.clear
|
410
554
|
end
|
411
555
|
queues.delete_if {|queue| queue.empty? }
|
556
|
+
|
557
|
+
# notify any args that will be overlooked
|
558
|
+
instances.compact.each do |(instance, args)|
|
559
|
+
next if args.empty?
|
560
|
+
puts "ignoring args: #{instance} [#{args.join(' ')}]"
|
561
|
+
end
|
412
562
|
|
413
563
|
queues
|
414
564
|
end
|
@@ -425,11 +575,11 @@ module Tap
|
|
425
575
|
tasks.length - 1
|
426
576
|
end
|
427
577
|
|
428
|
-
# Sets the targets to the source in
|
578
|
+
# Sets the targets to the source in workflow_map, tracking the
|
429
579
|
# workflow type.
|
430
580
|
def set_workflow(type, source, targets) # :nodoc
|
431
|
-
|
432
|
-
|
581
|
+
workflow_map[source] = [type, targets]
|
582
|
+
[*targets].each {|target| rounds_map[target] = nil }
|
433
583
|
end
|
434
584
|
|
435
585
|
# Sets a reverse workflow... ie the source is set to
|
@@ -438,10 +588,9 @@ module Tap
|
|
438
588
|
targets.each {|target| set_workflow(type, target, source) }
|
439
589
|
end
|
440
590
|
|
441
|
-
def add_task(definition, round_index
|
442
|
-
|
443
|
-
|
444
|
-
@round_indicies[next_index]
|
591
|
+
def add_task(definition, round_index) # :nodoc
|
592
|
+
tasks << definition
|
593
|
+
rounds_map[current_index] = round_index
|
445
594
|
end
|
446
595
|
|
447
596
|
# Yields each round formatted as a string.
|
@@ -88,8 +88,8 @@ module Tap
|
|
88
88
|
# Loads the contents of path as YAML. Returns an empty hash if the path
|
89
89
|
# is empty, does not exist, or is not a file.
|
90
90
|
def load_config(path)
|
91
|
-
|
92
|
-
|
91
|
+
# the last check prevents YAML from auto-loading itself for empty files
|
92
|
+
return {} if path == nil || !File.file?(path) || File.size(path) == 0
|
93
93
|
YAML.load_file(path) || {}
|
94
94
|
end
|
95
95
|
|
@@ -65,7 +65,7 @@ module Tap
|
|
65
65
|
# {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
|
66
66
|
# yamlize {'key' => 'value'} # => "key: value"
|
67
67
|
def yamlize(object)
|
68
|
-
object == nil ? "~" : object
|
68
|
+
object == nil ? "~" : YAML.dump(object)[4...-1].strip
|
69
69
|
end
|
70
70
|
|
71
71
|
# Nest the return of the block in the nesting lines.
|
data/lib/tap/task.rb
CHANGED
@@ -180,6 +180,10 @@ module Tap
|
|
180
180
|
super
|
181
181
|
end
|
182
182
|
|
183
|
+
#--
|
184
|
+
# use with caution... should reset dependencies?
|
185
|
+
attr_writer :instance
|
186
|
+
|
183
187
|
# Returns an instance of self; the instance is a kind of 'global'
|
184
188
|
# instance used in class-level dependencies. See depends_on.
|
185
189
|
def instance
|
@@ -47,14 +47,11 @@ module Tap
|
|
47
47
|
|
48
48
|
def script_test(test_dir=method_root.root)
|
49
49
|
subset_test("SCRIPT", "s") do
|
50
|
-
|
51
|
-
yield(cmd)
|
52
|
-
|
53
|
-
Tap::Root.chdir(test_dir, true) do
|
50
|
+
Tap::Root.chdir(test_dir, true) do
|
54
51
|
Utils.with_argv do
|
55
52
|
puts "\n# == #{method_name}"
|
56
53
|
|
57
|
-
cmd.
|
54
|
+
cmd = ScriptTest.new(default_command_path, env('stepwise')) do |expected, result, msg|
|
58
55
|
case expected
|
59
56
|
when String
|
60
57
|
assert_output_equal(expected, result, msg)
|
@@ -62,6 +59,8 @@ module Tap
|
|
62
59
|
assert_alike(expected, result, msg)
|
63
60
|
end
|
64
61
|
end
|
62
|
+
|
63
|
+
yield(cmd)
|
65
64
|
end
|
66
65
|
end
|
67
66
|
end
|
@@ -62,12 +62,14 @@ module Tap
|
|
62
62
|
regexp_str = ".*?" if regexp_str =~ /^\.*$/
|
63
63
|
substituents << regexp_str
|
64
64
|
end
|
65
|
+
substituents << ""
|
65
66
|
|
66
67
|
splits = str.split(ESCAPE_SEQUENCE).collect do |split|
|
67
68
|
super(split)
|
68
69
|
end
|
69
70
|
splits << "" if splits.empty?
|
70
|
-
|
71
|
+
|
72
|
+
splits.zip(substituents).to_a.flatten.join
|
71
73
|
end
|
72
74
|
|
73
75
|
# Same as escape.
|
@@ -13,10 +13,14 @@ module Tap
|
|
13
13
|
# An array of (command, message, expected, validation)
|
14
14
|
# entries, representing the accumulated test commands.
|
15
15
|
attr_reader :commands
|
16
|
-
|
17
|
-
|
16
|
+
|
17
|
+
attr_reader :stepwise, :run_block
|
18
|
+
|
19
|
+
def initialize(command_path=nil, stepwise=false, &run_block)
|
18
20
|
@command_path = command_path
|
19
21
|
@commands = []
|
22
|
+
@stepwise = stepwise
|
23
|
+
@run_block = run_block
|
20
24
|
end
|
21
25
|
|
22
26
|
# Splits the input string, collecting single-line commands
|
@@ -50,28 +54,33 @@ module Tap
|
|
50
54
|
end
|
51
55
|
|
52
56
|
def check(msg, command, use_regexp_escapes=true, &validation)
|
53
|
-
new_commands = split(command)
|
54
|
-
new_commands.
|
57
|
+
new_commands = split(command)
|
58
|
+
commands = new_commands.collect do |cmd, expected|
|
55
59
|
expected = RegexpEscape.new(expected) if expected && use_regexp_escapes
|
56
|
-
|
60
|
+
[cmd, msg, expected, validation]
|
57
61
|
end
|
62
|
+
|
63
|
+
run(commands)
|
58
64
|
end
|
59
65
|
|
60
66
|
def match(msg, command, regexp=nil, &validation)
|
61
|
-
new_commands = split(command)
|
62
|
-
new_commands.
|
67
|
+
new_commands = split(command)
|
68
|
+
commands = new_commands.collect do |cmd, expected|
|
63
69
|
raise "expected text specified in match command" unless expected == nil
|
64
|
-
|
70
|
+
[cmd, msg, regexp, validation]
|
65
71
|
end
|
72
|
+
|
73
|
+
run(commands)
|
66
74
|
end
|
67
75
|
|
68
|
-
def run(
|
69
|
-
commands.
|
76
|
+
def run(commands)
|
77
|
+
commands.each_with_index do |(cmd, msg, expected, validation), i|
|
70
78
|
start = Time.now
|
71
79
|
result = capture_sh(cmd) {|ok, status, tempfile_path| }
|
72
80
|
elapsed = Time.now - start
|
73
|
-
|
74
|
-
|
81
|
+
|
82
|
+
cmd_msg = commands.length > 1 ? "#{msg} (#{i})" : msg
|
83
|
+
run_block.call(expected, result, %Q{#{cmd_msg}\n% #{cmd}}) if expected
|
75
84
|
validation.call(result) if validation
|
76
85
|
|
77
86
|
if stepwise
|
@@ -80,12 +89,12 @@ module Tap
|
|
80
89
|
%s
|
81
90
|
> %s
|
82
91
|
%s
|
83
|
-
Time Elapsed: %.3fs} % [
|
92
|
+
Time Elapsed: %.3fs} % [cmd_msg, cmd, result, elapsed]
|
84
93
|
|
85
94
|
print "\nContinue? (y/n): "
|
86
95
|
break if gets.strip =~ /^no?$/i
|
87
|
-
else
|
88
|
-
puts "%.3fs : %s" % [elapsed,
|
96
|
+
else
|
97
|
+
puts "%.3fs : %s" % [elapsed, cmd_msg]
|
89
98
|
end
|
90
99
|
end
|
91
100
|
end
|