Class: Tap::Env
- Inherits:
-
Object
- Object
- Tap::Env
- Includes:
- Configurable, Enumerable, Minimap
- Defined in:
- lib/tap/env.rb,
lib/tap/env/gems.rb,
lib/tap/env/minimap.rb,
lib/tap/env/constant.rb,
lib/tap/env/manifest.rb,
lib/tap/env/string_ext.rb
Overview
Env abstracts an execution environment that spans many directories.
Defined Under Namespace
Modules: Gems, Minimap, StringExt Classes: ConfigError, Constant, Manifest
Constant Summary collapse
- COMPOUND_KEY =
Matches a compound registry search key. After the match, if the key is compound then:
$1:: env_key $2:: key
If the key is not compound, $2 is nil and $1 is the key.
/^((?:[A-z]:(?:\/|\\))?.*?)(?::(.*))?$/
Class Attribute Summary collapse
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#envs ⇒ Object
An array of nested Envs, by default comprised of the env_path + gem environments (in that order).
-
#manifests ⇒ Object
readonly
Returns the value of attribute manifests.
Class Method Summary collapse
- .from_gemspec(spec, context = {}) ⇒ Object
-
.load_config(path) ⇒ Object
Loads configurations from path as YAML.
- .scan(load_path, pattern = '**/*.rb') ⇒ Object
Instance Method Summary collapse
- #[](type) ⇒ Object
-
#activate ⇒ Object
Activates self by doing the following, in order:.
-
#active? ⇒ Boolean
Return true if self has been activated.
-
#class_path(dir, obj, *paths, &block) ⇒ Object
Returns the module_path traversing the inheritance hierarchy for the class of obj (or obj if obj is a Class).
-
#deactivate ⇒ Object
Deactivates self by doing the following in order:.
-
#each ⇒ Object
Passes each nested env to the block in order, starting with self.
-
#eeek(type, key) ⇒ Object
– Environment-seek.
- #glob(dir, pattern = "**/*") ⇒ Object
- #hlob(dir, pattern = "**/*") ⇒ Object
-
#initialize(config_or_dir = Dir.pwd, context = {}) ⇒ Env
constructor
Initializes a new Env linked to the specified directory.
-
#inspect(template = nil, globals = {}, filename = nil) ⇒ Object
All templaters are yielded to the block before any are built.
-
#manifest(type) ⇒ Object
:yields: env.
-
#minikey ⇒ Object
The minikey for self (root.root).
-
#module_path(dir, modules, *paths, &block) ⇒ Object
Retrieves a path associated with the inheritance hierarchy of an object.
- #path(dir, *paths) ⇒ Object
-
#push(env) ⇒ Object
Pushes env onto envs, removing duplicates.
-
#recursive_inject(memo, &block) ⇒ Object
Recursively injects the memo to each env of self.
- #register(type, override = false, &block) ⇒ Object
- #registry(build = false) ⇒ Object
- #reset ⇒ Object
-
#reverse_each ⇒ Object
Passes each nested env to the block in reverse order, ending with self.
-
#seek(type, key, &block) ⇒ Object
Searches across each for the first registered object minimatching key.
-
#unshift(env) ⇒ Object
Unshifts env onto envs.
Methods included from Minimap
#minihash, #minimap, #minimatch
Constructor Details
#initialize(config_or_dir = Dir.pwd, context = {}) ⇒ Env
Initializes a new Env linked to the specified directory. A config file basename may be specified to load configurations from ‘dir/basename’ as YAML. If a basename is specified, the same basename will be used to load configurations for nested envs.
Configurations may be manually provided in the place of dir. In that case, the same rules apply for loading configurations for nested envs, but no configurations will be loaded for the current instance.
The cache is used internally to prevent infinite loops of nested envs, and to optimize the generation of manifests.
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/tap/env.rb', line 188 def initialize(config_or_dir=Dir.pwd, context={}) @active = false @manifests = {} @context = context # setup root config = nil @root = case config_or_dir when Root then config_or_dir when String then Root.new(config_or_dir) else config = config_or_dir if config.has_key?(:root) && config.has_key?('root') raise "multiple values mapped to :root" end root = config.delete(:root) || config.delete('root') || Dir.pwd root.kind_of?(Root) ? root : Root.new(root) end if basename && !config config = Env.load_config(File.join(@root.root, basename)) end if instance(@root.root) raise "context already has an env for: #{@root.root}" end instances << self # set these for reset_env @gems = nil @env_paths = nil initialize_config(config || {}) end |
Class Attribute Details
.instance(auto_initialize = true) ⇒ Object
14 15 16 |
# File 'lib/tap/env.rb', line 14 def instance(auto_initialize=true) @instance ||= (auto_initialize ? new : nil) end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
123 124 125 |
# File 'lib/tap/env.rb', line 123 def context @context end |
#envs ⇒ Object
An array of nested Envs, by default comprised of the env_path + gem environments (in that order).
121 122 123 |
# File 'lib/tap/env.rb', line 121 def envs @envs end |
#manifests ⇒ Object (readonly)
Returns the value of attribute manifests.
125 126 127 |
# File 'lib/tap/env.rb', line 125 def manifests @manifests end |
Class Method Details
.from_gemspec(spec, context = {}) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/tap/env.rb', line 18 def from_gemspec(spec, context={}) path = spec.full_gem_path basename = context[:basename] dependencies = [] spec.dependencies.each do |dependency| unless dependency.type == :runtime next end unless gemspec = Gems.gemspec(dependency) # this error may result when a dependency has # been uninstalled for a particular gem warn "missing gem dependency: #{dependency.to_s} (#{spec.full_name})" next end if basename && !File.exists?(File.join(gemspec.full_gem_path, basename)) next end dependencies << gemspec end config = { 'root' => path, 'gems' => dependencies, 'load_paths' => spec.require_paths, 'set_load_paths' => false } if context[:basename] config.merge!(Env.load_config(File.join(path, context[:basename]))) end new(config, context) end |
.load_config(path) ⇒ Object
Loads configurations from path as YAML. Returns an empty hash if the path loads to nil or false (as happens for empty files), or doesn’t exist.
58 59 60 61 62 63 64 65 66 |
# File 'lib/tap/env.rb', line 58 def load_config(path) return {} unless path begin Root::Utils.trivial?(path) ? {} : (YAML.load_file(path) || {}) rescue(Exception) raise ConfigError.new($!, path) end end |
.scan(load_path, pattern = '**/*.rb') ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/tap/env.rb', line 68 def scan(load_path, pattern='**/*.rb') Dir.chdir(load_path) do Dir.glob(pattern).each do |require_path| next unless File.file?(require_path) default_const_name = require_path.chomp('.rb').camelize # note: the default const name has to be set here to allow for implicit # constant attributes (because a dir is needed to figure the relative path). # A conflict could arise if the same path is globed from two different # dirs... no surefire solution. document = Lazydoc[require_path] case document.default_const_name when nil then document.default_const_name = default_const_name when default_const_name else raise "found a conflicting default const name" end # scan for constants Lazydoc::Document.scan(File.read(require_path)) do |const_name, type, comment| const_name = default_const_name if const_name.empty? constant = Constant.new(const_name, require_path, comment) yield(type, constant) ############################################################### # [depreciated] manifest as a task key will be removed at 1.0 if type == 'manifest' warn "depreciation: ::task should be used instead of ::manifest as a resource key (#{require_path})" yield('task', constant) end ############################################################### end end end end |
Instance Method Details
#[](type) ⇒ Object
482 483 484 |
# File 'lib/tap/env.rb', line 482 def [](type) manifest(type) end |
#activate ⇒ Object
Activates self by doing the following, in order:
-
sets Env.instance to self (unless already set)
-
activate nested environments
-
unshift load_paths to $LOAD_PATH (if set_load_paths is true)
Once active, the current envs and load_paths are frozen and cannot be modified until deactivated. Returns true if activate succeeded, or false if self is already active.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/tap/env.rb', line 301 def activate return false if active? @active = true unless self.class.instance(false) self.class.instance = self end # freeze envs and load paths @envs.freeze @load_paths.freeze # activate nested envs envs.reverse_each do |env| env.activate end # add load paths if set_load_paths load_paths.reverse_each do |path| $LOAD_PATH.unshift(path) end $LOAD_PATH.uniq! end true end |
#active? ⇒ Boolean
Return true if self has been activated.
367 368 369 |
# File 'lib/tap/env.rb', line 367 def active? @active end |
#class_path(dir, obj, *paths, &block) ⇒ Object
Returns the module_path traversing the inheritance hierarchy for the class of obj (or obj if obj is a Class). Included modules are not visited, only the superclasses.
428 429 430 431 432 |
# File 'lib/tap/env.rb', line 428 def class_path(dir, obj, *paths, &block) klass = obj.kind_of?(Class) ? obj : obj.class superclasses = klass.ancestors - klass.included_modules module_path(dir, superclasses, *paths, &block) end |
#deactivate ⇒ Object
Deactivates self by doing the following in order:
-
deactivates nested environments
-
removes load_paths from $LOAD_PATH (if set_load_paths is true)
-
sets Env.instance to nil (if set to self)
-
clears cached manifest data
Once deactivated, envs and load_paths are unfrozen and may be modified. Returns true if deactivate succeeded, or false if self is not active.
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/tap/env.rb', line 339 def deactivate return false unless active? @active = false # dectivate nested envs envs.reverse_each do |env| env.deactivate end # remove load paths load_paths.each do |path| $LOAD_PATH.delete(path) end if set_load_paths # unfreeze envs and load paths @envs = @envs.dup @load_paths = @load_paths.dup # clear cached data klass = self.class if klass.instance(false) == self klass.instance = nil end true end |
#each ⇒ Object
Passes each nested env to the block in order, starting with self.
255 256 257 |
# File 'lib/tap/env.rb', line 255 def each visit_envs.each {|e| yield(e) } end |
#eeek(type, key) ⇒ Object
– Environment-seek
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
# File 'lib/tap/env.rb', line 493 def eeek(type, key) key =~ COMPOUND_KEY envs = if $2 # compound key, match for env key = $2 [minimatch($1)].compact else # not a compound key, search all envs by iterating self self end # traverse envs looking for the first # manifest entry matching key envs.each do |env| if result = env.manifest(type).minimatch(key) return [env, result] end end nil end |
#glob(dir, pattern = "**/*") ⇒ Object
383 384 385 |
# File 'lib/tap/env.rb', line 383 def glob(dir, pattern="**/*") hlob(dir, pattern).values.sort! end |
#hlob(dir, pattern = "**/*") ⇒ Object
371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/tap/env.rb', line 371 def hlob(dir, pattern="**/*") results = {} each do |env| root = env.root root.glob(dir, pattern).each do |path| relative_path = root.relative_path(dir, path) results[relative_path] ||= path end end results end |
#inspect(template = nil, globals = {}, filename = nil) ⇒ Object
All templaters are yielded to the block before any are built. This allows globals to be determined for all environments.
526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
# File 'lib/tap/env.rb', line 526 def inspect(template=nil, globals={}, filename=nil) # :yields: templater, globals if template == nil return "#<#{self.class}:#{object_id} root='#{root.root}'>" end env_keys = minihash(true) collect do |env| templater = Support::Templater.new(template, :env => env, :env_key => env_keys[env]) yield(templater, globals) if block_given? templater end.collect! do |templater| templater.build(globals, filename) end.join end |
#manifest(type) ⇒ Object
:yields: env
471 472 473 474 475 476 477 478 479 480 |
# File 'lib/tap/env.rb', line 471 def manifest(type) # :yields: env type = type.to_sym registry[type] ||= begin builder = builders[type] builder ? builder.call(self) : [] end manifests[type] ||= Manifest.new(self, type) end |
#minikey ⇒ Object
The minikey for self (root.root).
225 226 227 |
# File 'lib/tap/env.rb', line 225 def minikey root.root end |
#module_path(dir, modules, *paths, &block) ⇒ Object
Retrieves a path associated with the inheritance hierarchy of an object. An array of modules (which naturally can include classes) are provided and module_path traverses each, forming paths like:
path(dir, module_path, *paths)
By default, ‘module_path’ is ‘module.to_s.underscore’, but modules can specify an alternative by providing a module_path method.
The paths are yielded to the block and when the block returns true, the path will be returned. If no block is given, the first module path is returned. Returns nil if the block never returns true.
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
# File 'lib/tap/env.rb', line 408 def module_path(dir, modules, *paths, &block) paths.compact! while current = modules.shift module_path = if current.respond_to?(:module_path) current.module_path else current.to_s.underscore end if path = self.path(dir, module_path, *paths, &block) return path end end nil end |
#path(dir, *paths) ⇒ Object
387 388 389 390 391 392 393 |
# File 'lib/tap/env.rb', line 387 def path(dir, *paths) each do |env| path = env.root.path(dir, *paths) return path if !block_given? || yield(path) end nil end |
#push(env) ⇒ Object
Pushes env onto envs, removing duplicates.
Self cannot be pushed onto self.
246 247 248 249 250 251 252 |
# File 'lib/tap/env.rb', line 246 def push(env) unless env == self || envs[-1] == env envs = self.envs.reject {|e| e == env } self.envs = envs.push(env) end self end |
#recursive_inject(memo, &block) ⇒ Object
Recursively injects the memo to each env of self. Each env in envs receives the same memo from the parent. This is different from the inject provided via Enumerable, where each subsequent env receives the memo from the previous, not the parent, env.
a,b,c,d,e = ('a'..'e').collect {|name| Env.new(:name => name) }
a.push(b).push(c)
b.push(d).push(e)
lines = []
a.recursive_inject(0) do |nesting_depth, env|
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)}
288 289 290 |
# File 'lib/tap/env.rb', line 288 def recursive_inject(memo, &block) # :yields: memo, env inject_envs(memo, &block) end |
#register(type, override = false, &block) ⇒ Object
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 |
# File 'lib/tap/env.rb', line 454 def register(type, override=false, &block) type = type.to_sym # error for existing, or overwrite case when override builders.delete(type) registries.each {|root, registry| registry.delete(type) } when builders.has_key?(type) raise "a builder is already registered for: #{type.inspect}" when registries.any? {|root, registry| registry.has_key?(type) } raise "entries are already registered for: #{type.inspect}" end builders[type] = block end |
#registry(build = false) ⇒ Object
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/tap/env.rb', line 434 def registry(build=false) builders.each_pair do |type, builder| registry[type] ||= builder.call(self) end if build registries[minikey] ||= begin registry = {} load_paths.each do |load_path| next unless File.directory?(load_path) Env.scan(load_path) do |type, constant| entries = registry[type.to_sym] ||= [] entries << constant end end registry end end |
#reset ⇒ Object
486 487 488 489 |
# File 'lib/tap/env.rb', line 486 def reset manifests.clear registries.clear end |
#reverse_each ⇒ Object
Passes each nested env to the block in reverse order, ending with self.
260 261 262 |
# File 'lib/tap/env.rb', line 260 def reverse_each visit_envs.reverse_each {|e| yield(e) } end |
#seek(type, key, &block) ⇒ Object
Searches across each for the first registered object minimatching key. A single env can be specified by using a compound key like ‘env_key:key’.
Returns nil if no matching object is found.
519 520 521 522 |
# File 'lib/tap/env.rb', line 519 def seek(type, key, &block) # :yields: env, key env, result = eeek(type, key, &block) result end |
#unshift(env) ⇒ Object
Unshifts env onto envs. Self cannot be unshifted onto self.
237 238 239 240 241 242 |
# File 'lib/tap/env.rb', line 237 def unshift(env) unless env == self || envs[0] == env self.envs = envs.dup.unshift(env) end self end |