tap 0.10.0 → 0.10.1

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
@@ -10,37 +10,14 @@
10
10
  # tap command --help # prints help for 'command'
11
11
  #
12
12
 
13
- tap_root_dir = File.dirname(__FILE__) + "/.."
14
- require "#{tap_root_dir}/lib/tap.rb"
13
+ require "#{File.dirname(__FILE__)}/../lib/tap.rb"
14
+ require 'tap/exe'
15
15
 
16
16
  # setup the environment
17
17
  begin
18
18
 
19
19
  $DEBUG = true if ARGV.delete('-d-')
20
- before = nil
21
- after = nil
22
- aliases = nil
23
-
24
- app = Tap::App.instance
25
- env = Tap::Env.instantiate(app, Tap::Env.load_config(Tap::Env::GLOBAL_CONFIG_FILE), app.logger) do |unhandled_configs|
26
- before = unhandled_configs.delete(:before)
27
- after = unhandled_configs.delete(:after)
28
-
29
- aliases = unhandled_configs.delete(:alias)
30
- Tap::Support::Validation.validate(aliases, [Hash]) if aliases
31
-
32
- unless unhandled_configs.empty?
33
- local.log(:warn, "ignoring non-env configs: #{unhandled_configs.keys.join(',')}", Logger::DEBUG)
34
- end
35
- end
36
-
37
- # add all gems if no gems are specified (Note this is VERY SLOW ~ 1/3 the overhead for tap)
38
- if !File.exists?(Tap::Env::DEFAULT_CONFIG_FILE)
39
- env.gems = Tap::Env.known_gems(true)
40
- end
41
-
42
- tap = Tap::Env.instance_for(tap_root_dir)
43
- env.push(tap)
20
+ env = Tap::Exe.instantiate
44
21
 
45
22
  rescue(Tap::Env::ConfigError)
46
23
  # catch errors and exit gracefully
@@ -55,7 +32,7 @@ end
55
32
 
56
33
  at_exit do
57
34
  begin
58
- eval(after) if after != nil
35
+ eval(env.after) if env.after != nil
59
36
  rescue(Exception)
60
37
  puts "Error in after script."
61
38
  env.handle_error($!)
@@ -68,7 +45,7 @@ end
68
45
  #
69
46
 
70
47
  begin
71
- eval(before) if before != nil
48
+ eval(env.before) if env.before != nil
72
49
  rescue(Exception)
73
50
  puts "Error in before script."
74
51
  env.handle_error($!)
@@ -81,15 +58,7 @@ end
81
58
 
82
59
  begin
83
60
  env.activate
84
-
85
- command = ARGV.shift
86
- if aliases && aliases.has_key?(command)
87
- aliases[command].reverse_each {|arg| ARGV.unshift(arg)}
88
- command = ARGV.shift
89
- end
90
-
91
- case command
92
- when nil, '--help'
61
+ env.run do
93
62
  # give some help
94
63
  require 'tap/support/command_line'
95
64
 
@@ -98,14 +67,7 @@ begin
98
67
  puts "available commands:"
99
68
  puts env.summarize(:commands)
100
69
  puts
101
- puts "version #{Tap::VERSION} -- #{Tap::WEBSITE}"
102
- else
103
- if path = env.search(:commands, command)
104
- load path # run the command, if it exists
105
- else
106
- puts "Unknown command: '#{command}'"
107
- puts "Type 'tap help' for usage information."
108
- end
70
+ puts "version #{Tap::VERSION} -- #{Tap::WEBSITE}"
109
71
  end
110
72
  rescue
111
73
  env.handle_error($!)
