Class: Tap::Env

Inherits:
Object show all
Includes:
Enumerable, Support::Configurable, Support::Minimap
Defined in:
lib/tap/env.rb

Overview

– Note that gems and env_paths reset envs – custom modifications to envs will be lost whenever these configs are reset.

Direct Known Subclasses

Exe

Defined Under Namespace

Classes: ConfigError

Constant Summary collapse

DEFAULT_CONFIG_FILE =

The default config file path

"tap.yml"
TEMPLATES =
{}
@@instance =
nil
@@instances =
{}

Instance Attribute Summary collapse

Attributes included from Support::Configurable

#config

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Support::Minimap

#minimap, #minimatch

Methods included from Support::Configurable

included, #initialize_copy

Constructor Details

#initialize(config = {}, root = Tap::Root.new, logger = nil) ⇒ Env

Returns a new instance of Env.



207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/tap/env.rb', line 207

def initialize(config={}, root=Tap::Root.new, logger=nil)
  @root = root 
  @logger = logger
  @envs = []
  @active = false
  @manifests = {}

  # initialize these for reset_env

  @gems = []
  @env_paths = []
  
  initialize_config(config)
end

Instance Attribute Details

#loggerObject

Gets or sets the logger for self



117
118
119
# File 'lib/tap/env.rb', line 117

def logger
  @logger
end

#rootObject (readonly)

The Root directory structure for self.



114
115
116
# File 'lib/tap/env.rb', line 114

def root
  @root
end

Class Method Details

.gemspecs(latest = true) ⇒ Object

Returns the gemspecs for all installed gems with a DEFAULT_CONFIG_FILE. If latest==true, then only the specs for the most current gems will be returned.



82
83
84
85
86
# File 'lib/tap/env.rb', line 82

def gemspecs(latest=true)
  Support::Gems.select_gems(latest) do |spec|
    File.exists?(File.join(spec.full_gem_path, DEFAULT_CONFIG_FILE))
  end
end

.instanceObject

Returns the active instance of Env.



17
18
19
# File 'lib/tap/env.rb', line 17

def instance
  @@instance
end

.instance_for(path) ⇒ Object



60
61
62
63
# File 'lib/tap/env.rb', line 60

def instance_for(path)
  path = pathify(path)
  instances.has_key?(path) ? instances[path] : instantiate(path)
end

.instancesObject

A hash of (path, Env instance) pairs, generated by Env#instantiate. Used to prevent infinite loops of Env dependencies by assigning a single Env to a given path.



24
25
26
# File 'lib/tap/env.rb', line 24

def instances
  @@instances
end

.instantiate(path_or_root, default_config = {}, logger = nil, &block) ⇒ Object

Creates a new Env for the specified path and adds it to Env#instances, or returns the existing instance for the path. Paths can point to an env config file, or to a directory. If a directory is provided, instantiate treats path as the DEFAULT_CONFIG_FILE in that directory. All paths are expanded.

e1 = Env.instantiate("./path/to/config.yml")
e2 = Env.instantiate("./path/to/dir")

Env.instances       
# => {
#  File.expand_path("./path/to/config.yml") => e1, 
#  File.expand_path("./path/to/dir/#{Tap::Env::DEFAULT_CONFIG_FILE}") => e2 }

The Env is initialized using configurations read from the env config file using load_config, and a Root initialized to the config file directory. An instance will be initialized regardless of whether the config file or directory exists.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/tap/env.rb', line 44

def instantiate(path_or_root, default_config={}, logger=nil, &block)
  path = path_or_root.kind_of?(Root) ? path_or_root.root : path_or_root
  path = pathify(path)
  
  begin
    root = path_or_root.kind_of?(Root) ? path_or_root : Root.new(File.dirname(path))
    config = default_config.merge(load_config(path))
    
    # note the assignment of env to instances MUST occur before

    # reconfigure to prevent infinite looping

    (instances[path] = new({}, root, logger)).reconfigure(config, &block)
  rescue(Exception)
    raise Env::ConfigError.new($!, path)
  end
end

.manifest(name, &block) ⇒ Object

:yields: env (returns manifest)



72
73
74
75
76
77
# File 'lib/tap/env.rb', line 72

def manifest(name, &block) # :yields: env (returns manifest)

  name = name.to_sym
  define_method(name) do
    self.manifests[name] ||= block.call(self).bind(self, name)
  end
end

.pathify(path) ⇒ Object



65
66
67
68
69
70
# File 'lib/tap/env.rb', line 65

def pathify(path)
  if File.directory?(path) || (!File.exists?(path) && File.extname(path) == "")
    path = File.join(path, DEFAULT_CONFIG_FILE) 
  end
  File.expand_path(path)
