bahuvrihi-tap 0.10.1 → 0.10.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|