data/cmd/manifest.rb ADDED
@@ -0,0 +1,94 @@
1
+ # tap manifest
2
+ #
3
+ # Prints information about each env.
4
+ #
5
+
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+
9
+ opts.separator ""
10
+ opts.separator "options:"
11
+
12
+ opts.on("-h", "--help", "Show this message") do
13
+ opts.banner = cmdline.usage(__FILE__)
14
+ puts opts
15
+ exit
16
+ end
17
+
18
+ opts.on("-e", "--envs_only", "Only list environments") do
19
+ options[:envs_only] = true
20
+ end
21
+
22
+ opts.on("-r", "--require FILEPATH", "Require the specified file") do |value|
23
+ require value
24
+ end
25
+
26
+ end.parse!(ARGV)
27
+
28
+ # Simply a method to collect and format paths for
29
+ # the specified manifest.
30
+ def collect_map(env, manifest)
31
+ width = 10
32
+ map = manifest.minimize.collect do |(key, path)|
33
+ path = case path
34
+ when Tap::Support::Constant then path.require_path
35
+ else path
36
+ end
37
+
38
+ width = key.length if width < key.length
39
+ [key, env.root.relative_filepath(:root, path) || path]
40
+ end.collect do |args|
41
+ "%-#{width}s (%s)" % args
42
+ end
43
+
44
+ map.unshift("") unless map.empty?
45
+ map
46
+ end
47
+
48
+ # Collect remaining args as
49
+ env = Tap::Env.instance
50
+ envs_manifest = if ARGV.empty?
51
+ env.manifest(:envs, true).minimize
52
+ else
53
+ ARGV.collect do |name|
54
+ entry = env.find(:envs, name, false)
55
+ raise "could not find an env matching: #{name}" if entry == nil
56
+ entry
57
+ end
58
+ end
59
+
60
+ width = 10
61
+ envs_manifest.each {|(env_name, e)| width = env_name.length if width < env_name.length}
62
+ width += 2
63
+
64
+ env.each do |current|
65
+ env_name, current = envs_manifest.find {|(env_name, e)| e == current }
66
+ next if env_name == nil
67
+
68
+ puts '-' * 80 unless options[:envs_only]
69
+ puts "%-#{width}s (%s)" % [env_name + ':', current.root.root]
70
+
71
+ next if options[:envs_only]
72
+
73
+ manifest_keys = (Tap::Env.manifests.keys + current.manifests.keys).uniq
74
+ manifest_keys.each do |name|
75
+ next if name == :envs
76
+ manifest = current.manifest(name, true)
77
+ next if manifest.empty?
78
+
79
+ puts " %-10s %s" % [name, collect_map(current, manifest).join("\n ")]
80
+ end
81
+ end
82
+
83
+ if ARGV.empty?
84
+ puts '-' * 80
85
+ puts
86
+ env.recursive_each(0, nil) do |current, nesting_depth, last_env|
87
+ env_name, current = envs_manifest.find {|(env_name, e)| e == current }
88
+
89
+ leader = nesting_depth == 0 ? "" : '| ' * (nesting_depth - 1) + (last_env == current ? "`- " : "|- ")
90
+ puts("#{leader}#{env_name}")
91
+ [nesting_depth + 1, current.envs[-1]]
92
+ end
93
+ puts
94
+ end
data/cmd/run.rb CHANGED
@@ -23,7 +23,7 @@ OptionParser.new do |opts|
23
23
  next if receiver == Tap::Root
24
24
 
25
25
  opts.on(*cmdline.configv(config)) do |value|
26
- app.send(configuration.writer, value)
26
+ app.send(config.writer, value)
27
27
  end
28
28
  end
29
29
 
data/lib/tap.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'rubygems'
2
-
3
1
  require 'yaml' # expensive to load
4
2
  require 'thread'
5
3
 
@@ -7,9 +5,6 @@ require 'thread'
7
5
  case RUBY_VERSION
8
6
  when /^1.9/
9
7
  $: << File.expand_path(File.dirname(__FILE__) + "/tap/patches/ruby19")
10
-
11
- # suppresses TDoc warnings
12
- $DEBUG_RDOC ||= nil
13
8
  end
14
9
 
15
10
  $:.unshift File.expand_path(File.dirname(__FILE__))
data/lib/tap/constants.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Tap
2
2
  MAJOR = 0
3
3
  MINOR = 10
4
- TINY = 0
4
+ TINY = 1
5
5
 
6
6
  VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
7
7
  WEBSITE="http://tap.rubyforge.org"
data/lib/tap/env.rb CHANGED
@@ -1,7 +1,7 @@
1
- require 'tap/root'
1
+ require 'tap/support/manifest'
2
2
  require 'tap/support/constant'
3
3
  require 'tap/support/summary'
4
- require 'tap/support/manifest'
4
+ require 'tap/support/gems'
5
5
 
6
6
  module Tap
7
7
 
@@ -12,16 +12,13 @@ module Tap
12
12
  include Support::Configurable
13
13
  include Enumerable
14
14
 
15
- @@instance = nil
16
- @@instances = {}
17
- @@manifests = {}
18
-
19
- class << self
15
+ class << self
16
+
20
17
  # Returns the active instance of Env.
