lib/configurations/arbitrary.rb
# coding: utf-8
module Configurations
# Configuration is a blank object in order to allow configuration of
# various properties including keywords
#
module Arbitrary
# Initialize a new configuration
# @param [Hash] options The options to initialize a configuration with
# @option options [Hash] methods a hash of method names pointing to procs
# @option options [Proc] not_configured a proc to evaluate for
# not_configured properties
# @param [Proc] block a block to configure this configuration with
# @yield [HostModule::Configuration] a configuration
# @return [HostModule::Configuration] a configuration
# @note An arbitrary configuration has to control its writeable state,
# therefore configuration is only possible in the initialization block
#
def initialize(options = {}, &block)
self.__writeable__ = true
super
self.__writeable__ = false if block
end
# Method missing gives access for reading and writing to the underlying
# configuration hash via dot notation
#
def method_missing(method, *args, &block)
if __respond_to_writer?(method)
__assign!(method.to_s[0..-2].to_sym, args.first)
elsif __respond_to_method_for_write?(method)
@data[method]
elsif __respond_to_method_for_read?(method, *args, &block)
@data.fetch(method) do
@not_configured_blocks.evaluate!(@path.add(method), method)
end
else
super
end
end
# Respond to missing according to the method_missing implementation
#
def respond_to_missing?(method, include_private = false)
__respond_to_writer?(method) ||
__respond_to_method_for_read?(method, *args, &block) ||
__respond_to_method_for_write?(method) ||
super
end
# A convenience accessor to instantiate a configuration from a hash
# @param [Hash] h the hash to read into the configuration
# @return [Configuration] the configuration with values assigned
# @note can only be accessed during writeable state (in configure block).
# Unassignable values are ignored
# @raise [ArgumentError] unless used in writeable state
# (in configure block)
#
def from_h(h)
unless @writeable
fail ::ArgumentError, 'can not dynamically assign values from a hash'
end
super
end
# Set the configuration to writeable or read only. Access to writer methods
# is only allowed within the configure block, this method is used to invoke
# writeability for subconfigurations.
# @param [Boolean] data true if the configuration should be writeable,
# false otherwise
#
def __writeable__=(data)
@writeable = data
return unless defined?(@data) && @data
@data.each do |_k, v|
v.__writeable__ = data if v.is_a?(__class__)
end
end
private
# @param [Symbol] property The property to test for
# @return [Boolean] whether the given property has been configured
#
def __configured?(_property)
true
end
# @param [Symbol] method the method to test for
# @return [Boolean] whether the given method is a writer
#
def __is_writer?(method)
method.to_s.end_with?('=')
end
# @param [Symbol] method the method to test for
# @return [Boolean] whether the configuration responds to the given
# property as a method during writeable state
#
def __respond_to_method_for_write?(method)
!__is_writer?(method) && @writeable && @data[method].is_a?(__class__)
end
# @param [Symbol] method the method to test for
# @return [Boolean] whether the configuration responds to the
# given property
#
def __respond_to_method_for_read?(method, *args, &block)
!__is_writer?(method) && args.empty? && block.nil?
end
# @param [Symbol] method the method to test for
# @return [Boolean] whether the method is a writer and is used in writeable
# state
#
def __respond_to_writer?(method)
@writeable && __is_writer?(method)
end
end
end