tap 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/History +12 -0
  2. data/MIT-LICENSE +0 -2
  3. data/README +23 -32
  4. data/bin/rap +116 -0
  5. data/bin/tap +6 -9
  6. data/cgi/run.rb +67 -0
  7. data/cmd/console.rb +1 -1
  8. data/cmd/destroy.rb +4 -4
  9. data/cmd/generate.rb +4 -4
  10. data/cmd/manifest.rb +61 -53
  11. data/cmd/run.rb +8 -75
  12. data/doc/Class Reference +130 -121
  13. data/doc/Command Reference +76 -124
  14. data/doc/Syntax Reference +290 -0
  15. data/doc/Tutorial +305 -237
  16. data/lib/tap/app.rb +140 -467
  17. data/lib/tap/constants.rb +2 -2
  18. data/lib/tap/declarations.rb +211 -0
  19. data/lib/tap/env.rb +171 -193
  20. data/lib/tap/exe.rb +100 -21
  21. data/lib/tap/file_task.rb +3 -3
  22. data/lib/tap/generator/base.rb +1 -1
  23. data/lib/tap/generator/destroy.rb +10 -10
  24. data/lib/tap/generator/generate.rb +29 -18
  25. data/lib/tap/generator/generators/command/command_generator.rb +2 -2
  26. data/lib/tap/generator/generators/command/templates/command.erb +2 -2
  27. data/lib/tap/generator/generators/config/config_generator.rb +3 -3
  28. data/lib/tap/generator/generators/config/templates/doc.erb +1 -1
  29. data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
  30. data/lib/tap/generator/generators/file_task/templates/task.erb +1 -1
  31. data/lib/tap/generator/generators/file_task/templates/test.erb +1 -1
  32. data/lib/tap/generator/generators/generator/generator_generator.rb +27 -0
  33. data/lib/tap/generator/generators/generator/templates/task.erb +27 -0
  34. data/lib/tap/generator/generators/root/root_generator.rb +13 -13
  35. data/lib/tap/generator/generators/root/templates/README +0 -0
  36. data/lib/tap/generator/generators/root/templates/Rakefile +2 -2
  37. data/lib/tap/generator/generators/root/templates/gemspec +4 -5
  38. data/lib/tap/generator/generators/root/templates/tapfile +11 -8
  39. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
  40. data/lib/tap/generator/generators/task/task_generator.rb +1 -3
  41. data/lib/tap/generator/generators/task/templates/test.erb +1 -3
  42. data/lib/tap/patches/optparse/summarize.rb +62 -0
  43. data/lib/tap/root.rb +41 -29
  44. data/lib/tap/support/aggregator.rb +16 -3
  45. data/lib/tap/support/assignments.rb +10 -9
  46. data/lib/tap/support/audit.rb +58 -64
  47. data/lib/tap/support/class_configuration.rb +33 -44
  48. data/lib/tap/support/combinator.rb +125 -0
  49. data/lib/tap/support/configurable.rb +13 -14
  50. data/lib/tap/support/configurable_class.rb +21 -43
  51. data/lib/tap/support/configuration.rb +55 -9
  52. data/lib/tap/support/constant.rb +87 -13
  53. data/lib/tap/support/constant_manifest.rb +116 -0
  54. data/lib/tap/support/dependencies.rb +54 -0
  55. data/lib/tap/support/dependency.rb +44 -0
  56. data/lib/tap/support/executable.rb +247 -32
  57. data/lib/tap/support/executable_queue.rb +1 -1
  58. data/lib/tap/support/gems/rake.rb +29 -8
  59. data/lib/tap/support/gems.rb +10 -30
  60. data/lib/tap/support/instance_configuration.rb +29 -3
  61. data/lib/tap/support/intern.rb +46 -0
  62. data/lib/tap/support/join.rb +143 -0
  63. data/lib/tap/support/joins/fork.rb +19 -0
  64. data/lib/tap/support/joins/merge.rb +22 -0
  65. data/lib/tap/support/joins/sequence.rb +21 -0
  66. data/lib/tap/support/joins/switch.rb +25 -0
  67. data/lib/tap/support/joins/sync_merge.rb +63 -0
  68. data/lib/tap/support/joins.rb +15 -0
  69. data/lib/tap/support/lazy_attributes.rb +17 -2
  70. data/lib/tap/support/lazydoc/comment.rb +503 -0
  71. data/lib/tap/support/lazydoc/config.rb +17 -0
  72. data/lib/tap/support/lazydoc/definition.rb +36 -0
  73. data/lib/tap/support/lazydoc/document.rb +152 -0
  74. data/lib/tap/support/lazydoc/method.rb +24 -0
  75. data/lib/tap/support/lazydoc.rb +269 -343
  76. data/lib/tap/support/manifest.rb +121 -103
  77. data/lib/tap/support/minimap.rb +90 -0
  78. data/lib/tap/support/node.rb +56 -0
  79. data/lib/tap/support/parser.rb +436 -0
  80. data/lib/tap/support/schema.rb +359 -0
  81. data/lib/tap/support/shell_utils.rb +3 -5
  82. data/lib/tap/support/string_ext.rb +60 -0
  83. data/lib/tap/support/tdoc.rb +7 -2
  84. data/lib/tap/support/templater.rb +30 -16
  85. data/lib/tap/support/validation.rb +77 -8
  86. data/lib/tap/task.rb +431 -143
  87. data/lib/tap/tasks/dump.rb +15 -10
  88. data/lib/tap/tasks/load.rb +112 -0
  89. data/lib/tap/tasks/rake.rb +4 -41
  90. data/lib/tap/test/assertions.rb +38 -0
  91. data/lib/tap/test/env_vars.rb +1 -1
  92. data/lib/tap/test/extensions.rb +79 -0
  93. data/lib/tap/test/file_test.rb +420 -0
  94. data/lib/tap/test/file_test_class.rb +12 -0
  95. data/lib/tap/test/regexp_escape.rb +87 -0
  96. data/lib/tap/test/script_test.rb +46 -0
  97. data/lib/tap/test/script_tester.rb +115 -0
  98. data/lib/tap/test/subset_test.rb +260 -0
  99. data/lib/tap/test/subset_test_class.rb +99 -0
  100. data/lib/tap/test/{tap_methods.rb → tap_test.rb} +45 -43
  101. data/lib/tap/test/utils.rb +231 -0
  102. data/lib/tap/test.rb +53 -26
  103. data/lib/tap.rb +3 -20
  104. metadata +50 -27
  105. data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +0 -15
  106. data/lib/tap/patches/rake/rake_test_loader.rb +0 -8
  107. data/lib/tap/patches/rake/testtask.rb +0 -57
  108. data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -51
  109. data/lib/tap/patches/ruby19/parsedate.rb +0 -16
  110. data/lib/tap/support/batchable.rb +0 -47
  111. data/lib/tap/support/batchable_class.rb +0 -107
  112. data/lib/tap/support/command_line.rb +0 -98
  113. data/lib/tap/support/comment.rb +0 -270
  114. data/lib/tap/support/constant_utils.rb +0 -127
  115. data/lib/tap/support/declarations.rb +0 -111
  116. data/lib/tap/support/framework.rb +0 -83
  117. data/lib/tap/support/framework_class.rb +0 -180
  118. data/lib/tap/support/run_error.rb +0 -39
  119. data/lib/tap/support/summary.rb +0 -30
  120. data/lib/tap/test/file_methods.rb +0 -377
  121. data/lib/tap/test/script_methods/script_test.rb +0 -98
  122. data/lib/tap/test/script_methods.rb +0 -107
  123. data/lib/tap/test/subset_methods.rb +0 -420
  124. data/lib/tap/workflow.rb +0 -200