21
18
  def instance
22
19
  @@instance
23
20
  end
24
-
21
+
25
22
  # A hash of (path, Env instance) pairs, generated by Env#instantiate. Used
26
23
  # to prevent infinite loops of Env dependencies by assigning a single Env
27
24
  # to a given path.
@@ -29,6 +26,13 @@ module Tap
29
26
  @@instances
30
27
  end
31
28
 
29
+ # A hash of predefined manifest classes that can be initialized
30
+ # from an env. These classes are instantiated by instances
31
+ # of Env, as needed.
32
+ def manifests
33
+ @@manifests
34
+ end
35
+
32
36
  # Creates a new Env for the specified path and adds it to Env#instances, or
33
37
  # returns the existing instance for the path. Paths can point to an env config
34
38
  # file, or to a directory. If a directory is provided, instantiate treats
@@ -45,7 +49,7 @@ module Tap
45
49
  # The Env is initialized using configurations read from the env config file using
46
50
  # load_config, and a Root initialized to the config file directory. An instance
47
51
  # will be initialized regardless of whether the config file or directory exists.
48
- def instantiate(path_or_root, default_config={}, logger=nil)
52
+ def instantiate(path_or_root, default_config={}, logger=nil, &block)
49
53
  path = path_or_root.kind_of?(Root) ? path_or_root.root : path_or_root
50
54
  path = pathify(path)
51
55
 
@@ -55,14 +59,17 @@ module Tap
55
59
 
56
60
  # note the assignment of env to instances MUST occur before
57
61
  # reconfigure to prevent infinite looping
58
- (instances[path] = Env.new({}, root, logger)).reconfigure(config) do |unhandled_configs|
59
- yield(unhandled_configs) if block_given?
60
- end
62
+ (instances[path] = new({}, root, logger)).reconfigure(config, &block)
61
63
  rescue(Exception)
62
64
  raise Env::ConfigError.new($!, path)
63
65
  end
64
66
  end
65
67
 
68
+ def instance_for(path)
69
+ path = pathify(path)
70
+ instances.has_key?(path) ? instances[path] : instantiate(path)
71
+ end
72
+
66
73
  def pathify(path)
67
74
  if File.directory?(path) || (!File.exists?(path) && File.extname(path) == "")
68
75
  path = File.join(path, DEFAULT_CONFIG_FILE)
@@ -70,41 +77,60 @@ module Tap
70
77
  File.expand_path(path)
71
78
  end
72
79
 
73
- def instance_for(path)
74
- path = pathify(path)
75
- instances.has_key?(path) ? instances[path] : instantiate(path)
76
- end
77
-
78
- # Returns the gemspec for the specified gem. A gem version
79
- # can be specified in the name, like 'gem >= 1.2'. The gem
80
- # will be activated using +gem+ if necessary.
81
- def gemspec(gem_name)
82
- return gem_name if gem_name.kind_of?(Gem::Specification)
83
-
84
- # figure the version of the gem, by default >= 0.0.0
85
- gem_name.to_s =~ /^([^<=>]*)(.*)$/
86
- name, version = $1.strip, $2
87
- version = ">= 0.0.0" if version.empty?
88
-
89
- return nil if name.empty?
90
-
91
- # load the gem and get the spec
92
- gem(name, version)
93
- Gem.loaded_specs[name]
94
- end
95
-
96
- # Returns the gem name for all installed gems with a DEFAULT_CONFIG_FILE.
97
- # If latest==true, then only the names for the most current gem specs
98
- # will be returned.
99
- def known_gems(latest=true)
100
- index = latest ?
101
- Gem.source_index.latest_specs :
102
- Gem.source_index.gems.collect {|(name, spec)| spec }
80
+ def manifest(name, pattern, default_paths=[], &block) # :yields: search_path
81
+ manifest_class = Class.new(Support::Manifest)
82
+ manifest_class.send(:define_method, :entries_for, &block) if block_given?
83
+ manifest_class.send(:attr_reader, :env)
84
+ manifest_class.send(:define_method, :initialize) do |env|
85
+ @env = env
86
+ search_paths = default_paths.collect {|path| env.root[path] }
87
+ search_paths += env.root.glob(:root, pattern)
88
+ super search_paths.sort_by {|p| File.basename(p) }
89
+ end
103
90
 
