bahuvrihi-tap 0.10.4 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/bin/rap +112 -0
  2. data/bin/tap +21 -10
  3. data/cmd/destroy.rb +1 -1
  4. data/cmd/generate.rb +1 -1
  5. data/cmd/run.rb +4 -48
  6. data/cmd/server.rb +3 -1
  7. data/lib/tap/constants.rb +1 -1
  8. data/lib/tap/env.rb +37 -39
  9. data/lib/tap/exe.rb +59 -29
  10. data/lib/tap/generator/base.rb +1 -1
  11. data/lib/tap/generator/generators/config/templates/doc.erb +1 -1
  12. data/lib/tap/generator/generators/file_task/templates/test.erb +1 -1
  13. data/lib/tap/generator/generators/root/templates/README +0 -0
  14. data/lib/tap/generator/generators/root/templates/gemspec +3 -4
  15. data/lib/tap/generator/generators/root/templates/tapfile +3 -3
  16. data/lib/tap/parser.rb +35 -0
  17. data/lib/tap/patches/optparse/summarize.rb +62 -0
  18. data/lib/tap/root.rb +24 -18
  19. data/lib/tap/support/class_configuration.rb +1 -1
  20. data/lib/tap/support/configurable_class.rb +3 -1
  21. data/lib/tap/support/configuration.rb +19 -0
  22. data/lib/tap/support/constant.rb +14 -2
  23. data/lib/tap/support/declarations.rb +33 -39
  24. data/lib/tap/support/dependable.rb +21 -2
  25. data/lib/tap/support/gems.rb +4 -30
  26. data/lib/tap/support/gems/rack.rb +14 -11
  27. data/lib/tap/support/lazy_attributes.rb +1 -1
  28. data/lib/tap/support/lazydoc.rb +257 -340
  29. data/lib/tap/support/lazydoc/comment.rb +499 -0
  30. data/lib/tap/support/lazydoc/config.rb +17 -0
  31. data/lib/tap/support/lazydoc/declaration.rb +20 -0
  32. data/lib/tap/support/lazydoc/document.rb +118 -0
  33. data/lib/tap/support/lazydoc/method.rb +24 -0
  34. data/lib/tap/support/manifest.rb +33 -4
  35. data/lib/tap/support/validation.rb +56 -0
  36. data/lib/tap/task.rb +46 -44
  37. data/lib/tap/tasks/dump.rb +15 -10
  38. data/lib/tap/tasks/load.rb +25 -0
  39. data/lib/tap/tasks/rake.rb +2 -2
  40. data/lib/tap/test.rb +55 -36
  41. data/lib/tap/test/file_methods.rb +204 -178
  42. data/lib/tap/test/file_methods_class.rb +4 -18
  43. data/lib/tap/test/script_methods.rb +76 -90
  44. data/lib/tap/test/script_methods/regexp_escape.rb +92 -0
  45. data/lib/tap/test/script_methods/script_test.rb +4 -2
  46. data/lib/tap/test/subset_methods.rb +46 -49
  47. data/lib/tap/test/subset_methods_class.rb +17 -54
  48. data/lib/tap/test/tap_methods.rb +1 -5
  49. data/lib/tap/test/utils.rb +142 -32
  50. metadata +12 -3
  51. data/lib/tap/support/command_line.rb +0 -55
  52. data/lib/tap/support/comment.rb +0 -270
