lib/configurations/configuration.rb in configurations-1.4.0 vs lib/configurations/configuration.rb in configurations-2.0.0.pre
- old
+ new
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
module Configurations
# Configuration is a blank object in order to allow configuration of various properties including keywords
#
class Configuration < BasicObject
-
# 1.9 does not allow for method rebinding in another scope
#
if ::RUBY_VERSION < '2.0.0'
include ::Kernel
undef :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup,
@@ -31,29 +30,36 @@
install_kernel_method(:is_a?)
# Installs the inspect method from Kernel
#
install_kernel_method(:inspect)
+
end
# Initialize a new configuration
- # @param [Proc] configuration_defaults A proc yielding to a default configuration
- # @param [Hash] configurable a hash of configurable properties and their asserted types if given
+ # @param [Hash] options The options to initialize a configuration with
+ # @option options [Hash] configurable a hash of configurable properties and their asserted types if given
+ # @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
#
- def initialize(configuration_defaults, configurable, &block)
- @_writeable = true
- @configurable = configurable
+ def initialize(options={}, &block)
+ @_configurable = options[:configurable]
+ @_methods = options[:methods]
+ @_not_configured = options[:not_configured]
+
+ @_writeable = true
@configuration = _configuration_hash
_evaluate_configurable!
- self.instance_eval(&configuration_defaults) if configuration_defaults
+ instance_eval(&options[:defaults]) if options[:defaults]
if block
- self.instance_eval(&block)
+ instance_eval(&block)
self._writeable = false
end
end
# Method missing gives access for reading and writing to the underlying configuration hash via dot notation
@@ -62,23 +68,27 @@
property = method.to_s[0..-2].to_sym
value = args.first
if _respond_to_writer?(method)
_assign!(property, value)
- elsif _respond_to_property?(method)
+ elsif _respond_to_property_for_write?(method)
@configuration[method]
+ elsif _respond_to_property_for_read?(method)
+ @configuration.fetch(method, &_not_configured_callback)
+ elsif _has_configuration_method?(method)
+ _exec_configuration_method!(method, *args, &block)
elsif _can_delegate_to_kernel?(method)
::Kernel.send(method, *args, &block)
else
super
end
end
# Respond to missing according to the method_missing implementation
#
def respond_to?(method, include_private = false)
- _respond_to_writer?(method) or _respond_to_property?(method) or _can_delegate_to_kernel?(method) or super
+ _respond_to_writer?(method) or _respond_to_property_for_write?(method) or _respond_to_property_for_read?(method) or _can_delegate_to_kernel?(method) or !!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 writability for subconfigurations.
# @param [Boolean] data true if the configuration should be writeable, false otherwise
@@ -120,56 +130,75 @@
# @param [Symbol] property The property to test for configurability
# @return [Boolean] whether the given property is configurable
#
def _configurable?(property)
- _arbitrarily_configurable? or @configurable.has_key?(property)
+ _arbitrarily_configurable? or @_configurable.has_key?(property)
end
# @return [Boolean] whether this configuration is arbitrarily configurable
#
def _arbitrarily_configurable?
- @configurable.nil? or @configurable.empty?
+ @_configurable.nil? or @_configurable.empty?
end
# @return [Hash] the configurations configurable hash
def _configurable
- @configurable
+ @_configurable
end
private
# @param [Symbol] property The property to test for
# @return [Boolean] whether the given property has been configured
#
def _configured?(property)
- @configuration.has_key?(property)
+ @configuration.has_key?(property) or _not_configured_callback? or _arbitrarily_configurable?
end
# @return [Hash] A configuration hash instantiating subhashes if the key is configurable
#
def _configuration_hash
::Hash.new do |h, k|
- h[k] = Configuration.new(nil, @configurable) if _configurable?(k)
+ h[k] = Configuration.new(configurable: @_configurable, not_configured: @_not_configured) if _configurable?(k)
end
end
+ # @return [Proc] The not_configured callback
+ #
+ def _not_configured_callback
+ @_not_configured || ::Proc.new { |key| nil }
+ end
+
+ # @return [Boolean] whether the not configured callback has been configured
+ #
+ def _not_configured_callback?
+ !!@_not_configured
+ end
+
# Evaluates configurable properties and passes eventual hashes down to subconfigurations
#
def _evaluate_configurable!
return if _arbitrarily_configurable?
- @configurable.each do |k, assertion|
+ @_configurable.each do |k, assertion|
if k.is_a?(::Hash)
k.each do |property, nested|
- @configuration[property] = Configuration.new(nil, _configurable_hash(property, nested, assertion))
+ @configuration[property] = Configuration.new(configurable: _configurable_hash(property, nested, assertion), not_configured: _not_configured_callback)
end
end
end
end
+ # Executes a configuration method
+ #
+ def _exec_configuration_method!(method, *args, &block)
+ args << block #rbx complains if block is separate in the arguments list
+ instance_exec(*args, &@_methods[method])
+ end
+
# @param [Symbol, Hash, Array] property configurable properties, either single or nested
# @param [Symbol, Hash, Array] value configurable properties, either single or nested
# @param [Hash] assertion assertion if any
# @return a hash with configurable values pointing to their types
#
@@ -198,31 +227,31 @@
# @raise [ConfigurationError] if the given value has the wrong type
#
def _assert_type!(property, value)
return unless _evaluable?(property, :type)
- assertion = @configurable[property][:type]
+ assertion = @_configurable[property][:type]
::Kernel.raise ConfigurationError, "Expected #{property} to be configured with #{assertion}, but got #{value.class.inspect}", caller unless value.is_a?(assertion)
end
# Block assertion for configurable properties
# @param [Symbol] property the property to type test
# @param [Any] value the given value
#
def _evaluate_block!(property, value)
return value unless _evaluable?(property, :block)
- evaluation = @configurable[property][:block]
+ evaluation = @_configurable[property][:block]
evaluation.call(value)
end
# @param [Symbol] property The property to test for
# @param [Symbol] assertion_type The evaluation type type to test for
# @return [Boolean] whether the given property is assertable
#
def _evaluable?(property, evaluation)
- @configurable and @configurable.has_key?(property) and @configurable[property].is_a?(::Hash) and @configurable[property].has_key?(evaluation)
+ @_configurable and @_configurable.has_key?(property) and @_configurable[property].is_a?(::Hash) and @_configurable[property].has_key?(evaluation)
end
# @param [Symbol] property The property to test for
# @return [Boolean] whether this property is nested
#
@@ -235,21 +264,35 @@
#
def _is_writer?(method)
method.to_s.end_with?('=')
end
+ # @param [Symbol] method the method to test for existence
+ # @return [Boolean] whether the method exists as a configuration method
+ #
+ def _has_configuration_method?(method)
+ @_methods and @_methods.has_key?(method)
+ end
+
# @param [Symbol] method the method to test for
# @return [Boolean] whether the configuration responds to the given method writer
#
def _respond_to_writer?(method)
_is_writer?(method) and @_writeable and _configurable?(_property_from_writer(method))
end
# @param [Symbol] method the method to test for
- # @return [Boolean] whether the configuration responds to the given property as a method
+ # @return [Boolean] whether the configuration responds to the given property as a method during readable state
#
- def _respond_to_property?(method)
- not _is_writer?(method) and (@_writeable or _configured?(method))
+ def _respond_to_property_for_read?(method)
+ not _is_writer?(method) and _configured?(method)
+ 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_property_for_write?(method)
+ not _is_writer?(method) and @_writeable
end
# @param [Symbol] method the method to test for
# @return [Boolean] whether the configuration can delegate the given method to Kernel
#