Class: Tap::Env
- 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
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
-
#logger ⇒ Object
Gets or sets the logger for self.
-
#root ⇒ Object
readonly
The Root directory structure for self.
Attributes included from Support::Configurable
Class Method Summary collapse
-
.gemspecs(latest = true) ⇒ Object
Returns the gemspecs for all installed gems with a DEFAULT_CONFIG_FILE.
-
.instance ⇒ Object
Returns the active instance of Env.
- .instance_for(path) ⇒ Object
-
.instances ⇒ Object
A hash of (path, Env instance) pairs, generated by Env#instantiate.
-
.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.
-
.manifest(name, &block) ⇒ Object
:yields: env (returns manifest).
- .pathify(path) ⇒ Object
Instance Method Summary collapse
-
#activate ⇒ Object
Activates self by unshifting load_paths for self to the load_path_targets.
-
#active? ⇒ Boolean
Return true if self has been activated.
-
#count ⇒ Object
Returns the total number of unique envs nested in self (including self).
-
#deactivate ⇒ Object
Deactivates self by clearing manifests and deleting load_paths for self from the load_path_targets.
-
#each ⇒ Object
Passes each nested env to the block in order, starting with self.
-
#env_path ⇒ Object
Returns the path for self in Env.instances.
-
#envs(flat = false) ⇒ Object
An array of nested Envs, by default comprised of the env_path + gem environments (in that order).
-
#envs=(envs) ⇒ Object
Sets envs removing duplicates and instances of self.
-
#initialize(config = {}, root = Tap::Root.new, logger = nil) ⇒ Env
constructor
A new instance of Env.
-
#inspect(template = nil) ⇒ Object
:yields: templater, attrs.
-
#log(action, msg = "", level = Logger::INFO) ⇒ Object
Logs the action and message at the input level (default INFO).
-
#push(env) ⇒ Object
Pushes env onto envs, removing duplicates.
-
#reconfigure(overrides = {}) ⇒ Object
Processes and resets the input configurations for both root and self.
-
#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.
-
#recursive_inspect(template = nil, *args) ⇒ Object
:yields: templater, attrs.
-
#reverse_each ⇒ Object
Passes each nested env to the block in reverse order, ending with self.
-
#search_path(dir, path) ⇒ Object
Searches each env for the first existing file or directory at env.root.filepath(dir, path).
- #summarize(name, template = ) ⇒ Object
-
#unshift(env) ⇒ Object
Unshifts env onto envs, removing duplicates.
Methods included from Support::Minimap
Methods included from Support::Configurable
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
#logger ⇒ Object
Gets or sets the logger for self
117 118 119 |
# File 'lib/tap/env.rb', line 117 def logger @logger end |
#root ⇒ Object (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 |
.instance ⇒ Object
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 |
.instances ⇒ Object
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.(path) end |
Instance Method Details
#activate ⇒ Object
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.
442 443 444 |
# File 'lib/tap/env.rb', line 442 def active? @active end |
#count ⇒ Object
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 |
#deactivate ⇒ Object
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 |
#each ⇒ Object
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_path ⇒ Object
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_each ⇒ Object
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 |