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) ordered = [] environments.each do |environment| environment.flatten_to_array(ordered) end ordered.inject(nil) do |parent, environment| environment.dup(parent: parent) end end
def self.system_environment(env = ENV, **options)
def self.system_environment(env = ENV, **options) self.new(nil, Hash[env.map{|key, value| [key.downcase.to_sym, value]}], **options) end
def == other
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 [](key)
def [](key) environment = lookup(key) environment ? environment.values[key] : nil end
def []=(key, value)
def []=(key, value) @values[key] = value end
def checksum(digester: Digest::SHA1.new)
def checksum(digester: Digest::SHA1.new) checksum_recursively(digester) return digester.hexdigest end
def checksum_recursively(digester)
def checksum_recursively(digester) sorted_keys.each do |key| digester.update(key.to_s) case value = @values[key] when Proc digester.update(value.source_location.join) else digester.update(value.to_s) end end @parent.checksum_recursively(digester) if @parent end
def construct!(proxy, *arguments, &block)
def construct!(proxy, *arguments, &block) constructor = Constructor.new(self, proxy) if block_given? constructor.instance_exec(*arguments, &block) end return self end
def defined
def defined @values.select{|name,value| Define === value} end
def dup(parent: @parent, values: @values, update: @update, name: @name)
def dup(parent: @parent, values: @values, update: @update, name: @name) self.class.new(parent, values.dup, name: name, &update) end
def eql?(other)
def eql?(other) self == other end
def evaluate(**options)
def evaluate(**options) self.class.new(nil, self.to_h, **options) end
def evaluator
def evaluator Evaluator.new(self) end
def export
def export System.convert_to_shell(self) end
def fetch(key, *default, &block)
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 flatten(**options)
def flatten(**options) hash = {} flatten_to_hash(hash) options[:name] ||= self.name return self.class.new(nil, hash, **options) 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)
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 freeze
def freeze return self if frozen? @parent.freeze @values.freeze @update.freeze super end
def hash
def hash @parent.hash ^ @values.hash ^ @update.hash ^ @name.hash end
def include?(key)
def include?(key) if @values.include?(key) true elsif @parent @parent.include?(key) end end
def initialize(parent = nil, values = nil, name: nil, &block)
def initialize(parent = nil, values = nil, name: nil, &block) @parent = parent @values = (values || {}).to_h @update = block @name = name end
def lookup(name)
def lookup(name) if @values.include? name self elsif @parent @parent.lookup(name) end end
def merge(**options, &block)
def merge(**options, &block) self.class.new(self, **options, &block) end
def size
def size @values.size + (@parent ? @parent.size : 0) end
def sorted_keys
def sorted_keys @values.keys.sort_by(&:to_s) end
def to_a
def to_a flat = [] flatten_to_array(flat) return flat end
def to_h
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 to_s
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 update!
def update! construct!(self, &@update) @update = nil return self end
def update_hash(hash)
def update_hash(hash) @values.each do |key, value| previous = hash[key] if Replace === value # Replace the parent value hash[key] = value elsif Default === value # Update the parent value if not defined. hash[key] = previous || value elsif Array === previous # Merge with the parent value hash[key] = previous + Array(value) elsif OpenStruct === value hash[key] = value.to_h else hash[key] = value end end return self end