data/bin/rap ADDED
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env ruby
2
+ # usage: rap taskname {options} [args]
3
+
4
+ require "#{File.dirname(__FILE__)}/../lib/tap.rb"
5
+
6
+ # setup the environment
7
+ begin
8
+ env = Tap::Exe.instantiate
9
+ rescue(Tap::Env::ConfigError)
10
+ # catch errors and exit gracefully
11
+ # (errors usu from gem loading errors)
12
+ puts $!.message
13
+ exit(1)
14
+ end
15
+
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
+ #
42
+ # setup after script
43
+ #
44
+
45
+ at_exit do
46
+ begin
47
+ eval(env.after) if env.after != nil
48
+ rescue(Exception)
49
+ puts "Error in after script."
50
+ env.handle_error($!)
51
+ exit(1)
52
+ end
53
+ end
54
+
55
+ #
56
+ # run before script
57
+ #
58
+
59
+ begin
60
+ eval(env.before) if env.before != nil
61
+ rescue(Exception)
62
+ puts "Error in before script."
63
+ env.handle_error($!)
64
+ exit(1)
65
+ end
66
+
67
+ #
68
+ # run rap
69
+ #
70
+
71
+ module Tap
72
+ module Tasks
73
+ autoload(:Rake, 'tap/tasks/rake')
74
+ end
75
+ end
76
+
77
+ begin
78
+ env.activate
79
+
80
+ case ARGV[0]
81
+ when '--help', nil, '-T'
82
+ puts Tap::Support::Lazydoc.usage(__FILE__)
83
+ puts
84
+ puts "=== tap tasks ==="
85
+ puts env.summarize(:tasks) {|const| const.document[const.name]['manifest'] }
86
+ puts
87
+ puts "=== rake tasks ==="
88
+ Tap::Tasks::Rake.new.enq('-T')
89
+ Tap::App.instance.run
90
+
91
+ # this is not currently reached as rake exits on -T
92
+ puts
93
+ puts "version #{Tap::VERSION} -- #{Tap::WEBSITE}"
94
+ exit
95
+ else
96
+ queues = env.build(ARGV) {|args| Tap::Tasks::Rake }
97
+ ARGV.clear
98
+
99
+ if queues.empty?
100
+ puts "no task specified"
101
+ exit
102
+ end
103
+
104
+ env.set_signals
105
+ env.run(queues)
106
+ end
107
+
108
+ rescue
109
+ env.handle_error($!)
110
+ end
111
+
112
+ exit(0)
data/bin/tap CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/local/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
  # usage: tap <command> {options} [args]
3
3
  #
4
4
  # examples:
@@ -6,19 +6,15 @@
6
6
  # tap run taskname --option input # runs the 'taskname' task
7
7
  #
8
8
  # help:
9
- # tap help # prints this help
9
+ # tap --help # prints this help
10
10
  # tap command --help # prints help for 'command'
11
11
  #
12
12
 
13
13
  require "#{File.dirname(__FILE__)}/../lib/tap.rb"
14
- require 'tap/exe'
15
14
 
16
15
  # setup the environment
17
16
  begin
18
-
19
- $DEBUG = true if ARGV.delete('-d-')
20
17
  env = Tap::Exe.instantiate
21
-
22
18
  rescue(Tap::Env::ConfigError)
23
19
  # catch errors and exit gracefully
24
20
  # (errors usu from gem loading errors)
@@ -26,6 +22,24 @@ rescue(Tap::Env::ConfigError)
26
22
  exit(1)
27
23
  end
28
24
 
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
+
29
43
  #
30
44
  # setup after script
31
45
  #
@@ -59,10 +73,7 @@ end
59
73
  begin
60
74
  env.activate
61
75
  env.execute(ARGV) do
62
- # give some help
63
- require 'tap/support/command_line'
64
-
65
- puts Tap::Support::CommandLine.usage(__FILE__)
76
+ puts Tap::Support::Lazydoc.usage(__FILE__)
66
77
  puts
67
78
  puts "available commands:"
68
79
  puts env.summarize(:commands)
data/cmd/destroy.rb CHANGED
@@ -12,5 +12,5 @@ name = ARGV.shift
12
12
  const = env.search(:generators, name) or raise "unknown generator: #{name}"
13
13
 
14
14
  generator_class = const.constantize
15
- generator, argv = generator_class.instantiate(ARGV)
15
+ generator, argv = generator_class.parse(ARGV)
16
16
  generator.extend(Tap::Generator::Destroy).process(*argv)
data/cmd/generate.rb CHANGED
@@ -12,5 +12,5 @@ name = ARGV.shift
12
12
  const = env.search(:generators, name) or raise "unknown generator: #{name}"
13
13
 
14
14
  generator_class = const.constantize
15
- generator, argv = generator_class.instantiate(ARGV)
15
+ generator, argv = generator_class.parse(ARGV)
16
16
  generator.extend(Tap::Generator::Generate).process(*argv)
data/cmd/run.rb CHANGED
@@ -14,15 +14,13 @@ app = Tap::App.instance
14
14
 
15
15
  dump = false
16
16
  OptionParser.new do |opts|
17
- cmdline = Tap::Support::CommandLine
18
-
19
17
  opts.separator ""
20
18
  opts.separator "configurations:"
21
19
 
22
20
  Tap::App.configurations.each do |receiver, key, config|
23
21
  next if receiver == Tap::Root
24
22
 
25
- opts.on(*cmdline.configv(config)) do |value|
23
+ opts.on(*config.to_optparse_argv) do |value|
26
24
  app.send(config.writer, value)
