class Environment
Represents a layered build environment, implemented as a linked list of hashes. It is primarily used for organising build configurations across a wide range of different sub-systems, e.g. platform configuration, target configuration, local project configuration, etc.
Nested
Definitions
def initialize(parent = nil, values = nil, name: nil, &block)
Initialize a new environment with an optional parent, initial values, name, and update block.
Signature
-
parameter
parentEnvironment | Nil The parent environment to inherit values from.
-
parameter
valuesHash | Nil The initial key-value pairs for this layer.
-
parameter
nameString | Nil An optional name for this environment.
-
parameter
blockProc An optional block applied when constructing the environment.
Implementation
def initialize(parent = nil, values = nil, name: nil, &block)
@parent = parent
@values = (values || {}).to_h
@update = block
@name = name
end
def ==(other)
Compare this environment with another for equality.
Signature
-
parameter
otherEnvironment The environment to compare against.
-
returns
Boolean trueif both environments have the same parent, values, update, and name.
Implementation
def == other
self.equal?(other) or
self.class == other.class and
@parent == other.parent and
@values == other.values and
@update == other.update and
@name == other.name
end
def eql?(other)
Check equality using the == operator.
Signature
-
parameter
otherEnvironment The environment to compare against.
-
returns
Boolean trueif the environments are equal.
Implementation
def eql?(other)
self == other
end
def hash
Compute a hash value for this environment based on its parent, values, update, and name.
Signature
-
returns
Integer The computed hash value.
Implementation
def hash
@parent.hash ^ @values.hash ^ @update.hash ^ @name.hash
end
def dup(parent: @parent, values: @values, update: @update, name: @name)
Create a duplicate of this environment, optionally overriding parent, values, update, or name.
Signature
-
parameter
parentEnvironment | Nil The parent for the duplicate.
-
parameter
valuesHash The values for the duplicate.
-
parameter
updateProc | Nil The update block for the duplicate.
-
parameter
nameString | Nil The name for the duplicate.
-
returns
Environment A new environment with the given attributes.
Implementation
def dup(parent: @parent, values: @values, update: @update, name: @name)
self.class.new(parent, values.dup, name: name, &update)
end
def freeze
Freeze this environment and its entire parent chain, making it immutable.
Signature
-
returns
Environment The frozen environment.
Implementation
def freeze
return self if frozen?
@parent.freeze
@values.freeze
@update.freeze
super
end
def lookup(name)
Find the environment layer that contains the given key.
Signature
-
parameter
nameSymbol The key to search for.
-
returns
Environment | Nil The environment layer containing the key, or
nilif not found.
Implementation
def lookup(name)
if @values.include? name
self
elsif @parent
@parent.lookup(name)
end
end
def include?(key)
Check whether the key exists in this environment or any parent layer.
Signature
-
parameter
keySymbol The key to check.
-
returns
Boolean | Nil trueif the key exists,nilotherwise.
Implementation
def include?(key)
if @values.include?(key)
true
elsif @parent
@parent.include?(key)
end
end
def size
Count the total number of key-value pairs across all layers.
Signature
-
returns
Integer The total size.
Implementation
def size
@values.size + (@parent ? @parent.size : 0)
end
def fetch(key, *default, &block)
Retrieve the value for a key, with support for a default value or block.
Signature
-
parameter
keySymbol The key to look up.
-
parameter
defaultArray An optional default value.
-
raises
KeyError If the key is not found and no default or block is given.
-
returns
Object The value associated with the key, or the default.
Implementation
def fetch(key, *default, &block)
if environment = lookup(key)
return environment.values[key]
elsif block_given?
yield(key, *default)
elsif !default.empty?
return default.first
else
raise KeyError.new("Environment missing #{key}")
end
end
def [](key)
Retrieve the value for a key, returning nil if not found.
Signature
-
parameter
keySymbol The key to look up.
-
returns
Object | Nil The value, or
nilif the key does not exist.
Implementation
def [](key)
environment = lookup(key)
environment ? environment.values[key] : nil
end
def []=(key, value)
Set the value for a key in the current environment layer.
Signature
-
parameter
keySymbol The key to set.
-
parameter
valueObject The value to assign.
Implementation
def []=(key, value)
@values[key] = value
end
def to_s
Return a human-readable string representation of this environment.
Signature
-
returns
String A string showing the class, name, update source location, and values.
Implementation
def to_s
buffer = String.new("\#<#{self.class} ")
if @name
buffer << @name.inspect << " "
end
if @update
buffer << @update.source_location.join(":") << " "
end
buffer << @values.to_s << ">"
return buffer
end
def construct!(proxy, *arguments, &block)
Apply a block to this environment using a class Build::Environment::Constructor proxy, then return the environment.
Signature
-
parameter
proxyObject | Nil An optional proxy object to delegate unknown method calls to.
-
parameter
argumentsArray Arguments forwarded to the block.
-
returns
Environment The updated environment.
Implementation
def construct!(proxy, *arguments, &block)
constructor = Constructor.new(self, proxy)
if block_given?
constructor.instance_exec(*arguments, &block)
end
return self
end
def self.combine(*environments)
Flatten the list of environments.
Implementation
def self.combine(*environments)
ordered = []
environments.each do |environment|
environment.flatten_to_array(ordered)
end
ordered.inject(nil) do |parent, environment|
environment.dup(parent: parent)
end
end
def merge(**options, &block)
Create a new child environment inheriting from this one, with optional keyword options and block.
Signature
-
parameter
optionsHash Options forwarded to the new environment's constructor.
-
parameter
blockProc An optional update block for the new environment.
-
returns
Environment A new environment with
selfas the parent.
Implementation
def merge(**options, &block)
self.class.new(self, **options, &block)
end
def to_a
Convert the hierarchy of environments to an array where the parent comes before the child.
Implementation
def to_a
flat = []
flatten_to_array(flat)
return flat
end
def flatten_to_array(array)
Recursively collect this environment and its ancestors into an array, parent first.
Signature
-
parameter
arrayArray The array to append environments into.
Implementation
def flatten_to_array(array)
if @parent
@parent.flatten_to_array(array)
end
array << self
end
def to_h
Evaluate all environment layers into a single flat hash with all values resolved.
Signature
-
returns
Hash A hash mapping all keys to their fully evaluated values.
Implementation
def to_h
hash = {}
# Flatten this chain of environments:
flatten_to_hash(hash)
# Evaluate all items to their respective object value:
evaluator = Evaluator.new(hash)
# Evaluate all the individual environment values so that they are flat:
Hash[hash.map{|key, value| [key, evaluator.object_value(value)]}]
end
def evaluator
Create a new class Build::Environment::Evaluator for this environment.
Signature
-
returns
Evaluator An evaluator backed by this environment.
Implementation
def evaluator
Evaluator.new(self)
end
def evaluate(**options)
Flatten and evaluate all values, returning a new single-layer environment.
Signature
-
parameter
optionsHash Options forwarded to the new environment's constructor.
-
returns
Environment A new environment with all values fully evaluated.
Implementation
def evaluate(**options)
self.class.new(nil, self.to_h, **options)
end
def flatten(**options)
Merge all environment layers into a single-level environment without evaluating values.
Signature
-
parameter
optionsHash Options forwarded to the new environment's constructor.
-
returns
Environment A flat environment containing the merged but unevaluated values.
Implementation
def flatten(**options)
hash = {}
flatten_to_hash(hash)
options[:name] ||= self.name
return self.class.new(nil, hash, **options)
end
def defined
Return all key-value pairs in the current layer whose values are Define instances.
Signature
-
returns
Hash A hash of keys mapped to their
Definevalues.
Implementation
def defined
@values.select{|name,value| Define === value}
end
def checksum(digester: Digest::SHA1.new)
Compute a hex digest checksum of the environment's content.
Signature
-
parameter
digesterDigest The digest algorithm to use.
-
returns
String The hexadecimal digest string.
Implementation
def checksum(digester: Digest::SHA1.new)
checksum_recursively(digester)
return digester.hexdigest
end
def update!
Apply the update function to this environment.
Implementation
def update!
construct!(self, &@update)
@update = nil
return self
end
def flatten_to_hash(hash)
We fold in the ancestors one at a time from oldest to youngest.
Implementation
def flatten_to_hash(hash)
if parent = @parent
parent = parent.flatten_to_hash(hash)
end
if @update
self.dup(parent: parent).update!.update_hash(hash)
else
self.update_hash(hash)
end
end
def self.system_environment(env = ENV, **options)
Construct an environment from a given system environment:
Implementation
def self.system_environment(env = ENV, **options)
self.new(nil, Hash[env.map{|key, value| [key.downcase.to_sym, value]}], **options)
end
def export
Make a hash appropriate for a process environment
Implementation
def export
System.convert_to_shell(self)
end