require 'tap/support/assignments'
require 'tap/support/instance_configuration'
require 'tap/support/configuration'
module Tap
module Support
# ClassConfiguration tracks configurations defined by a Configurable class.
class ClassConfiguration
include Enumerable
config_templates_dir = File.expand_path File.dirname(__FILE__) + "/../generator/generators/config/templates"
# The path to the :doc template (see inspect)
DOC_TEMPLATE_PATH = File.join(config_templates_dir, 'doc.erb')
# The path to the :nodoc template (see inspect)
NODOC_TEMPLATE_PATH = File.join(config_templates_dir, 'nodoc.erb')
# The Configurable class receiving new configurations
attr_reader :receiver
# An Assignments tracking the assignment of config keys to receivers
attr_reader :assignments
# A map of [key, Configuration] pairs
attr_reader :map
# Generates a new ClassConfiguration for the receiver. If a parent is
# provided, configurations will be inherited from it.
def initialize(receiver, parent=nil)
@receiver = receiver
if parent != nil
@map = parent.map.inject({}) do |hash, (key, config)|
hash[key] = config.dup
hash
end
@assignments = Assignments.new(parent.assignments)
else
@map = {}
@assignments = Assignments.new
end
end
# Initializes a Configuration using the inputs and sets using name
# as a key. Any existing config by the same name is overridden.
# Returns the new config.
def add(name, default=nil, attributes={})
self[name] = Configuration.new(name.to_sym, default, attributes)
end
# Removes the specified configuration.
def remove(key)
self[key] = nil
end
# Gets the config specified by key. The key is symbolized.
def [](key)
map[key.to_sym]
end
# Assigns the config to key. A nil config unassigns the
# configuration key. The key is symbolized.
def []=(key, config)
key = key.to_sym
if config == nil
assignments.unassign(key)
map.delete(key)
else
assignments.assign(receiver, key) unless assignments.assigned?(key)
map[key] = config
end
end
# Returns true if key is a config key.
def key?(key)
map.has_key?(key)
end
# Returns all config keys.
def keys
map.keys
end
# Returns config keys in order.
def ordered_keys
assignments.values
end
# Returns all mapped configs.
def values
map.values
end
# True if map is empty.
def empty?
map.empty?
end
# Calls block once for each [receiver, key, config] in self,
# passing those elements as parameters in the order in
# which they were assigned.
def each
assignments.each do |receiver, key|
yield(receiver, key, map[key])
end
end
# Calls block once for each [key, config] pair in self,
# passing those elements as parameters in the order in
# which they were assigned.
def each_pair
assignments.each do |receiver, key|
yield(key, map[key])
end
end
# Initializes and returns a new InstanceConfiguration set to self
# and bound to the receiver, if specified.
def instance_config(receiver=nil, store={})
InstanceConfiguration.new(self, receiver, store)
end
# Returns a hash of the [key, config.default] pairs in self.
def to_hash
hash = {}
each_pair {|key, config| hash[key] = config.default }
hash
end
# An array of config descriptions that are Comment objects.
def code_comments
code_comments = []
values.each do |config|
code_comments << config.desc if config.desc.kind_of?(Lazydoc::Comment)
end
code_comments
end
# Inspects the configurations using the specified template. Templates
# are used for format each [receiver, configurations] pair in self.
# See DEFAULT_TEMPLATE as a model. The results of each template cycle
# are pushed to target.
#
# Two default templates are defined, :doc and :nodoc.
# These map to the contents of DOC_TEMPLATE_PATH and NODOC_TEMPLATE_PATH
# and correspond to the documented and undocumented
# Tap::Generator::Generators::ConfigGenerator templates.
def inspect(template=:doc, target="")
Lazydoc.resolve_comments(code_comments)
template = case template
when :doc then File.read(DOC_TEMPLATE_PATH)
when :nodoc then File.read(NODOC_TEMPLATE_PATH)
else template
end
templater = Templater.new(template)
assignments.each_pair do |receiver, keys|
next if keys.empty?
# set the template attributes
templater.receiver = receiver
templater.configurations = keys.collect do |key|
# duplicate config so that any changes to it
# during templation will not propogate back
# into self
[key, map[key].dup]
end.compact
yield(templater) if block_given?
target << templater.build
end
target
end
end
end
end