@@ -19,19 +19,19 @@ module Tap
19
19
  file_task.rmdir(target) unless pretend
20
20
  end
21
21
  end
22
-
22
+
23
23
  def file(target, options={})
24
- target = File.expand_path(target, target_dir)
25
-
26
- if File.exists?(target)
27
- log_relative :rm, target
28
- file_task.added_files << File.expand_path(target)
29
- file_task.rm(target) unless pretend
30
- else
31
- log_relative :missing, target
24
+ target = File.expand_path(target, target_dir)
25
+
26
+ if File.exists?(target)
27
+ log_relative :rm, target
28
+ file_task.added_files << File.expand_path(target)
29
+ file_task.rm(target) unless pretend
30
+ else
31
+ log_relative :missing, target
32
32
  end
33
33
  end
34
+
34
35
  end
35
-
36
36
  end
37
37
  end
@@ -16,25 +16,36 @@ module Tap
16
16
  end
17
17
  end
18
18
 
19
- def file(target, options={})
20
- target = File.expand_path(target, target_dir)
21
-
22
- case
23
- when !File.exists?(target)
24
- log_relative :create, target
25
- # should check for identical...
26
- when force_file_collision?(target)
27
- log_relative :force, target
28
- else
29
- log_relative :skip, target
30
- return
19
+ def file(target, options={})
20
+ source_file = Tempfile.new('generate')
21
+ yield(source_file) if block_given?
22
+ source_file.close
23
+
24
+ source = source_file.path
25
+ target = File.expand_path(target, target_dir)
26
+
27
+ copy_file = case
28
+ when !File.exists?(target)
29
+ log_relative :create, target
30
+ true
31
+ when FileUtils.cmp(source, target)
32
+ log_relative :exists, target
33
+ false
34
+ when force_file_collision?(target)
35
+ log_relative :force, target
36
+ true
37
+ else
38
+ log_relative :skip, target
39
+ false
40
+ end
41
+
42
+ if copy_file && !pretend
43
+ file_task.prepare(target)
44
+ FileUtils.mv(source, target)
31
45
  end