27
25
  end
28
26
  end
@@ -31,7 +29,7 @@ OptionParser.new do |opts|
31
29
  opts.separator "options:"
32
30
 
33
31
  opts.on("-h", "--help", "Show this message") do
34
- opts.banner = cmdline.usage(__FILE__)
32
+ opts.banner = Tap::Support::Lazydoc.usage(__FILE__)
35
33
  Tap::App.lazydoc.resolve
36
34
  puts opts
37
35
  exit
@@ -45,7 +43,7 @@ OptionParser.new do |opts|
45
43
  end.parse!(ARGV)
46
44
 
47
45
  #
48
- # handle options for each specified task
46
+ # build and run the argv
49
47
  #
50
48
 
51
49
  queues = env.build(ARGV)
@@ -56,48 +54,6 @@ if queues.empty?
56
54
  exit
57
55
  end
58
56
 
59
- #
60
- # set signals
61
- #
62
-
63
- # info signal -- Note: some systems do
64
- # not support the INFO signal
65
- # (windows, fedora, at least)
66
- signals = Signal.list.keys
67
- if signals.include?("INFO")
68
- Signal.trap("INFO") do
69
- puts app.info
70
- end
71
- end
72
-
73
- # interuption signal
74
- if signals.include?("INT")
75
- Signal.trap("INT") do
76
- puts " interrupted!"
77
- # prompt for decision
78
- while true
79
- print "stop, terminate, exit, or resume? (s/t/e/r):"
80
- case gets.strip
81
- when /s(top)?/i
82
- app.stop
83
- break
84
- when /t(erminate)?/i
85
- app.terminate
86
- break
87
- when /e(xit)?/i
88
- exit
89
- when /r(esume)?/i
90
- break
91
- else
92
- puts "unexpected response..."
93
- end
94
- end
95
- end
96
- end
97
-
98
- #
99
- # enque tasks and run!
100
- #
101
-
57
+ env.set_signals
102
58
  env.run(queues)
103
59
 
data/cmd/server.rb CHANGED
@@ -37,4 +37,6 @@ end.parse!(ARGV)
37
37
  #
38
38
 
39
39
  env.extend Tap::Support::Gems::Rack
40
- Rack::Handler::WEBrick.run(env, options)
40
+ Rack::Handler::WEBrick.run(env, options) do |handler|
41
+ env.handler = handler
42
+ end
data/lib/tap/constants.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Tap
2
2
  MAJOR = 0
3
3
  MINOR = 10
4
- TINY = 4
4
+ TINY = 5
5
5
 
6
6
  VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
7
7
  WEBSITE="http://tap.rubyforge.org"
data/lib/tap/env.rb CHANGED
@@ -123,12 +123,11 @@ module Tap
123
123
  manifests[name] = manifest_class
124
124
  end
125
125
 
126
- # Returns the gemspecs for all installed gems with a DEFAULT_TASK_FILE
127
- # or DEFAULT_CONFIG_FILE. If latest==true, then only the specs for the
128
- # most current gems will be returned.
126
+ # Returns the gemspecs for all installed gems with a DEFAULT_CONFIG_FILE.
127
+ # If latest==true, then only the specs for the most current gems will be
128
+ # returned.
129
129
  def gemspecs(latest=true)
130
130
  Support::Gems.select_gems(latest) do |spec|
131
- File.exists?(File.join(spec.full_gem_path, DEFAULT_TASK_FILE)) ||
132
131
  File.exists?(File.join(spec.full_gem_path, DEFAULT_CONFIG_FILE))
133
132
  end
134
133
  end
@@ -175,16 +174,10 @@ module Tap
175
174
  @@instance = nil
176
175
  @@instances = {}
177
176
  @@manifests = {:envs => Manifest}
178
-
179
- # The global config file path
180
- GLOBAL_CONFIG_FILE = File.join(Support::Gems.user_home, ".tap.yml")
181
177
 
182
178
  # The default config file path
183
179
  DEFAULT_CONFIG_FILE = "tap.yml"
184
180
 
185
- # The default task file path
186
- DEFAULT_TASK_FILE = "tapfile.rb"
187
-
188
181
  # The Root directory structure for self.
189
182
  attr_reader :root
190
183
 
@@ -194,16 +187,17 @@ module Tap
194
187
  # A hash of the manifests for self.
195
188
  attr_reader :manifests
196
189
 