104
- index.select do |spec|
105
- File.exists?(File.join(spec.full_gem_path, DEFAULT_CONFIG_FILE)) ||
106
- File.exists?(File.join(spec.full_gem_path, DEFAULT_TASK_FILE))
107
- end.sort
91
+ manifests[name] = manifest_class
92
+ end
93
+
94
+ #--
95
+ # To manifest simply requires an glob_<name> method which
96
+ # yields each (key, path) pair for the manifested object in
97
+ # a predictable order.
98
+ #
99
+ #--
100
+ # Alternate implementation would create the manifest for each individual
101
+ # env, then merge the manifests. On the plus side, each env would then
102
+ # carry it's own slice of the manifest without having to recalculate.
103
+ # On the down side, the merging would have to occur in some separate
104
+ # method that cannot be defined here.
105
+ def path_manifest(name, paths_key, pattern, default_paths=[], &block) # :yields: search_path_root, search_path
106
+ manifest_class = Class.new(Support::Manifest)
107
+ manifest_class.send(:define_method, :entries_for, &block) if block_given?
108
+ manifest_class.send(:attr_reader, :env)
109
+ manifest_class.send(:define_method, :initialize) do |env|
110
+ @env = env
111
+ search_paths = default_paths.collect do |path|
112
+ [env.root.root, env.root[path]]
113
+ end
114
+
115
+ env.send(paths_key).each do |search_path_root|
116
+ env.root.glob(search_path_root, pattern).each do |search_path|
117
+ search_paths << [search_path_root, search_path]
118
+ end
119
+ end
120
+
121
+ super search_paths.sort_by {|pr, p| File.basename(p) }
122
+ end
123
+ manifests[name] = manifest_class
124
+ end
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.
129
+ def gemspecs(latest=true)
130
+ Support::Gems.select_gems(latest) do |spec|
131
+ File.exists?(File.join(spec.full_gem_path, DEFAULT_TASK_FILE)) ||
132
+ File.exists?(File.join(spec.full_gem_path, DEFAULT_CONFIG_FILE))
133
+ end
108
134
  end
109
135
 
110
136
  protected
@@ -137,46 +163,21 @@ module Tap
137
163
  instance_variable_set(instance_variable, [*input].compact.collect {|path| root[path]}.uniq)
138
164
  end
139
165
  end
140
-
141
- #--
142
- # To manifest simply requires an glob_<name> method which
143
- # yields each (key, path) pair for the manifested object in
144
- # a predictable order.
145
- #
146
- #--
147
- # Alternate implementation would create the manifest for each individual
148
- # env, then merge the manifests. On the plus side, each env would then
149
- # carry it's own slice of the manifest without having to recalculate.
150
- # On the down side, the merging would have to occur in some separate
151
- # method that cannot be defined here.
152
- def manifest(name, paths_key, pattern, &block)
153
- return manifest(name, paths_key, pattern) do |context, path|
154
- [[path.chomp(File.extname(path)), path]]
155
- end unless block_given?
156
-
157
- glob_method = Support::Manifest.glob_method(name)
158
- module_eval %Q{
159
- def #{glob_method}
160
- paths = []
161
- self.#{paths_key}.each do |manifest_path|
162
- root.glob(manifest_path, "#{pattern}").each do |path|
163
- next if File.directory?(path)
164
- paths << [manifest_path, path]
165
- end
166
- end
167
- paths.sort_by {|mp, p| File.basename(p)}
168
- end
169
- }
170
-
171
- map_method = Support::Manifest.map_method(name)
172
- define_method(map_method, &block)
173
-
174
- protected glob_method, map_method
166
+ end
167
+
168
+ class Manifest < Support::Manifest
169
+ def initialize(env)
170
+ super([])
171
+ @entries = env.collect {|e| [e.root.root, e] }
175
172
  end
176
173
  end
177
174
 
175
+ @@instance = nil
176
+ @@instances = {}
177
+ @@manifests = {:envs => Manifest}
178
+
178
179
  # The global config file path
179
- GLOBAL_CONFIG_FILE = File.join(Gem.user_home, ".tap.yml")
180
+ GLOBAL_CONFIG_FILE = File.join(Support::Gems.user_home, ".tap.yml")
180
181
 
181
182
  # The default config file path
182
183
  DEFAULT_CONFIG_FILE = "tap.yml"
@@ -204,7 +205,7 @@ module Tap
204
205
  config_attr :gems, [] do |input|
205
206
  check_configurable