32
-
33
- unless pretend
34
- file_task.prepare(target)
35
- File.open(target, "wb") {|file| yield(file) if block_given? }
36
- end
37
- end
46
+ end
47
+
48
+ protected
38
49
 
39
50
  # Ask the user interactively whether to force collision.
40
51
  def force_file_collision?(target)
@@ -1,6 +1,6 @@
1
1
  module Tap::Generator::Generators
2
2
 
3
- # :startdoc::generator a new tap command
3
+ # :startdoc: Tap::Generator::Generators::CommandGenerator::generator a new tap command
4
4
  #
5
5
  # Generates a new tap command under the cmd directory. The
6
6
  # new command can be run from the command line using:
@@ -18,4 +18,4 @@ module Tap::Generator::Generators
18
18
  end
19
19
 
20
20
  end
21
- end
21
+ end
@@ -16,7 +16,7 @@ OptionParser.new do |opts|
16
16
  opts.separator "options:"
17
17
 
18
18
  opts.on("-h", "--help", "Show this message") do
19
- opts.banner = Tap::Support::CommandLine.usage(__FILE__)
19
+ opts.banner = Tap::Support::Lazydoc.usage(__FILE__)
20
20
  puts opts
21
21
  exit
22
22
  end
@@ -29,4 +29,4 @@ end.parse!(ARGV)
29
29
  #
30
30
 
31
31
  puts "Received: #{ARGV.join(', ')}"
32
- puts app.info
32
+ puts app.info
@@ -1,6 +1,6 @@
1
1
  module Tap::Generator::Generators
2
2
 
3
- # :startdoc::generator a config file for a task
3
+ # :startdoc: Tap::Generator::Generators::ConfigGenerator::generator a config file for a task
4
4
  #
5
5
  # Generates a new config file for a task. The configurations, defaults,
6
6
  # and documentation is determined from the task source file.
@@ -13,12 +13,12 @@ module Tap::Generator::Generators
13
13
  end
