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 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
@@ -58,7 +58,7 @@ end
58
58
 
59
59
  begin
60
60
  env.activate
61
- env.run do
61
+ env.launch(ARGV) do
62
62
  # give some help
63
63
  require 'tap/support/command_line'
64
64
 
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 = cmdline.split(ARGV).collect do |argvs|
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
@@ -1,7 +1,7 @@
1
1
  module Tap
2
2
  MAJOR = 0
3
3
  MINOR = 10
4
- TINY = 1
4
+ TINY = 2
5
5
 
6
6
  VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
7
7
  WEBSITE="http://tap.rubyforge.org"
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 run(argv=ARGV)
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
- # Executes the block in the specified directory. Makes the directory, if
113
- # necessary when mkdir is specified. Otherwise, indir raises an error
114
- # for non-existant directories, as well as non-directory inputs.
115
- def indir(dir, mkdir=false)
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
- pwd = Dir.pwd
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 input dir to
531
- # the aliased output dir. Raises an error if the filepath is not relative
532
- # to the aliased input dir.
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, input_dir, output_dir)
537
- unless relative_path = relative_filepath(input_dir, filepath)
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
- # Executes the provided block in the specified directory using Root.indir.
559
- def indir(dir, mkdir=false)
560
- Root.indir(self[dir], mkdir) { yield }
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,13 @@
1
+ module Tap
2
+ module Spec
3
+ module FileMethodsClass
4
+ def trs
5
+ @trs ||= (superclass.respond_to?(:trs) ? superclass.trs : nil)
6
+ end
7
+
8
+ def file_test_root
9
+ super.chomp("_spec")
10
+ end
11
+ end
12
+ end
13
+ 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