190
+ # Specify files to require when self is activated.
191
+ config :requires, [], &c.array_or_nil
192
+
197
193
  # Specify gems to load as nested Envs. Gems may be specified
198
194
  # by name and/or version, like 'gemname >= 1.2'; by default the
199
195
  # latest version of the gem is selected.
200
196
  #
201
197
  # Gems are immediately loaded (via gem) through this method.
202
- #--
203
- # Note that the gems are resolved to gemspecs using Env.gemspec,
204
- # so self.gems returns an array of gemspecs.
205
198
  config_attr :gems, [] do |input|
206
199
  check_configurable
200
+ specs_by_name = {}
207
201
  @gems = [*input].compact.collect do |gem_name|
208
202
  spec = Support::Gems.gemspec(gem_name)
209
203
 
@@ -212,8 +206,20 @@ module Tap
212
206
  else Env.instance_for(spec.full_gem_path)
213
207
  end
214
208
 
215
- spec
209
+ (specs_by_name[spec.name] ||= []) << spec
210
+ spec.name
216
211
  end.uniq
212
+
213
+ # this song and dance is to ensure that the latest spec for a
214
+ # given gem appears first in the manifest
215
+ specs_by_name.each_pair do |name, specs|
216
+ specs_by_name[name] = specs.uniq.sort_by {|spec| spec.version }.reverse
217
+ end
218
+
219
+ @gems.collect! do |name|
220
+ specs_by_name[name]
221
+ end.flatten!
222
+
217
223
  reset_envs
218
224
  end
219
225
 
@@ -235,16 +241,12 @@ module Tap
235
241
  # Designate paths for discovering generators.
236
242
  path_config :generator_paths, ["lib"]
237
243
 
238
- path_manifest(:tasks, :load_paths, "**/*.rb", [DEFAULT_TASK_FILE]) do |load_path, path|
244
+ path_manifest(:tasks, :load_paths, "**/*.rb") do |load_path, path|
239
245
  next unless File.file?(path) && document = Support::Lazydoc.scan_doc(path, 'manifest')
240
246
 
241
- document.const_names.collect do |const_name|
242
- if const_name.empty?
243
- key = env.root.relative_filepath(load_path, path).chomp('.rb')
244
- [key, Support::Constant.new(key.camelize, path)]
245
- else
246
- [const_name.underscore, Support::Constant.new(const_name, path)]
247
- end
247
+ document.default_const_name = env.root.relative_filepath(load_path, path).chomp('.rb').camelize
248
+ document.const_attrs.keys.collect do |const_name|
249
+ [const_name.underscore, Support::Constant.new(const_name, path)]
248
250
  end
249
251
  end
250
252
 
@@ -257,13 +259,9 @@ module Tap
257
259
  next unless File.file?(path) && "#{File.basename(dirname)}_generator.rb" == File.basename(path)
258
260
 
259
261
  next unless document = Support::Lazydoc.scan_doc(path, 'generator')
260
- document.const_names.collect do |const_name|
261
- if const_name.empty?
262
- key = env.root.relative_filepath(generator_path, dirname)
263
- [key, Support::Constant.new((key + '_generator').camelize, path)]
264
- else
265
- [const_name.underscore, Support::Constant.new(const_name, path)]
266
- end
262
+ document.default_const_name = "#{env.root.relative_filepath(generator_path, dirname)}_generator".camelize
263
+ document.const_attrs.keys.collect do |const_name|
264
+ [const_name.underscore.chomp('_generator'), Support::Constant.new(const_name, path)]
267
265
  end
268
266
  end
269
267
 
@@ -454,6 +452,12 @@ module Tap
454
452
  end
455
453
 
456
454
  $LOAD_PATH.uniq!
455
+
456
+ # perform requires
457
+ requires.each do |path|
458
+ require path
459
+ end
460
+
457
461
  true
458
462
  end
459
463
 
@@ -519,10 +523,8 @@ module Tap
519
523
  # mini-matches the input pattern. See Tap::Root.minimal_match?
520
524
  # for details on mini-matching.
521
525
  def find(name, pattern, value_only=true)
522
- manifest(name).each do |key, value|
523
- return(value_only ? value : [key, value]) if Root.minimal_match?(key, pattern)
524
- end
525
- nil
526
+ return nil unless entry = manifest(name)[pattern]
527
+ value_only ? entry[1] : entry
526
528
  end
527
529
 
528
530
  # Like find, but searches across all envs for the matching value.