14
14
 
15
15
  def manifest(m, name, config_name=name)
16
- const = env.search(:tasks, name) or raise "unknown task: #{name}"
16
+ const = env.tasks.search(name) or raise "unknown task: #{name}"
17
17
  task_class = const.constantize or raise "unknown task: #{name}"
18
18
 
19
19
  m.directory app['config']
20
20
  m.file app.filepath('config', config_name + '.yml') do |file|
21
- task_class.configurations.format_str((doc ? :doc : :nodoc), file)
21
+ task_class.configurations.inspect((doc ? :doc : :nodoc), file)
22
22
  end
23
23
  end
24
24
 
@@ -3,7 +3,7 @@
3
3
  ###############################################################################
4
4
  <% configurations.each do |key, config| %>
5
5
 
6
- <% Comment.wrap(config.desc.to_s.split(/\r?\n/), 50, 2).each do |line| %>
6
+ <% Lazydoc::Comment.wrap(config.desc.to_s, 50, 2).each do |line| %>
7
7
  # <%= line %>
8
8
  <% end %>
9
9
  <%= config.default == nil ? '#' : '' %><%= yamlize({key.to_s => config.default}) %>
@@ -2,7 +2,7 @@ require 'tap/generator/generators/task/task_generator'
2
2
 
3
3
  module Tap::Generator::Generators
4
4
 
5
- # :startdoc::generator a file_task and test
5
+ # :startdoc: Tap::Generator::Generators::FileTaskGenerator::generator a file_task and test
6
6
  #
7
7
  # Generates a new Tap::FileTask and associated test files.
8
8
  class FileTaskGenerator < TaskGenerator
@@ -25,7 +25,7 @@ class <%= const.const_name %> < Tap::FileTask
25
25
  end
26
26
 
27
27
  File.open(target, "wb") do |file|
28
- file << letter_count.to_yaml
28
+ file << YAML.dump(letter_count)
29
29
  end
30
30
 
31
31
  target
@@ -17,7 +17,7 @@ class <%= const.name %>Test < Test::Unit::TestCase
17
17
  t = <%= const.name %>.new
18
18
  assert_files do |input_files|
19
19
  input_files.each do |source|
20
- target = method_filepath(:output, 'result.yml')
20
+ target = method_root.filepath(:output, 'result.yml')
21
21
  t.enq(source, target)
22
22
  end
23
23
 
@@ -0,0 +1,27 @@
1
+ module Tap::Generator::Generators
2
+
3
+ # :startdoc: Tap::Generator::Generators::GeneratorGenerator::generator a generator task and test
4
+ #
5
+ # Generates a new generator.
6
+ class GeneratorGenerator < Tap::Generator::Base
7
+
8
+ def manifest(m, const_name)
9
+ const = Constant.new(const_name.camelize)
10
+ dir= File.join('lib', const.path)
11
+
12
+ # make the directory
13
+ m.directory app.filepath(dir)
14
+
15
+ # make the generator
16
+ m.template app.filepath(dir, const.basename + '_generator.rb'), "task.erb", :const => const
17
+
18
+ # make the templates directory
19
+ m.directory app.filepath(dir, 'templates')
20
+ m.file app.filepath(dir, 'templates', 'template_file.erb') do |file|
21
+ file.puts "# A sample template file."
22
+ file.puts "key: <%= key %>"
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ <% redirect do |target| %># <%= const.name %>::generator <replace with manifest summary>
2
+ # <replace with command line description>
3
+
4
+ # <%= const.const_name %> Documentation
5
+ class <%= const.const_name %> < Tap::Generator::Base
6
+
7
+ config :key, 'value' # a sample config
8
+
9
+ # The generator will receive the inputs on the command line, and
10
+ # m, a Manifest object that records the actions of this method.
11
+ def manifest(m, *inputs)
12
+
13
+ # make a directory
14
+ # m.directory path
15
+
16
+ # make a file
17
+ # m.file path do |file|
18
+ # file << contents
19
+ # end
20
+
21
+ # template a file in the templates directory using ERB.
22
+ # The (key, value) pairs will be available in the
23
+ # template as local variables.
24
+ m.template "<%= const.const_name.underscore %>_file.txt", "template_file.erb", :key => 'value'
25
+
26
+ end
27
+ end <% module_nest(const.nesting, ' ') { target } end %>
@@ -2,26 +2,26 @@ require 'tap/root'
2
2
 