206
207
  @gems = [*input].compact.collect do |gem_name|
207
- spec = Env.gemspec(gem_name)
208
+ spec = Support::Gems.gemspec(gem_name)
208
209
 
209
210
  case spec
210
211
  when nil then log(:warn, "unknown gem: #{gem_name}", Logger::WARN)
@@ -224,10 +225,8 @@ module Tap
224
225
  end.uniq
225
226
  reset_envs
226
227
  end
227
-
228
- # Designate load paths. If use_dependencies == true, then
229
- # load_paths will be used for automatic loading of modules
230
- # through the active_support Dependencies module.
228
+
229
+ # Designate load paths.
231
230
  path_config :load_paths, ["lib"]
232
231
 
233
232
  # Designate paths for discovering and executing commands.
@@ -236,12 +235,12 @@ module Tap
236
235
  # Designate paths for discovering generators.
237
236
  path_config :generator_paths, ["lib"]
238
237
 
239
- manifest(:tasks, :load_paths, "**/*.rb") do |load_path, path|
240
- next unless document = Support::Lazydoc.scan_doc(path, 'manifest')
238
+ path_manifest(:tasks, :load_paths, "**/*.rb", [DEFAULT_TASK_FILE]) do |load_path, path|
239
+ next unless File.file?(path) && document = Support::Lazydoc.scan_doc(path, 'manifest')
241
240
 
242
241
  document.const_names.collect do |const_name|
243
242
  if const_name.empty?
244
- key = root.relative_filepath(load_path, path).chomp('.rb')
243
+ key = env.root.relative_filepath(load_path, path).chomp('.rb')
245
244
  [key, Support::Constant.new(key.camelize, path)]
246
245
  else
247
246
  [const_name.underscore, Support::Constant.new(const_name, path)]
@@ -249,16 +248,18 @@ module Tap
249
248
  end
250
249
  end
251
250
 
252
- manifest(:commands, :command_paths, "**/*.rb")
251
+ path_manifest(:commands, :command_paths, "**/*.rb") do |command_path, path|
252
+ File.file?(path) ? [[path, path]] : nil
253
+ end
253
254
 
254
- manifest(:generators, :generator_paths, '**/*_generator.rb') do |load_path, path|
255
+ path_manifest(:generators, :generator_paths, '**/*_generator.rb') do |generator_path, path|
255
256
  dirname = File.dirname(path)
256
- next unless "#{File.basename(dirname)}_generator.rb" == File.basename(path)
257
+ next unless File.file?(path) && "#{File.basename(dirname)}_generator.rb" == File.basename(path)
257
258
 
258
259
  next unless document = Support::Lazydoc.scan_doc(path, 'generator')
259
260
  document.const_names.collect do |const_name|
260
261
  if const_name.empty?
261
- key = root.relative_filepath(load_path, dirname)
262
+ key = env.root.relative_filepath(generator_path, dirname)
262
263
  [key, Support::Constant.new((key + '_generator').camelize, path)]
263
264
  else
264
265
  [const_name.underscore, Support::Constant.new(const_name, path)]
@@ -304,7 +305,7 @@ module Tap
304
305
  unless env == self || envs[0] == env
305
306
  self.envs = envs.dup.unshift(env)
306
307
  end
307
- envs
308
+ self
308
309
  end
309
310
 
310
311
  # Pushes env onto envs, removing duplicates.
@@ -314,7 +315,7 @@ module Tap
314
315
  envs = self.envs.reject {|e| e == env }
315
316
  self.envs = envs.push(env)
316
317
  end
317
- envs
318
+ self
318
319
  end
319
320
 
320
321
  # Passes each nested env to the block in order, starting with self.
@@ -327,18 +328,40 @@ module Tap
327
328
  envs(true).reverse_each {|e| yield(e) }
328
329
  end
329
330
 
