bahuvrihi-tap 0.10.1 → 0.10.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.
- data/History +9 -0
- data/README +1 -0
- data/bin/tap +1 -1
- data/cmd/run.rb +2 -23
- data/lib/tap/constants.rb +1 -1
- data/lib/tap/exe.rb +71 -11
- data/lib/tap/root.rb +27 -23
- data/lib/tap/spec.rb +67 -0
- data/lib/tap/spec/adapter.rb +48 -0
- data/lib/tap/spec/file_methods.rb +16 -0
- data/lib/tap/spec/file_methods_class.rb +13 -0
- data/lib/tap/spec/subset_methods.rb +14 -0
- data/lib/tap/support/command_line.rb +0 -43
- data/lib/tap/support/command_line/parser.rb +121 -0
- data/lib/tap/support/configurable_class.rb +3 -3
- data/lib/tap/support/declarations.rb +2 -2
- data/lib/tap/support/framework_class.rb +6 -4
- data/lib/tap/support/gems/rake.rb +4 -4
- data/lib/tap/support/lazydoc.rb +10 -1
- data/lib/tap/test.rb +82 -1
- data/lib/tap/test/env_vars.rb +1 -1
- data/lib/tap/test/file_methods.rb +128 -138
- data/lib/tap/test/file_methods_class.rb +26 -0
- data/lib/tap/test/script_methods.rb +7 -24
- data/lib/tap/test/subset_methods.rb +6 -163
- data/lib/tap/test/subset_methods_class.rb +128 -0
- data/lib/tap/test/tap_methods.rb +1 -33
- data/lib/tap/test/utils.rb +118 -0
- metadata +10 -1
data/History
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
== 0.10.1 / 2008-08-21
|
|
2
|
+
|
|
3
|
+
Update of Tap with a few improvements to manifests
|
|
4
|
+
and a new manifest command.
|
|
5
|
+
|
|
6
|
+
* Fixed some bugs and extended manifests
|
|
7
|
+
* Bug fixes in generators
|
|
8
|
+
* Added task definitions to Workflow
|
|
9
|
+
|
|
1
10
|
== 0.10.0 / 2008-08-08
|
|
2
11
|
|
|
3
12
|
Major revision. Reworked configurations and the execution
|
data/README
CHANGED
|
@@ -14,6 +14,7 @@ development, and bug tracking.
|
|
|
14
14
|
* Website[http://tap.rubyforge.org]
|
|
15
15
|
* Lighthouse[http://bahuvrihi.lighthouseapp.com/projects/9908-tap-task-application/overview]
|
|
16
16
|
* Github[http://github.com/bahuvrihi/tap/tree/master]
|
|
17
|
+
* {Google Group}[http://groups.google.com/group/ruby-on-tap]
|
|
17
18
|
|
|
18
19
|
=== Additional Notes:
|
|
19
20
|
|
data/bin/tap
CHANGED
data/cmd/run.rb
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
env = Tap::Env.instance
|
|
9
9
|
app = Tap::App.instance
|
|
10
|
-
cmdline = Tap::Support::CommandLine
|
|
11
10
|
|
|
12
11
|
#
|
|
13
12
|
# handle options
|
|
@@ -15,6 +14,7 @@ cmdline = Tap::Support::CommandLine
|
|
|
15
14
|
|
|
16
15
|
dump = false
|
|
17
16
|
OptionParser.new do |opts|
|
|
17
|
+
cmdline = Tap::Support::CommandLine
|
|
18
18
|
|
|
19
19
|
opts.separator ""
|
|
20
20
|
opts.separator "configurations:"
|
|
@@ -48,30 +48,9 @@ end.parse!(ARGV)
|
|
|
48
48
|
# handle options for each specified task
|
|
49
49
|
#
|
|
50
50
|
|
|
51
|
-
rounds =
|
|
52
|
-
argvs.each do |argv|
|
|
53
|
-
ARGV.clear
|
|
54
|
-
ARGV.concat(argv)
|
|
55
|
-
|
|
56
|
-
unless td = cmdline.shift(ARGV)
|
|
57
|
-
# warn nil?
|
|
58
|
-
next
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# attempt lookup the task class
|
|
62
|
-
const = env.search(:tasks, td) or raise "unknown task: #{td}"
|
|
63
|
-
task_class = const.constantize or raise "unknown task: #{td}"
|
|
64
|
-
|
|
65
|
-
# now let the class handle the argv
|
|
66
|
-
task, argv = task_class.instantiate(ARGV, app)
|
|
67
|
-
task.enq *argv.collect! {|str| cmdline.parse_yaml(str) }
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
app.queue.clear
|
|
71
|
-
end
|
|
51
|
+
rounds = env.parse(ARGV)
|
|
72
52
|
ARGV.clear
|
|
73
53
|
|
|
74
|
-
rounds.delete_if {|round| round.empty? }
|
|
75
54
|
if rounds.empty?
|
|
76
55
|
puts "no task specified"
|
|
77
56
|
exit
|
data/lib/tap/constants.rb
CHANGED
data/lib/tap/exe.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
require 'tap/support/command_line/parser'
|
|
2
|
+
|
|
1
3
|
module Tap
|
|
2
4
|
class Exe < Env
|
|
5
|
+
Parser = Support::CommandLine::Parser
|
|
3
6
|
|
|
4
7
|
class << self
|
|
5
8
|
def instantiate
|
|
@@ -28,18 +31,22 @@ module Tap
|
|
|
28
31
|
config :before, nil
|
|
29
32
|
config :after, nil
|
|
30
33
|
config :aliases, {}, &c.hash_or_nil
|
|
31
|
-
|
|
32
|
-
def handle_error(err)
|
|
33
|
-
case
|
|
34
|
-
when $DEBUG
|
|
35
|
-
puts err.message
|
|
36
|
-
puts
|
|
37
|
-
puts err.backtrace
|
|
38
|
-
else puts err.message
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
34
|
|
|
42
|
-
def
|
|
35
|
+
def app
|
|
36
|
+
root
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def handle_error(err)
|
|
40
|
+
case
|
|
41
|
+
when $DEBUG
|
|
42
|
+
puts err.message
|
|
43
|
+
puts
|
|
44
|
+
puts err.backtrace
|
|
45
|
+
else puts err.message
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def launch(argv=ARGV)
|
|
43
50
|
command = argv.shift.to_s
|
|
44
51
|
|
|
45
52
|
if aliases && aliases.has_key?(command)
|
|
@@ -59,5 +66,58 @@ module Tap
|
|
|
59
66
|
end
|
|
60
67
|
end
|
|
61
68
|
end
|
|
69
|
+
|
|
70
|
+
def parse(argv=ARGV)
|
|
71
|
+
parser = Parser.new(argv)
|
|
72
|
+
targets = parser.targets
|
|
73
|
+
|
|
74
|
+
tasks = []
|
|
75
|
+
rounds = parser.rounds.collect do |round|
|
|
76
|
+
round.each do |argv|
|
|
77
|
+
unless td = Parser.shift_arg(argv)
|
|
78
|
+
# warn nil?
|
|
79
|
+
next
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# attempt lookup the task class
|
|
83
|
+
const = search(:tasks, td) or raise ArgumentError, "unknown task: #{td}"
|
|
84
|
+
task_class = const.constantize or raise ArgumentError, "unknown task: #{td}"
|
|
85
|
+
|
|
86
|
+
# now let the class handle the argv
|
|
87
|
+
task, args = task_class.instantiate(argv, app)
|
|
88
|
+
|
|
89
|
+
if !targets.include?(tasks.length)
|
|
90
|
+
task.enq(*args)
|
|
91
|
+
elsif !args.empty?
|
|
92
|
+
raise ArgumentError, "workflow target receives argv: [#{argv.unshift(td).join(', ')}]"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
tasks << task
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
app.queue.clear
|
|
99
|
+
end
|
|
100
|
+
rounds.delete_if {|round| round.empty? }
|
|
101
|
+
|
|
102
|
+
# build the workflow
|
|
103
|
+
|
|
104
|
+
parser.sequences.each do |sequence|
|
|
105
|
+
app.sequence(*sequence.collect {|s| tasks[s]})
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
parser.forks.each do |source, targets|
|
|
109
|
+
app.fork(tasks[source], *targets.collect {|t| tasks[t]})
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
parser.merges.each do |target, sources|
|
|
113
|
+
app.merge(tasks[target], *sources.collect {|s| tasks[s]})
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
parser.sync_merges.each do |target, sources|
|
|
117
|
+
app.sync_merge(tasks[target], *sources.collect {|s| tasks[s]})
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
rounds
|
|
121
|
+
end
|
|
62
122
|
end
|
|
63
123
|
end
|
data/lib/tap/root.rb
CHANGED
|
@@ -78,6 +78,19 @@ module Tap
|
|
|
78
78
|
# as in: relative_filepath('/path', '/path') then the first arg returns nil, and an
|
|
79
79
|
# empty string is returned
|
|
80
80
|
expanded_path[( expanded_dir.chomp("/").length + 1)..-1] || ""
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Generates a target filepath translated from the source_dir to
|
|
84
|
+
# the target_dir. Raises an error if the filepath is not relative
|
|
85
|
+
# to the source_dir.
|
|
86
|
+
#
|
|
87
|
+
# Root.translate("/path/to/file.txt", "/path", "/another/path") # => '/another/path/to/file.txt'
|
|
88
|
+
#
|
|
89
|
+
def translate(path, source_dir, target_dir)
|
|
90
|
+
unless relative_path = relative_filepath(source_dir, path)
|
|
91
|
+
raise ArgumentError, "\n#{path}\nis not relative to:\n#{source_dir}"
|
|
92
|
+
end
|
|
93
|
+
File.join(target_dir, relative_path)
|
|
81
94
|
end
|
|
82
95
|
|
|
83
96
|
# Lists all unique paths matching the input glob patterns.
|
|
@@ -109,10 +122,10 @@ module Tap
|
|
|
109
122
|
end.flatten.uniq
|
|
110
123
|
end
|
|
111
124
|
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
def
|
|
125
|
+
# Like Dir.chdir but makes the directory, if necessary, when
|
|
126
|
+
# mkdir is specified. chdir raises an error for non-existant
|
|
127
|
+
# directories, as well as non-directory inputs.
|
|
128
|
+
def chdir(dir, mkdir=false, &block)
|
|
116
129
|
unless File.directory?(dir)
|
|
117
130
|
if !File.exists?(dir) && mkdir
|
|
118
131
|
FileUtils.mkdir_p(dir)
|
|
@@ -120,14 +133,8 @@ module Tap
|
|
|
120
133
|
raise "not a directory: #{dir}"
|
|
121
134
|
end
|
|
122
135
|
end
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
begin
|
|
126
|
-
Dir.chdir(dir)
|
|
127
|
-
yield
|
|
128
|
-
ensure
|
|
129
|
-
Dir.chdir(pwd)
|
|
130
|
-
end
|
|
136
|
+
|
|
137
|
+
Dir.chdir(dir, &block)
|
|
131
138
|
end
|
|
132
139
|
|
|
133
140
|
# The path root type indicating windows, *nix, or some unknown
|
|
@@ -527,17 +534,14 @@ module Tap
|
|
|
527
534
|
Root.relative_filepath(self[dir], filepath)
|
|
528
535
|
end
|
|
529
536
|
|
|
530
|
-
# Generates a target filepath translated from the aliased
|
|
531
|
-
# the aliased
|
|
532
|
-
# to the aliased
|
|
537
|
+
# Generates a target filepath translated from the aliased source_dir to
|
|
538
|
+
# the aliased target_dir. Raises an error if the filepath is not relative
|
|
539
|
+
# to the aliased source_dir.
|
|
533
540
|
#
|
|
534
541
|
# fp = r.filepath(:in, 'path/to/file.txt') # => '/root_dir/in/path/to/file.txt'
|
|
535
542
|
# r.translate(fp, :in, :out) # => '/root_dir/out/path/to/file.txt'
|
|
536
|
-
def translate(filepath,
|
|
537
|
-
|
|
538
|
-
raise "\n#{filepath}\nis not relative to:\n#{input_dir}"
|
|
539
|
-
end
|
|
540
|
-
filepath(output_dir, relative_path)
|
|
543
|
+
def translate(filepath, source_dir, target_dir)
|
|
544
|
+
Root.translate(filepath, self[source_dir], self[target_dir])
|
|
541
545
|
end
|
|
542
546
|
|
|
543
547
|
# Lists all files in the aliased dir matching the input patterns. Patterns
|
|
@@ -555,9 +559,9 @@ module Tap
|
|
|
555
559
|
Root.vglob(filepath(dir, filename), *vpatterns)
|
|
556
560
|
end
|
|
557
561
|
|
|
558
|
-
#
|
|
559
|
-
def
|
|
560
|
-
Root.
|
|
562
|
+
# chdirs to the specified directory using Root.chdir.
|
|
563
|
+
def chdir(dir, mkdir=false, &block)
|
|
564
|
+
Root.chdir(self[dir], mkdir, &block)
|
|
561
565
|
end
|
|
562
566
|
|
|
563
567
|
private
|
data/lib/tap/spec.rb
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Tap
|
|
2
|
+
module Spec
|
|
3
|
+
|
|
4
|
+
def self.included(base)
|
|
5
|
+
super
|
|
6
|
+
base.send(:include, Tap::Spec::Adapter)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Causes a TestCase to act as a file test, by instantiating a class Tap::Root
|
|
10
|
+
# (trs), and including FileMethods. The root and directories used to
|
|
11
|
+
# instantiate trs can be specified as options. By default file_test_root
|
|
12
|
+
# and the directories {:input => 'input', :output => 'output', :expected => 'expected'}
|
|
13
|
+
# will be used.
|
|
14
|
+
#
|
|
15
|
+
# Note: file_test_root determines a root directory <em>based on the calling file</em>.
|
|
16
|
+
# Be sure to specify the root directory explicitly if you call acts_as_file_test
|
|
17
|
+
# from a file that is NOT meant to be test file.
|
|
18
|
+
def acts_as_file_spec(options={})
|
|
19
|
+
include Tap::Spec::FileMethods
|
|
20
|
+
|
|
21
|
+
options = {
|
|
22
|
+
:root => file_test_root,
|
|
23
|
+
:directories => {:input => 'input', :output => 'output', :expected => 'expected'}
|
|
24
|
+
}.merge(options)
|
|
25
|
+
self.trs = Tap::Root.new(options[:root], options[:directories])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Causes a unit test to act as a tap test -- resulting in the following:
|
|
29
|
+
# - setup using acts_as_file_test
|
|
30
|
+
# - inclusion of Tap::Test::SubsetMethods
|
|
31
|
+
# - inclusion of Tap::Test::InstanceMethods
|
|
32
|
+
#
|
|
33
|
+
# Note: Unless otherwise specified, <tt>acts_as_tap_test</tt> infers a root directory
|
|
34
|
+
# based on the calling file. Be sure to specify the root directory explicitly
|
|
35
|
+
# if you call acts_as_file_test from a file that is NOT meant to be test file.
|
|
36
|
+
# def acts_as_tap_spec(options={})
|
|
37
|
+
# include Tap::Test::SubsetMethods
|
|
38
|
+
# include Tap::Test::FileMethods
|
|
39
|
+
# include Tap::Test::TapMethods
|
|
40
|
+
#
|
|
41
|
+
# acts_as_file_test({:root => file_test_root}.merge(options))
|
|
42
|
+
# end
|
|
43
|
+
#
|
|
44
|
+
# def acts_as_script_spec(options={})
|
|
45
|
+
# include Tap::Test::FileMethods
|
|
46
|
+
# include Tap::Test::ScriptMethods
|
|
47
|
+
#
|
|
48
|
+
# acts_as_file_test({:root => file_test_root}.merge(options))
|
|
49
|
+
# end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
module Tap
|
|
54
|
+
|
|
55
|
+
# Modules facilitating testing. TapMethods are specific to
|
|
56
|
+
# Tap, but SubsetMethods and FileMethods are more general in
|
|
57
|
+
# their utility.
|
|
58
|
+
module Spec
|
|
59
|
+
autoload(:SubsetMethods, 'tap/spec/subset_methods')
|
|
60
|
+
autoload(:FileMethods, 'tap/spec/file_methods')
|
|
61
|
+
autoload(:TapMethods, 'tap/spec/tap_methods')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Tap
|
|
2
|
+
module Spec
|
|
3
|
+
module Adapter
|
|
4
|
+
def method_name
|
|
5
|
+
self.description.strip.gsub(/\s+/, "_")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# A method serving as the dumping ground for 'should ==' statements
|
|
9
|
+
# that otherwise cause a 'useless use of <method> in void context'
|
|
10
|
+
# warning. Useful if you're running tests with -w.
|
|
11
|
+
#
|
|
12
|
+
# check 1.should == 1
|
|
13
|
+
#
|
|
14
|
+
# Check will validate that the line calling check contains a
|
|
15
|
+
# should/should_not statement; the check fails if it does not.
|
|
16
|
+
def check(return_value)
|
|
17
|
+
return false unless SCRIPT_LINES__
|
|
18
|
+
|
|
19
|
+
caller[0] =~ /^(([A-z]:)?[^:]+):(\d+)/
|
|
20
|
+
|
|
21
|
+
check_file = SCRIPT_LINES__[$1]
|
|
22
|
+
violated("could not validate check: #{$1} (#{$3})") unless check_file
|
|
23
|
+
|
|
24
|
+
# note the line number in caller
|
|
25
|
+
# starts at 1, not 0
|
|
26
|
+
line = check_file[$3.to_i - 1]
|
|
27
|
+
case line
|
|
28
|
+
when /\.should(_not)?[^\w]/
|
|
29
|
+
true # pass
|
|
30
|
+
when /^\s+check/
|
|
31
|
+
violated("check used without should/should_not statement: #{line} (#{caller[0]})")
|
|
32
|
+
else
|
|
33
|
+
violated("multiline check statements are not allowed: #{caller[0]}")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Maps flunk to violated.
|
|
38
|
+
def flunk(msg)
|
|
39
|
+
violated(msg)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Maps assert_equal to actual.should == expected.
|
|
43
|
+
def assert_equal(expected, actual, msg=nil)
|
|
44
|
+
check actual.should == expected
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'tap/spec/adapter'
|
|
2
|
+
require 'tap/test/file_methods'
|
|
3
|
+
require 'tap/spec/file_methods_class'
|
|
4
|
+
|
|
5
|
+
module Tap
|
|
6
|
+
module Spec
|
|
7
|
+
module FileMethods
|
|
8
|
+
def self.included(base)
|
|
9
|
+
super
|
|
10
|
+
base.send(:include, Tap::Spec::Adapter)
|
|
11
|
+
base.send(:include, Tap::Test::FileMethods)
|
|
12
|
+
base.extend Tap::Spec::FileMethodsClass
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'tap/spec/adapter'
|
|
2
|
+
require 'tap/test/subset_methods'
|
|
3
|
+
|
|
4
|
+
module Tap
|
|
5
|
+
module Spec
|
|
6
|
+
module SubsetMethods
|
|
7
|
+
def self.included(base)
|
|
8
|
+
super
|
|
9
|
+
base.send(:include, Tap::Spec::Adapter)
|
|
10
|
+
base.send(:include, Tap::Test::SubsetMethods)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -7,49 +7,6 @@ module Tap
|
|
|
7
7
|
module CommandLine
|
|
8
8
|
module_function
|
|
9
9
|
|
|
10
|
-
# Parses the input string as YAML, if the string matches the YAML document
|
|
11
|
-
# specifier (ie it begins with "---\s*\n"). Otherwise returns the string.
|
|
12
|
-
#
|
|
13
|
-
# str = {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
|
|
14
|
-
# Tap::Script.parse_yaml(str) # => {'key' => 'value'}
|
|
15
|
-
# Tap::Script.parse_yaml("str") # => "str"
|
|
16
|
-
def parse_yaml(str)
|
|
17
|
-
str =~ /\A---\s*\n/ ? YAML.load(str) : str
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
SPLIT_ARGV_REGEXP = /\A-{2}(\+*)\z/
|
|
21
|
-
|
|
22
|
-
def split(argv)
|
|
23
|
-
current = []
|
|
24
|
-
current_split = []
|
|
25
|
-
splits = [current_split]
|
|
26
|
-
|
|
27
|
-
argv.each do |arg|
|
|
28
|
-
if arg =~ SPLIT_ARGV_REGEXP
|
|
29
|
-
current_split << current unless current.empty?
|
|
30
|
-
current = []
|
|
31
|
-
current_split = (splits[$1.length] ||= [])
|
|
32
|
-
else
|
|
33
|
-
current << arg
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
current_split << current unless current.empty?
|
|
38
|
-
splits.delete_if {|split| split.nil? || split.empty? }
|
|
39
|
-
splits
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def shift(argv)
|
|
43
|
-
index = nil
|
|
44
|
-
argv.each_with_index do |arg, i|
|
|
45
|
-
if arg !~ /\A-/
|
|
46
|
-
index = i
|
|
47
|
-
break
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
index == nil ? nil : argv.delete_at(index)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
10
|
def usage(path, cols=80)
|
|
54
11
|
parse_usage(File.read(path), cols)
|
|
55
12
|
end
|