3
3
  module Tap::Generator::Generators
4
4
 
5
- # :startdoc::generator a basic tap directory structure
5
+ # :startdoc: Tap::Generator::Generators::RootGenerator::generator a basic tap directory structure
6
6
  #
7
- # Generates a tap root directory structure:
7
+ # Generates a tap root directory structure. Use the switches to
8
+ # generate a Tapfile and/or a tap config file:
8
9
  #
9
10
  # root
10
11
  # |- Rakefile
11
12
  # |- lib
12
13
  # |- sample.gemspec
13
14
  # |- tap.yml
14
- # |- tapfile.rb
15
+ # |- Tapfile
15
16
  # `- test
16
17
  # |- tap_test_helper.rb
17
18
  # |- tap_test_suite.rb
18
19
  # `- tapfile_test.rb
19
20
  #
20
- # By default a tapfile will be created, but not a config file.
21
21
  class RootGenerator < Tap::Generator::Base
22
22
 
23
- config :config_file, false, &c.switch # create a tap.yml file
24
- config :tapfile, true, &c.switch # create a tapfile
23
+ config :config_file, true, &c.switch # create a tap.yml file
24
+ config :tapfile, false, &c.switch # create a tapfile
25
25
 
26
26
  # ::args ROOT, PROJECT_NAME=basename(ROOT)
27
27
  def manifest(m, root, project_name=nil)
@@ -35,26 +35,26 @@ module Tap::Generator::Generators
35
35
  case
36
36
  when File.directory?(source)
37
37
  m.directory r[target]
38
+ next
38
39
  when target == 'gemspec'
39
40
  m.template r[project_name + '.gemspec'], source, :project_name => project_name, :tapfile => tapfile, :config_file => config_file
40
- when target =~ /tapfile/
41
+ next
42
+ when target =~ /tapfile/i
41
43
  next unless tapfile
42
- target = (target == 'tapfile' ? r['tapfile.rb'] : r[target])
43
- m.template target, source, :project_name => project_name
44
- else
45
- m.template r[target], source, :project_name => project_name
46
44
  end
45
+
46
+ m.template r[target], source, :project_name => project_name
47
47
  end
48
48
 
49
49
  m.file(r['tap.yml']) do |file|
50
- Tap::App.configurations.format_str(:doc, file) do |templater|
50
+ Tap::App.configurations.inspect(:doc, file) do |templater|
51
51
  next unless templater.receiver == Tap::Root
52
52
 
53
53
  templater.configurations.each do |(key, config)|
54
54
  config.default = nil if key.to_s == 'root'
55
55
  end
56
56
  end
57
- Tap::Env.configurations.format_str(:doc, file)
57
+ Tap::Env.configurations.inspect(:doc, file)
58
58
  end if config_file
59
59
  end
60
60
  end
@@ -4,7 +4,6 @@ require 'rake/rdoctask'
4
4
  require 'rake/gempackagetask'
5
5
 
6
6
  require 'tap/constants'
7
- require 'tap/patches/rake/testtask.rb'
8
7
 
9
8
  #
10
9
  # Gem specification
@@ -36,7 +35,7 @@ task :print_manifest do
36
35
  # included already (marking by the absence
37
36
  # of a label)
38
37
  Dir.glob("**/*").each do |file|
39
- next if file =~ /^(rdoc|pkg)/ || File.directory?(file)
38
+ next if file =~ /^(rdoc|pkg|backup)/ || File.directory?(file)
40
39
 