331
+ # Visits each nested env in order, starting with self, and passing
332
+ # to the block the env and any arguments generated by the parent of
333
+ # the env. The initial arguments are set when recursive_each is
334
+ # first called; subsequent arguements are the return values of the
335
+ # block.
336
+ #
337
+ # e0, e1, e2, e3, e4 = ('a'..'e').collect {|name| Tap::Env.new(:name => name) }
338
+ #
339
+ # e0.push(e1).push(e2)
340
+ # e1.push(e3).push(e4)
341
+ #
342
+ # lines = []
343
+ # e0.recursive_each(0) do |env, nesting_depth|
344
+ # lines << "\n#{'..' * nesting_depth}#{env.config[:name]} (#{nesting_depth})"
345
+ # nesting_depth + 1
346
+ # end
347
+ #
348
+ # lines.join
349
+ # # => %Q{
350
+ # # a (0)
351
+ # # ..b (1)
352
+ # # ....d (2)
353
+ # # ....e (2)
354
+ # # ..c (1)}
355
+ #
356
+ def recursive_each(*args, &block) # :yields: env, *parent_args
357
+ each_nested_env(self, [], args, &block)
358
+ end
359
+
330
360
  # Returns the total number of unique envs nested in self (including self).
331
361
  def count
332
362
  envs(true).length
333
363
  end
334
364
 
335
- # Returns a list of arrays that receive load_paths on activate,
336
- # by default [$LOAD_PATH]. If use_dependencies == true, then
337
- # Dependencies.load_paths will also be included.
338
- def load_path_targets
339
- [$LOAD_PATH]
340
- end
341
-
342
365
  # Processes and resets the input configurations for both root
343
366
  # and self. Reconfiguration consists of the following steps:
344
367
  #
@@ -412,7 +435,7 @@ module Tap
412
435
  return false if active?
413
436
 
414
437
  @active = true
415
- @@instance = self unless @@instance
438
+ @@instance = self if @@instance == nil
416
439
 
417
440
  # freeze array configs like load_paths
418
441
  config.each_pair do |key, value|
@@ -426,15 +449,12 @@ module Tap
426
449
  env.activate
427
450
  end
428
451
 
429
- # add load paths to load_path_targets
430
- load_path_targets.each do |target|
431
- load_paths.reverse_each do |path|
432
- target.unshift(path)
433
- end
434
-
435
- target.uniq!
452
+ # add load paths
453
+ load_paths.reverse_each do |path|
454
+ $LOAD_PATH.unshift(path)
436
455
  end
437
456
 
457
+ $LOAD_PATH.uniq!
438
458
  true
439
459
  end
440
460
 
@@ -446,13 +466,11 @@ module Tap
446
466
  def deactivate
447
467
  return false unless active?
448
468
 
449
- # remove load paths from load_path_targets
450
- load_path_targets.each do |target|
451
- load_paths.each do |path|
452
- target.delete(path)
453
- end
469
+ # remove load paths
470
+ load_paths.each do |path|
471
+ $LOAD_PATH.delete(path)
454
472
  end
455
-
473
+
456
474
  # unfreeze array configs by duplicating
457
475
  self.config.class_config.each_pair do |key, value|
458
476
  value = send(key)
@@ -478,57 +496,76 @@ module Tap
478
496
  @active
479
497
  end
480
498
 
481
- # Cycles through all items yielded by the iterate_<name> method and
482
- # adds each to the manifests[name] hash. Freezes the hash when complete.
483
- # Simply returns the manifests[name] hash if frozen.
484
- def manifest(name)
485
- manifest = manifests[name] ||= Support::Manifest.new(name, self)
486
-
487
- manifest.entries.each do |key, path|
488
- yield(key, path)
489
- end if block_given?
490
-
491
- manifest.each_path do |context, path|
492
- next unless keys = send(manifest.map_method, context, path)
493
-
494
- keys.each {|entry| manifest.store(entry) }
495
- keys.each {|key, value| yield(key, value) } if block_given?
496
- end unless manifest.complete?
497
-
499
+ # Returns the manifest in manifests by the specified name. Yields
500
+ # each entry in the manifest to the block, if given, or simply
501
+ # builds and returns the manifest.
502
+ #
503
+ # If the specified manifest does not exists, the manifest class
504
+ # in self.class.manifests will be instatiated with self to make
505
+ # the manifest. Raises an error if no manifest could be found
506
+ # or instantiated.
507
+ def manifest(name, build=false)
508
+ manifest = manifests[name] ||= case
509
+ when manifests_class = self.class.manifests[name]
510
+ manifests_class.new(self)
511
+ else
512
+ raise "unknown manifest: #{name}"
513
+ end
514
+
515
+ manifest.build if build
498
516
  manifest
499
517
  end
500
518
 
