class Falcon::Configuration::Loader

The domain specific language for loading configuration files.

def self.load_file(configuration, path)

@oaram path [String] The path to the configuration file, e.g. `falcon.rb`.
@parameter configuration [Configuration]
Load the specified file into the given configuration.
def self.load_file(configuration, path)
	path = File.realpath(path)
	root = File.dirname(path)
	
	loader = self.new(configuration, root)
	
	loader.instance_eval(File.read(path), path)
end

def environment(name, *parents, &block)

@yields {...} The block that will generate the environment.
@parameter parents [Array(Symbol)] The names of the parent environments to inherit.
@parameter name [String] The name of the environment.
Add the named environment, with zero or more parent environments, defined using the specified `block`.
def environment(name, *parents, &block)
	raise KeyError.new("#{name} is already set", key: name) if @environments.key?(name)
	@environments[name] = merge(name, *parents, &block)
end

def host(name, *parents, &block)

@parameter name [String] The name of the environment, usually a hostname.
Adds `root` and `authority` keys.
Define a host with the specified name.
def host(name, *parents, &block)
	environment = merge(name, :host, *parents, &block)
	
	environment[:root] = @root
	environment[:authority] = name
	
	@configuration.add(environment.flatten)
end

def initialize(configuration, root = nil)

@parameter root [String] The file-system root path for relative path computations.
@parameter configuration [Configuration]
Any environments generated by the loader will be added to the configuration.
Initialize the loader, attached to a specific configuration instance.
def initialize(configuration, root = nil)
	@loaded = {}
	@configuration = configuration
	@environments = {}
	@root = root
end

def load(*features)

@parameter features [Array(Symbol)] The features to load.

Falcon provides default environments for different purposes. These are included in the gem, in the `environments/` directory. This method loads the code in those files into the current configuration.

Load specific features into the current configuration.
def load(*features)
	features.each do |feature|
		next if @loaded.include?(feature)
		
		relative_path = File.join(__dir__, "environments", "#{feature}.rb")
		
		self.instance_eval(File.read(relative_path), relative_path)
		
		@loaded[feature] = relative_path
	end
end

def merge(name, *parents, &block)

@yields {...} The block that will generate the environment.
@parameter parents [Array(Build::Environment)]
@parameter name [String]
Build a new environment with the specified name and the given parents.
def merge(name, *parents, &block)
	environments = parents.map{|name| @environments.fetch(name)}
	
	parent = Build::Environment.combine(*environments)
	
	Build::Environment.new(parent, name: name, &block)
end

def proxy(name, *parents, &block)

@parameter name [String] The name of the environment, usually a hostname.
Adds `root` and `authority` keys.
Define a proxy with the specified name.
def proxy(name, *parents, &block)
	environment = merge(name, :proxy, *parents, &block)
	
	environment[:root] = @root
	environment[:authority] = name
	
	@configuration.add(environment.flatten)
end

def rack(name, *parents, &block)

@parameter name [String] The name of the environment, usually a hostname.
Adds `root` and `authority` keys.
Define a rack application with the specified name.
def rack(name, *parents, &block)
	environment = merge(name, :rack, *parents, &block)
	
	environment[:root] = @root
	environment[:authority] = name
	
	@configuration.add(environment.flatten)
end

def supervisor(&block)

Adds `root` key.
Define a supervisor instance
def supervisor(&block)
	name = File.join(@root, "supervisor")
	environment = merge(name, :supervisor, &block)
	
	environment[:root] = @root
	
	@configuration.add(environment.flatten)
end