41
40
  path = File.expand_path(file)
42
41
  files[path] = ["", file] unless files.has_key?(path)
@@ -58,6 +57,7 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
58
57
 
59
58
  rdoc.rdoc_dir = 'rdoc'
60
59
  rdoc.title = '<%= project_name %>'
60
+ rdoc.main = 'README'
61
61
  rdoc.options << '--line-numbers' << '--inline-source'
62
62
  rdoc.rdoc_files.include( spec.extra_rdoc_files )
63
63
  rdoc.rdoc_files.include( spec.files.select {|file| file =~ /^lib.*\.rb$/} )
@@ -5,24 +5,23 @@ Gem::Specification.new do |s|
5
5
  #s.email = "your.email@pubfactory.edu"
6
6
  #s.homepage = "http://rubyforge.org/projects/<%= project_name %>/"
7
7
  s.platform = Gem::Platform::RUBY
8
- s.summary = "<%= project_name %> task library"
8
+ s.summary = "<%= project_name %>"
9
9
  s.require_path = "lib"
10
10
  s.test_file = "test/tap_test_suite.rb"
11
11
  #s.rubyforge_project = "<%= project_name %>"
12
12
  #s.has_rdoc = true
13
- s.add_dependency("tap", "~> <%= Tap::VERSION %>")
13
+ s.add_dependency("tap", "= <%= Tap::VERSION %>")
14
14
 
15
- # list extra rdoc files like README here.
15
+ # list extra rdoc files here.
16
16
  s.extra_rdoc_files = %W{
17
+ README
17
18
  }
18
19
 
19
20
  # list the files you want to include here. you can
20
21
  # check this manifest using 'rake :print_manifest'
21
22
  s.files = %W{
22
23
  <%= config_file ? " tap.yml\n" : '' %>
23
- <%= tapfile ? " tapfile.rb\n" : '' %>
24
24
  test/tap_test_helper.rb
25
25
  test/tap_test_suite.rb
26
- test/tapfile_test.rb
27
26
  }
28
27
  end
@@ -1,8 +1,11 @@
1
- require 'tap'
2
-
3
- # Goodnight::manifest your basic goodnight moon task
4
- # Prints the input with a configurable message.
5
- Tap.task('goodnight', :message => 'goodnight') do |task, name|
6
- task.log task.message, name
7
- "#{task.message} #{name}"
8
- end
1
+ require 'tap/declarations'
2
+
3
+ module <%= project_name.camelize %>
4
+ extend Tap::Declarations
5
+
6
+ # ::desc your basic goodnight moon task
7
+ # Says goodnight with a configurable message.
8
+ task(:goodnight, :obj, :message => 'goodnight') do |task, args|
9
+ puts "#{task.message} #{args.obj}"
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  $:.unshift File.join(File.dirname(__FILE__), '../lib')
2
2
 
3
- # runs all subsets (see Tap::Test::SubsetMethods)
3
+ # runs all subsets (see Tap::Test::SubsetTest)
4
4
  ENV["ALL"] = "true"
5
5
  Dir.glob("./**/*_test.rb").each {|test| require test}
@@ -1,6 +1,6 @@
1
1
  module Tap::Generator::Generators
2
2
 
3
- # :startdoc::generator a task and test
3
+ # :startdoc: Tap::Generator::Generators::TaskGenerator::generator a task and test
4
4
  #
5
5
  # Generates a new Tap::Task and an associated test file.
6
6
  class TaskGenerator < Tap::Generator::Base
@@ -19,8 +19,6 @@ module Tap::Generator::Generators
19
19
  m.directory File.dirname(test_path)
20
20
  m.template test_path, "test.erb", :const => const
21
21
  end
22
-
23
- const
24
22
  end
25
23
 
26
24
  end
@@ -12,9 +12,7 @@ class <%= const.name %>Test < Test::Unit::TestCase
12
12
  assert_equal "goodnight moon", task.process("moon")