@@ -582,12 +584,8 @@ module Tap
582
584
  lines.join("\n")
583
585
  end
584
586
 
585
- def inspect(brief=false)
586
- brief ? "#<#{self.class}:#{object_id} root='#{root.root}'>" : super()
587
- end
588
-
589
- def to_s
590
- inspect(true)
587
+ def inspect
588
+ "#<#{self.class}:#{object_id} root='#{root.root}'>"
591
589
  end
592
590
 
593
591
  protected
data/lib/tap/exe.rb CHANGED
@@ -8,16 +8,17 @@ 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(Tap::Env::GLOBAL_CONFIG_FILE), app.logger)
11
+ exe = super(app, load_config(GLOBAL_CONFIG_FILE), app.logger)
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)
15
- exe.gems = gemspecs(true)
15
+ exe.gems = gemspecs(false)
16
16
  end
17
-
17
+
18
+ # add the default tap instance
18
19
  tap = instance_for("#{File.dirname(__FILE__)}/../..")
19
- tap.manifest(:tasks).search_paths = tap.root.glob(:lib, "tap/tasks/*").collect do |path|
20
- [tap.root[:lib], path]
20
+ tap.manifest(:tasks).search_paths = tap.root.glob(:lib, "tap/tasks/*").collect do |task_path|
21
+ [tap.root[:lib], task_path]
21
22
  end
22
23
  exe.push(tap)
23
24
  exe
@@ -33,6 +34,10 @@ module Tap
33
34
  config :after, nil
34
35
  config :aliases, {}, &c.hash_or_nil
35
36
 
37
+ # The global config file path
38
+ GLOBAL_CONFIG_FILE = File.join(Gem.user_home, ".tap.yml")
39
+
40
+ # Alias for root (Exe should have a Tap::App as root)
36
41
  def app
37
42
  root
38
43
  end
@@ -69,36 +74,61 @@ module Tap
69
74
  end
70
75
 
71
76
  def build(argv=ARGV)
72
- parser = Parser.new(argv)
73
-
74
- # attempt lookup and instantiate the task class
75
- tasks = parser.tasks.collect do |args|
77
+ Parser.new(argv).build(app) do |args|
76
78
  task = args.shift
77
-
78
- const = search(:tasks, task) or raise ArgumentError, "unknown task: #{task}"
79
- task_class = const.constantize or raise ArgumentError, "unknown task: #{task}"
80
- task_class.instantiate(args, app)
81
- end
82
-
83
- # build the workflow
84
- parser.workflow.each_with_index do |(type, target_indicies), source_index|
85
- next if type == nil
79
+ const = search(:tasks, task)
80
+
81
+ task_class = case
82
+ when const then const.constantize
83
+ when block_given?
84
+ args.unshift(task)
85
+ yield(args)
86
+ else nil
87
+ end
86
88
 
87
- tasks[source_index].send(type, *target_indicies.collect {|i| tasks[i] })
89
+ task_class or raise ArgumentError, "unknown task: #{task}"
90
+ task_class.parse(args, app) do |help|
91
+ puts help
92
+ exit
93
+ end
88
94
  end
89
-
90
- # build queues
91
- queues = parser.rounds.collect do |round|
92
- round.each do |index|
93
- task, args = tasks[index]
94
- task.enq(*args)
95
+ end
96
+
97
+ def set_signals
98
+ # info signal -- Note: some systems do
99
+ # not support the INFO signal
100
+ # (windows, fedora, at least)
101
+ signals = Signal.list.keys
102
+ if signals.include?("INFO")
103
+ Signal.trap("INFO") do
104
+ puts app.info
95
105
  end
96
-
97
- app.queue.clear
98
106
  end
99
- queues.delete_if {|queue| queue.empty? }
100
107
 
101
- queues
108
+ # interuption signal
109
+ if signals.include?("INT")
110
+ Signal.trap("INT") do
111
+ puts " interrupted!"
112
+ # prompt for decision
113
+ while true
114
+ print "stop, terminate, exit, or resume? (s/t/e/r):"
115
+ case gets.strip
116
+ when /s(top)?/i
117
+ app.stop
118
+ break
119
+ when /t(erminate)?/i
120
+ app.terminate
121
+ break
122
+ when /e(xit)?/i
123
+ exit
124
+ when /r(esume)?/i
125
+ break
126
+ else
127
+ puts "unexpected response..."
128
+ end
129
+ end
130
+ end
131
+ end
102
132
  end
103
133
 
104
134
  def run(queues)