class Build::Environment

This is the basic environment data structure which is essentially 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.

def self.combine(*environments)

def self.combine(*environments)
	# Flatten the list of environments:
	environments = environments.collect do |environment|
		if Environment === environment
			environment.to_a
		else
			environment
		end
	end.flatten
	
	# Resequence based on order:
	first = Environment.new(nil, environments.shift)
	top = first
	
	environments.each do |tail|
		top = Environment.new(top, tail)
	end
	
	return top
end

def self.hash(**values)

def self.hash(**values)
	self.new(nil, values)
end

def self.system_environment(env = ENV)

Construct an environment from a given system environment:
def self.system_environment(env = ENV)
	self.new(Hash[env.map{|key, value| [key.downcase.to_sym, value]}])
end

def [] (key)

def [] (key)
	environment = lookup(key)
	
	environment ? environment.values[key] : nil
end

def []= (key, value)

def []= (key, value)
	@values[key] = value
end

def checksum

This should be stable within environments that produce the same results.
def checksum
	digester = Digest::MD5.new
	
	checksum_recursively(digester)
	
	return digester.hexdigest
end

def checksum_recursively(digester)

def checksum_recursively(digester)
	@values.each do |(key, value)|
		digester.update(key.to_s)
		digester.update(value.to_s)
	end
	
	@parent.checksum_recursively(digester) if @parent
end

def defined

def defined
	@values.select{|name,value| Define === value}
end

def export

Make a hash appropriate for a process environment
def export
	System::convert_to_shell(self)
end

def flatten

def flatten
	self.class.new(nil, self.to_hash)
end

def flatten_to_array(array)

def flatten_to_array(array)
	if @parent
		@parent.flatten_to_array(array)
	end
	
	array << self
end

def flatten_to_hash(hash)

We fold in the ancestors one at a time from oldest to youngest.
def flatten_to_hash(hash)
	if @parent
		@parent.flatten_to_hash(hash)
	end
	@values.each do |key, value|
		previous = hash[key]
		if Replace === value
			# Replace the parent value
			hash[key] = value
		elsif Array === previous
			# Merge with the parent value
			hash[key] = previous + Array(value)
		elsif Default === value
			# Update the parent value if not defined.
			hash[key] = previous || value
		else
			hash[key] = value
		end
	end
end

def include?(key)

def include?(key)
	lookup(key) != nil
end

def initialize(parent = nil, values = nil, &block)

def initialize(parent = nil, values = nil, &block)
	@values = (values || {}).to_h
	@parent = parent
	
	if block_given?
		Constructor.new(self).instance_exec(&block)
	end
end

def inspect(output = $stdout, indent = "")

def inspect(output = $stdout, indent = "")
	@values.each do |(key, value)|
		output.puts "#{indent}#{key}: #{value}"
	end
	
	@parent.inspect(output, indent + "\t") if @parent
end

def lookup(name)

def lookup(name)
	if @values.include? name
		self
	elsif @parent
		@parent.lookup(name)
	end
end

def merge(&block)

def merge(&block)
	self.class.combine(
		self,
		self.class.new(&block)
	)
end

def size

def size
	@values.size + (@parent ? @parent.size : 0)
end

def to_a

Convert the hierarchy of environments to an array where the parent comes before the child.
def to_a
	flat = []
	
	flatten_to_array(flat)
	
	return flat
end

def to_h

def to_h
	@values
end

def to_hash

def to_hash
	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 to_s

def to_s
	"<#{self.class} #{self.values}>"
end