13
13
 
14
14
  # a more complex test
15
- task.enq("moon")
16
- app.run
17
-
15
+ task.execute("moon")
18
16
  assert_equal ["goodnight moon"], app.results(task)
19
17
  assert_audit_equal ExpAudit[[nil, "moon"], [task, "goodnight moon"]], app._results(task)[0]
20
18
  end
@@ -0,0 +1,62 @@
1
+ #--
2
+ # This patch fixes some formatting errors in OptParse.
3
+ # In particular, long config names and config names of
4
+ # 13 characters in length cause either ugly wrapping,
5
+ # or an outright error. It could also wrap long comments,
6
+ # although that feature is currently disabled.
7
+ #
8
+ # See:
9
+ # - http://bahuvrihi.lighthouseapp.com/projects/9908/tickets/97-unlucky-13-character-config-name#ticket-97-1
10
+
11
+ class OptionParser # :nodoc:
12
+ class Switch # :nodoc:
13
+ undef_method :summarize
14
+
15
+ def summarize(sdone = [], ldone = [], width = 1, max = width - 1, indent = "")
16
+ sopts, lopts = [], []
17
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
18
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
19
+ return if sopts.empty? and lopts.empty? # completely hidden
20
+
21
+ left = [sopts.join(', ')]
22
+ right = desc.dup
23
+
24
+ while str = lopts.shift
25
+ l = left[-1].length + str.length
26
+ l += arg.length if left.size == 1 && arg
27
+ #l < max or left << ''
28
+ left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << str
29
+ end
30
+
31
+ #left[0] << arg if arg
32
+ left[-1] << arg if arg
33
+
34
+ mlen = left.collect {|s| s.length}.max.to_i
35
+ while mlen > width and l = left.shift
36
+ mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen
37
+ yield(indent + l)
38
+ end
39
+
40
+ # uncomment to justify long comments
41
+ # comment_indent = width + indent.length + 2
42
+ # split_right = []
43
+ # right.each do |obj|
44
+ # start_index = 0
45
+ # str = obj.to_str
46
+ # while start_index < str.length
47
+ # split_right << str[start_index, comment_indent].strip
48
+ # start_index += comment_indent
49
+ # end
50
+ # end
51
+ # right = split_right
52
+
53
+ while begin l = left.shift; r = right.shift; l or r end
54
+ l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
55
+ #yield(indent + l)
56
+ yield(indent + l) unless l == nil
57
+ end
58
+
59
+ self
60
+ end
61
+ end
62
+ end
data/lib/tap/root.rb CHANGED
@@ -79,6 +79,19 @@ module Tap
79
79
  # empty string is returned
80
80
  expanded_path[( expanded_dir.chomp("/").length + 1)..-1] || ""
81
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)
94
+ end
82
95
 
83
96
  # Lists all unique paths matching the input glob patterns.
84
97
  def glob(*patterns)
@@ -109,25 +122,21 @@ 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)
129
+ dir = File.expand_path(dir)
130
+
116
131
  unless File.directory?(dir)
117
132
  if !File.exists?(dir) && mkdir
118
133
  FileUtils.mkdir_p(dir)
119
134
  else
120
- raise "not a directory: #{dir}"
135
+ raise ArgumentError, "not a directory: #{dir}"
121
136
  end
122
137
  end
123
-
124
- pwd = Dir.pwd
125
- begin
126
- Dir.chdir(dir)
127
- yield
128
- ensure
129
- Dir.chdir(pwd)
130
- end
138
+
139
+ Dir.chdir(dir, &block)
131
140
  end
132
141
 
133
142
  # The path root type indicating windows, *nix, or some unknown
@@ -257,7 +266,7 @@ module Tap
257
266
  end.compact
258
267
  end
259
268
  end
260
-
269
+
261
270
  # Returns true if the mini_path matches path. Matching logic
262
271
  # reverses that of minimize:
263
272
  # * a match occurs when path ends with mini_path