end

Instance Method Details

#activateObject

Activates self by unshifting load_paths for self to the load_path_targets. Once active, self can be referenced from Env.instance and the current configurations are frozen. Env.instance is deactivated, if set, before self is activated. Returns true if activate succeeded, or false if self is already active.



370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/tap/env.rb', line 370

def activate
  return false if active?
  
  @active = true
  @@instance = self if @@instance == nil
  
  # freeze array configs like load_paths

  config.each_pair do |key, value|
    case value
    when Array then value.freeze
    end
  end
  
  # activate nested envs

  envs.reverse_each do |env|
    env.activate
  end

  # add load paths

  load_paths.reverse_each do |path|
    $LOAD_PATH.unshift(path)
  end

  $LOAD_PATH.uniq!
  
  # perform requires

  requires.each do |path|
    require path
  end
  
  # perform loads

  loads.each do |path|
    load path
  end
  
  true
end

#active?Boolean

Return true if self has been activated.

Returns:

  • (Boolean)


442
443
444
# File 'lib/tap/env.rb', line 442

def active?
  @active
end

#countObject

Returns the total number of unique envs nested in self (including self).



297
298
299
# File 'lib/tap/env.rb', line 297

def count
  envs(true).length
end

#deactivateObject

Deactivates self by clearing manifests and deleting load_paths for self from the load_path_targets. Env.instance will no longer reference self and the configurations are unfrozen (using duplication).

Returns true if deactivate succeeded, or false if self is not active.



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/tap/env.rb', line 413

def deactivate
  return false unless active?
  
  # remove load paths

  load_paths.each do |path|
    $LOAD_PATH.delete(path)
  end

  # unfreeze array configs by duplicating

  self.config.class_config.each_pair do |key, value|
    value = send(key)
    case value
    when Array then instance_variable_set("@#{key}", value.dup)
    end
  end
  
  @active = false
  @manifests.clear
  @@instance = nil if @@instance == self
  
  # dectivate nested envs

  envs.reverse_each do |env|
    env.deactivate
  end
  
  true
end

#eachObject

Passes each nested env to the block in order, starting with self.



258
259
260
# File 'lib/tap/env.rb', line 258

def each
  envs(true).each {|e| yield(e) }
end

#env_pathObject

Returns the path for self in Env.instances.



354
355
356
357
# File 'lib/tap/env.rb', line 354

def env_path
  Env.instances.each_pair {|path, env| return path if env == self }
  nil
end

#envs(flat = false) ⇒ Object

An array of nested Envs, by default comprised of the env_path + gem environments (in that order). These nested Envs are activated/deactivated with self.

Returns a flattened array of the unique nested envs when flat == true.



234
235
236
# File 'lib/tap/env.rb', line 234

def envs(flat=false)
  flat ? (@flat_envs ||= self.flatten_envs.freeze) : @envs
end

#envs=(envs) ⇒ Object

Sets envs removing duplicates and instances of self.



222
223
224
225
226
# File 'lib/tap/env.rb', line 222

def envs=(envs)
  @envs = envs.uniq.delete_if {|e| e == self }
  @envs.freeze
  @flat_envs = nil
end

#inspect(template = nil) ⇒ Object

:yields: templater, attrs



528
529
530
531
532
533
534
535
536
537
538
# File 'lib/tap/env.rb', line 528

def inspect(template=nil) # :yields: templater, attrs

  return "#<#{self.class}:#{object_id} root='#{root.root}'>" if template == nil
  
  attrs = {}
  collect do |env|
    templater = Support::Templater.new(template, :env => env)
    block_given? ? (yield(templater, attrs) ? templater : nil) : templater
  end.compact.collect do |templater|
    templater.build(attrs)
  end.join
end

#log(action, msg = "", level = Logger::INFO) ⇒ Object

Logs the action and message at the input level (default INFO). Logging is suppressed if no logger is set.



361
362
363
# File 'lib/tap/env.rb', line 361

def log(action, msg="", level=Logger::INFO)
  logger.add(level, msg, action.to_s) if logger
end

#push(env) ⇒ Object

Pushes env onto envs, removing duplicates.

Self cannot be pushed onto self.



249
250
251
252
253
254
255
# File 'lib/tap/env.rb', line 249

def push(env)
  unless env == self || envs[-1] == env
    envs = self.envs.reject {|e| e == env }
    self.envs = envs.push(env)
  end
  self
end

#reconfigure(overrides = {}) ⇒ Object

Processes and resets the input configurations for both root and self. Reconfiguration consists of the following steps:

  • partition overrides into env, root, and other configs

  • reconfigure root with the root configs

  • reconfigure self with the env configs

  • yield other configs to the block (if given)