501
- def find(name, pattern)
502
- manifest(name) do |key, path|
503
- return path if Root.minimal_match?(key, pattern)
519
+ # Returns the first value in the specified manifest where the key
520
+ # mini-matches the input pattern. See Tap::Root.minimal_match?
521
+ # for details on mini-matching.
522
+ def find(name, pattern, value_only=true)
523
+ manifest(name).each do |key, value|
524
+ return(value_only ? value : [key, value]) if Root.minimal_match?(key, pattern)
504
525
  end
505
526
  nil
506
527
  end
507
528
 
508
- def search(name, pattern)
509
- return find(name, pattern) if name == :envs
529
+ # Like find, but searches across all envs for the matching value.
530
+ # An env pattern can be provided in pattern, to select a single
531
+ # env to search.
532
+ #
533
+ # The :envs manifest cannot be searched; use find instead.
534
+ def search(name, pattern, value_only=true)
535
+ if name == :envs
536
+ raise ArgumentError, "cannot search the :envs manifest; use find instead"
537
+ end
510
538
 
511
539
  envs = case pattern
512
540
  when /^(.*):([^:]+)$/
513
541
  env_pattern = $1
514
542
  pattern = $2
515
- find(:envs, env_pattern) or raise(ArgumentError, "could not find env: #{env_pattern}")
543
+ find(:envs, env_pattern)
516
544
  else manifest(:envs).values
517
545
  end
518
546
 
519
547
  envs.each do |env|
520
- if result = env.find(name, pattern)
548
+ if result = env.find(name, pattern, value_only)
521
549
  return result
522
550
  end
523
- end
551
+ end if envs
524
552
 
525
553
  nil
526
554
  end
527
555
 
556
+ def constantize(name, *patterns)
557
+ patterns.collect do |pattern|
558
+ case const = search(name, pattern)
559
+ when Support::Constant then const.constantize
560
+ else raise "could not constantize: #{pattern} (#{name})"
561
+ end
562
+ end
563
+ end
564
+
528
565
  def summary(name)
529
566
  summary = Support::Summary.new
530
- manifest(:envs).mini_map.each do |(key, env)|
531
- summary.add(key, env, env.manifest(name).mini_map)
567
+ manifest(:envs, true).minimize.each do |(key, env)|
568
+ summary.add(key, env, env.manifest(name, true).minimize)
532
569
  end
533
570
  summary
534
571
  end
@@ -546,51 +583,9 @@ module Tap
546
583
  def to_s
547
584
  inspect(true)
548
585
  end
549
-
550
- #--
551
- # Under construction
552
- #++
553
-
554
- def handle_error(err)
555
- case
556
- when $DEBUG
557
- puts err.message
558
- puts
559
- puts err.backtrace
560
- else puts err.message
561
- end
562
- end
563
586
 
564
587
  protected
565
588
 
566
- # Iterates over each nested env, yielding the root path and env.
567
- # This is the manifest method for envs.
568
- def manifest_glob_envs
569
- collect {|env| [env.root.root, env] }.sort_by {|root, env| File.basename(root) }
570
- end
571
-
572
- def manifest_map(context, path)
573
- [[context, path]]
574
- end
575
-
576
- alias default_manifest_glob_tasks manifest_glob_tasks
577
-
578
- def manifest_glob_tasks
579
- paths = default_manifest_glob_tasks
580
-
581
- # very odd behaviors --
582
- # * OS X is case-insensitive, apparently. Tapfile.rb and tapfile.rb are the same.
583
- # * require 'tapfile' does not work
584
- # * require 'tapfile.rb' works
585
- # * load 'tapfile' works
586
- #
587
- root.glob(:root, DEFAULT_TASK_FILE).each do |path|
588
- next if File.directory?(path)
589
- paths.unshift [root.root, path]
590
- end
591
- paths
592
- end
593
-
594
589
  # Raises an error if self is already active (and hence, configurations
595
590
  # should not be modified)
596
591
  def check_configurable
@@ -619,7 +614,20 @@ module Tap
619
614
 
620
615
  target
621
616
  end
622
-
617
+
618
+ private
619
+
620
+ def each_nested_env(env, visited, args, &block)
621
+ return if visited.include?(env)
622
+
623
+ visited << env
624
+ next_args = yield(env, *args)
625
+ next_args = [] if next_args == nil
626
+ env.envs.each do |nested_env|
627
+ each_nested_env(nested_env, visited, next_args, &block)
628
+ end
629
+ end
630
+
623
631
  # Raised when there is a Env-level configuration error.
624
632
  class ConfigError < StandardError
625
633
  attr_reader :original_error, :env_path