@@ -286,8 +295,7 @@ module Tap
286
295
  # Tap::Root.minimal_match?('dir/file-0.1.0.txt', 'r/file') # => true
287
296
  #
288
297
  def minimal_match?(path, mini_path)
289
- extname = File.extname(mini_path)
290
- extname = '' if extname =~ /^\.\d+$/
298
+ extname = non_version_extname(mini_path)
291
299
  version = mini_path =~ /(-\d+(\.\d+)*)#{extname}$/ ? $1 : ''
292
300
 
293
301
  match_path = case
@@ -296,10 +304,10 @@ module Tap
296
304
  path
297
305
  when !version.empty?
298
306
  # match up to version
299
- path.chomp(File.extname(path))
307
+ path.chomp(non_version_extname(path))
300
308
  else
301
309
  # match up base
302
- path.chomp(File.extname(path)).sub(/(-\d+(\.\d+)*)$/, '')
310
+ path.chomp(non_version_extname(path)).sub(/(-\d+(\.\d+)*)$/, '')
303
311
  end
304
312
 
305
313
  # key ends with pattern AND basenames of each are equal...
@@ -391,6 +399,13 @@ module Tap
391
399
  just_one
392
400
  end
393
401
 
402
+ # utility method for minimal_match -- returns a non-version
403
+ # extname, or an empty string if the path ends in a version.
404
+ def non_version_extname(path) # :nodoc:
405
+ extname = File.extname(path)
406
+ extname =~ /^\.\d+$/ ? '' : extname
407
+ end
408
+
394
409
  end
395
410
 
396
411
  include Support::Versions
@@ -527,17 +542,14 @@ module Tap
527
542
  Root.relative_filepath(self[dir], filepath)
528
543
  end
529
544
 
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.
545
+ # Generates a target filepath translated from the aliased source_dir to
546
+ # the aliased target_dir. Raises an error if the filepath is not relative
547
+ # to the aliased source_dir.
533
548
  #
534
549
  # fp = r.filepath(:in, 'path/to/file.txt') # => '/root_dir/in/path/to/file.txt'
535
550
  # 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)
551
+ def translate(filepath, source_dir, target_dir)
552
+ Root.translate(filepath, self[source_dir], self[target_dir])
541
553
  end
542
554
 
543
555
  # Lists all files in the aliased dir matching the input patterns. Patterns
@@ -555,9 +567,9 @@ module Tap
555
567
  Root.vglob(filepath(dir, filename), *vpatterns)
556
568
  end
557
569
 
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 }
570
+ # chdirs to the specified directory using Root.chdir.
571
+ def chdir(dir, mkdir=false, &block)
572
+ Root.chdir(self[dir], mkdir, &block)
561
573
  end
562
574
 
563
575
  private
@@ -2,9 +2,22 @@ module Tap
2
2
  module Support
3
3
 
4
4
  # Aggregator allows thread-safe collection of Audits, organized
5
- # by Audit#_current_source.
5
+ # by Audit#_current_source.
6
+ #
7
+ # a = Audit.new
8
+ # a._record(:src, 'a')
9
+ #
10
+ # b = Audit.new
11
+ # b._record(:src, 'b')
12
+ #
13
+ # agg = Aggregator.new
14
+ # agg.store(a)
15
+ # agg.store(b)
16
+ # agg.retrieve(:src) # => [a, b]
17
+ #
6
18
  class Aggregator < Monitor
7
-
19
+
20
+ # Creates a new Aggregator.
8
21
  def initialize
9
22
  super
10
23
  clear
@@ -35,7 +48,7 @@ module Tap
35
48
  synchronize { hash[source] }
36
49
  end
37
50
 
38
- # Retreives all audits for the input sources, joined into an array.
51
+ # Retreives all audits for the input sources, joined as an array.
39
52
  def retrieve_all(*sources)
40
53
  synchronize do
41
54
  sources.collect {|src| hash[src] }.flatten.compact