bahuvrihi-tap 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
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($!)
@@ -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__))
@@ -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"
@@ -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