Reconfigure will always yields to the block, even if there are no non-root, non-env configurations. Unspecified configurations are NOT reconfigured. (Note this means that existing path configurations like load_paths will not automatically be reset using reconfigured root.)



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/tap/env.rb', line 314

def reconfigure(overrides={})
  check_configurable
  
  # partiton config into its parts

  env_configs = {}
  root_configs = {}
  other_configs = {}
  
  env_configurations = self.class.configurations
  root_configurations = root.class.configurations
  overrides.each_pair do |key, value|
    key = key.to_sym

    partition = case 
    when env_configurations.key?(key) then env_configs
    when root_configurations.key?(key) then root_configs
    else other_configs
    end

    partition[key] = value
  end

  # reconfigure root so it can resolve path_configs

  root.reconfigure(root_configs)
  
  # reconfigure self

  super(env_configs)
  
  # handle other configs 

  case
  when block_given?
    yield(other_configs) 
  when !other_configs.empty?
    log(:warn, "ignoring non-env configs: #{other_configs.keys.join(',')}", Logger::DEBUG)
  end
  
  self
end

#recursive_each(*args, &block) ⇒ Object

Visits each nested env in order, starting with self, and passing to the block the env and any arguments generated by the parent of the env. The initial arguments are set when recursive_each is first called; subsequent arguements are the return values of the block.

e0, e1, e2, e3, e4 = ('a'..'e').collect {|name| Tap::Env.new(:name => name) }

e0.push(e1).push(e2)
e1.push(e3).push(e4)

lines = []
e0.recursive_each(0) do |env, nesting_depth|
  lines << "\n#{'..' * nesting_depth}#{env.config[:name]} (#{nesting_depth})"
  nesting_depth + 1
end

lines.join
# => %Q{
# a (0)
# ..b (1)
# ....d (2)
# ....e (2)
# ..c (1)}


292
293
294
# File 'lib/tap/env.rb', line 292

def recursive_each(*args, &block) # :yields: env, *parent_args

  each_nested_env(self, [], args, &block)
end

#recursive_inspect(template = nil, *args) ⇒ Object

:yields: templater, attrs



540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# File 'lib/tap/env.rb', line 540

def recursive_inspect(template=nil, *args) # :yields: templater, attrs

  return "#<#{self.class}:#{object_id} root='#{root.root}'>" if template == nil
  
  attrs = {}
  templaters = []
  recursive_each(*args) do |env, *argv|
    templater = Support::Templater.new(template, :env => env)
    next_args = block_given? ? yield(templater, attrs, *argv) : argv
    templaters << templater if next_args
    
    next_args
  end
  
  templaters.collect do |templater|
    templater.build(attrs)
  end.join
end

#reverse_eachObject

Passes each nested env to the block in reverse order, ending with self.



263
264
265
# File 'lib/tap/env.rb', line 263

def reverse_each
  envs(true).reverse_each {|e| yield(e) }
end

#search_path(dir, path) ⇒ Object

Searches each env for the first existing file or directory at env.root.filepath(dir, path). Paths are expanded, and search_path checks to make sure the file is, in fact, relative to env.root. An optional block may be used to check the file; the file will only be returned if the block returns true.

Returns nil if no file can be found.



453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/tap/env.rb', line 453

def search_path(dir, path)
  each do |env|
    directory = env.root.filepath(dir)
    file = env.root.filepath(dir, path)
    
    # check the file is relative to the

    # directory, and that the file exists.

    if file.rindex(directory, 0) == 0 && 
      File.exists?(file) && 
      (!block_given? || yield(file))
      return file
    end
  end
  
  nil
end

#summarize(name, template = ) ⇒ Object



500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# File 'lib/tap/env.rb', line 500

def summarize(name, template=TEMPLATES[name])
  count = 0
  width = 10
  
  env_names = {}
  minimap.each do |env_name, env|
    env_names[env] = env_name
  end
  
  inspect(template) do |templater, share|
    env = templater.env
    entries = env.send(name).minimap
    next(false) if entries.empty?
    
    templater.env_name = env_names[env]
    templater.entries = entries
    
    count += 1
    entries.each do |entry_name, entry|
      width = entry_name.length if width < entry_name.length
    end
    
    share[:count] = count
    share[:width] = width
    true
  end
end

#unshift(env) ⇒ Object

Unshifts env onto envs, removing duplicates.

Self cannot be unshifted onto self.



240
241
242
243
244
245
# File 'lib/tap/env.rb', line 240

def unshift(env)
  unless env == self || envs[0] == env
    self.envs = envs.dup.unshift(env)
  end
  self
end