diff --git a/lib/configurable/class_methods.rb b/lib/configurable/class_methods.rb index d7952ce..079ee18 100644 --- a/lib/configurable/class_methods.rb +++ b/lib/configurable/class_methods.rb @@ -6,19 +6,19 @@ module Configurable # Hash of default config types (bool, integer, float, string). DEFAULT_CONFIG_TYPES = { - :bool => ConfigTypes::BooleanType, - :integer => ConfigTypes::IntegerType, - :float => ConfigTypes::FloatType, - :string => ConfigTypes::StringType, - :nest => ConfigTypes::NestType, - :obj => ConfigTypes::ObjectType + :bool => ConfigClasses::BooleanConfig, + :integer => ConfigClasses::IntegerConfig, + :float => ConfigClasses::FloatConfig, + :string => ConfigClasses::StringConfig, + :nest => ConfigClasses::Nest, + :obj => ConfigClasses::Config } # ClassMethods extends classes that include Configurable and provides methods # for declaring configurations. module ClassMethods include ConfigClasses - include ConfigTypes + include ConfigClasses # A hash of (key, Config) pairs tracking configs defined on self. See the # configs method for all configs declared across all ancestors. @@ -149,12 +149,16 @@ def config(key, default=nil, attrs={}, &block) nest_class = guess_nest_class(default, block) attrs[:default] = nest_class ? nest_class.new : default - attrs[:type] = guess_config_type(attrs).new(attrs) attrs[:desc] = guess_config_desc(attrs, Lazydoc.register_caller) - - config_class = attrs[:class] || guess_config_class(attrs) + attrs[:list] = default.kind_of?(Array) unless attrs.has_key?(:list) + + config_class = guess_config_type(attrs) config = define_config(key, attrs, config_class) - + + if attrs[:list] + config.extend List + end + if nest_class const_name = attrs[:const_name] || guess_nest_const_name(config) unless const_defined?(const_name) @@ -232,7 +236,7 @@ def define_config_type(name, config_type) end def config_type(name, *matchers, &caster) - config_type = StringType.subclass(*matchers).cast(&caster) + config_type = StringConfig.subclass(*matchers).cast(&caster) const_name = guess_config_type_const_name(name) unless const_defined?(const_name) @@ -257,7 +261,7 @@ def remove_config_type(name) # # ==== Implementation Note # - # ConfigTypes are undefined by setting the key to nil in the registry. + # ConfigClasses are undefined by setting the key to nil in the registry. # Deleting the config_type is not sufficient because the registry needs to # convey to self and subclasses to not inherit the config_type from # ancestors. @@ -354,7 +358,7 @@ def guess_config_type_by_value(value) # :nodoc: end end - ObjectType + Config end def guess_config_type(attrs) # :nodoc: @@ -367,17 +371,6 @@ def guess_config_type(attrs) # :nodoc: end end - def guess_config_class(attrs) # :nodoc: - case attrs[:default] - when Array - List - when Configurable - Nest - else - Config - end - end - def guess_config_desc(base_attrs, comment) # :nodoc: Hash.new do |hash, key| comment.resolve diff --git a/lib/configurable/config_classes.rb b/lib/configurable/config_classes.rb index e845f33..c107152 100644 --- a/lib/configurable/config_classes.rb +++ b/lib/configurable/config_classes.rb @@ -1,3 +1,7 @@ require 'configurable/config_classes/config' require 'configurable/config_classes/list' require 'configurable/config_classes/nest' +require 'configurable/config_classes/string_config' +require 'configurable/config_classes/boolean_config' +require 'configurable/config_classes/integer_config' +require 'configurable/config_classes/float_config' diff --git a/lib/configurable/config_types/boolean_type.rb b/lib/configurable/config_classes/boolean_config.rb similarity index 88% rename from lib/configurable/config_types/boolean_type.rb rename to lib/configurable/config_classes/boolean_config.rb index 81e0086..f1a8456 100644 --- a/lib/configurable/config_types/boolean_type.rb +++ b/lib/configurable/config_classes/boolean_config.rb @@ -1,6 +1,6 @@ module Configurable - module ConfigTypes - class BooleanType < StringType + module ConfigClasses + class BooleanConfig < StringConfig matches TrueClass, FalseClass # Casts the input to a boolean ie: diff --git a/lib/configurable/config_classes/config.rb b/lib/configurable/config_classes/config.rb index 52dae5c..1d726b3 100644 --- a/lib/configurable/config_classes/config.rb +++ b/lib/configurable/config_classes/config.rb @@ -1,11 +1,49 @@ -require 'configurable/config_types' - module Configurable module ConfigClasses # ConfigClasses are used by ConfigHash to delegate get/set configs on a # receiver and to map configs between user interfaces. class Config - include ConfigTypes + class << self + attr_reader :matchers + + def inherited(base) # :nodoc: + unless base.instance_variable_defined?(:@matchers) + base.instance_variable_set(:@matchers, matchers.dup) + end + end + + def subclass(*matchers, &caster) + subclass = Class.new(self) + subclass.matches(*matchers) + subclass.cast(&caster) + subclass + end + + def cast(&block) + define_method(:cast, &block) if block + self + end + + def uncast(&block) + define_method(:uncast, &block) if block + self + end + + def errors(&block) + define_method(:errors, &block) if block + self + end + + def matches(*matchers) + @matchers = matchers + self + end + + def matches?(value) + matchers.any? {|matcher| matcher === value } + end + end + matches() # The config key, used as a hash key for access. attr_reader :key @@ -23,9 +61,6 @@ class Config # The default config value. attr_reader :default - # The config type for self (defaults to an ObjectType) - attr_reader :type - # A hash of information used to render self in various contexts. attr_reader :desc @@ -37,7 +72,6 @@ def initialize(key, attrs={}) check_name(@name) @default = attrs[:default] - @type = attrs[:type] || ObjectType.new check_default(@default) @reader = (attrs[:reader] || name).to_sym @@ -58,13 +92,13 @@ def get(receiver) def set(receiver, value) receiver.send(writer, value) end - + def cast(input) - type.cast(input) + input end def uncast(value) - type.uncast(value) + value end # Returns an inspect string. diff --git a/lib/configurable/config_types/float_type.rb b/lib/configurable/config_classes/float_config.rb similarity index 64% rename from lib/configurable/config_types/float_type.rb rename to lib/configurable/config_classes/float_config.rb index cc1ca0c..364346c 100644 --- a/lib/configurable/config_types/float_type.rb +++ b/lib/configurable/config_classes/float_config.rb @@ -1,6 +1,6 @@ module Configurable - module ConfigTypes - class FloatType < StringType + module ConfigClasses + class FloatConfig < StringConfig matches Float def cast(input) diff --git a/lib/configurable/config_types/integer_type.rb b/lib/configurable/config_classes/integer_config.rb similarity index 64% rename from lib/configurable/config_types/integer_type.rb rename to lib/configurable/config_classes/integer_config.rb index d4ceec4..b3eb11e 100644 --- a/lib/configurable/config_types/integer_type.rb +++ b/lib/configurable/config_classes/integer_config.rb @@ -1,6 +1,6 @@ module Configurable - module ConfigTypes - class IntegerType < StringType + module ConfigClasses + class IntegerConfig < StringConfig matches Integer def cast(input) diff --git a/lib/configurable/config_classes/list.rb b/lib/configurable/config_classes/list.rb index 33c454e..f2f03bb 100644 --- a/lib/configurable/config_classes/list.rb +++ b/lib/configurable/config_classes/list.rb @@ -1,16 +1,6 @@ module Configurable module ConfigClasses - - class List < Config - - def initialize(key, attrs={}) - unless attrs.has_key?(:default) - attrs[:default] = [] - end - - super - end - + module List def cast(values) results = [] values.each {|value| results << super(value) } diff --git a/lib/configurable/config_classes/nest.rb b/lib/configurable/config_classes/nest.rb index 90f2736..729f154 100644 --- a/lib/configurable/config_classes/nest.rb +++ b/lib/configurable/config_classes/nest.rb @@ -3,6 +3,7 @@ module ConfigClasses # Represents a config where the input is expected to be Configurable. class Nest < Config + matches Configurable def configurable @default @@ -38,6 +39,14 @@ def set(receiver, value) end end + def cast(input) + configurable.class.configs.import(input) + end + + def uncast(value) + configurable.class.configs.export(value) + end + protected def check_default(default) # :nodoc: diff --git a/lib/configurable/config_types/string_type.rb b/lib/configurable/config_classes/string_config.rb similarity index 75% rename from lib/configurable/config_types/string_type.rb rename to lib/configurable/config_classes/string_config.rb index 2e983a5..8fba940 100644 --- a/lib/configurable/config_types/string_type.rb +++ b/lib/configurable/config_classes/string_config.rb @@ -1,6 +1,6 @@ module Configurable - module ConfigTypes - class StringType < ObjectType + module ConfigClasses + class StringConfig < Config matches String def cast(input) diff --git a/lib/configurable/config_types.rb b/lib/configurable/config_types.rb deleted file mode 100644 index 159f28e..0000000 --- a/lib/configurable/config_types.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'configurable/config_types/object_type' -require 'configurable/config_types/string_type' -require 'configurable/config_types/boolean_type' -require 'configurable/config_types/integer_type' -require 'configurable/config_types/float_type' -require 'configurable/config_types/nest_type' diff --git a/lib/configurable/config_types/nest_type.rb b/lib/configurable/config_types/nest_type.rb deleted file mode 100644 index 931b711..0000000 --- a/lib/configurable/config_types/nest_type.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Configurable - module ConfigTypes - class NestType < ObjectType - matches Configurable - - attr_reader :configurable - - def initialize(attrs={}) - @configurable = attrs[:default] - - unless configurable.kind_of?(Configurable) - raise ArgumentError, "not a Configurable: #{configurable.inspect}" - end - - super - end - - def cast(input) - configurable.class.configs.import(input) - end - - def uncast(value) - configurable.class.configs.export(value) - end - end - end -end \ No newline at end of file diff --git a/lib/configurable/config_types/object_type.rb b/lib/configurable/config_types/object_type.rb deleted file mode 100644 index 9f592ee..0000000 --- a/lib/configurable/config_types/object_type.rb +++ /dev/null @@ -1,58 +0,0 @@ -module Configurable - module ConfigTypes - class ObjectType - class << self - attr_reader :matchers - - def inherited(base) # :nodoc: - unless base.instance_variable_defined?(:@matchers) - base.instance_variable_set(:@matchers, matchers.dup) - end - end - - def subclass(*matchers, &caster) - subclass = Class.new(self) - subclass.matches(*matchers) - subclass.cast(&caster) - subclass - end - - def cast(&block) - define_method(:cast, &block) if block - self - end - - def uncast(&block) - define_method(:uncast, &block) if block - self - end - - def errors(&block) - define_method(:errors, &block) if block - self - end - - def matches(*matchers) - @matchers = matchers - self - end - - def matches?(value) - matchers.any? {|matcher| matcher === value } - end - end - matches() - - def initialize(attrs={}) - end - - def cast(input) - input - end - - def uncast(value) - value - end - end - end -end \ No newline at end of file diff --git a/lib/configurable/conversions.rb b/lib/configurable/conversions.rb index 0c773aa..edf227a 100644 --- a/lib/configurable/conversions.rb +++ b/lib/configurable/conversions.rb @@ -27,7 +27,7 @@ def to_parser(*args, &block) :key => config.key, :nest_keys => nest_keys, :default => config.default, - :callback => lambda {|value| config.type.cast(value) } + :callback => lambda {|value| config.cast(value) } } attrs = guess_attrs.merge(config.desc).merge(config_attrs) diff --git a/test/configurable/config_types/boolean_type_test.rb b/test/configurable/config_classes/boolean_config_test.rb similarity index 79% rename from test/configurable/config_types/boolean_type_test.rb rename to test/configurable/config_classes/boolean_config_test.rb index 9f7d7d7..934c327 100644 --- a/test/configurable/config_types/boolean_type_test.rb +++ b/test/configurable/config_classes/boolean_config_test.rb @@ -1,13 +1,13 @@ require File.expand_path('../../../test_helper', __FILE__) -require 'configurable/config_types' +require 'configurable/config_classes' -class BooleanTypeTest < Test::Unit::TestCase - include Configurable::ConfigTypes +class BooleanConfigTest < Test::Unit::TestCase + include Configurable::ConfigClasses attr_reader :type def setup - @type = BooleanType.new + @type = BooleanConfig.new(:key) end # diff --git a/test/configurable/config_classes/config_test.rb b/test/configurable/config_classes/config_test.rb index 42537ef..9bb01e9 100644 --- a/test/configurable/config_classes/config_test.rb +++ b/test/configurable/config_classes/config_test.rb @@ -3,7 +3,7 @@ class ConfigTest < Test::Unit::TestCase include Configurable::ConfigClasses - include Configurable::ConfigTypes + include Configurable::ConfigClasses attr_reader :config @@ -85,22 +85,4 @@ def test_set_calls_writer_on_receiver_with_input config.set(receiver, 'value') assert_equal 'value', receiver.key end - - # - # cast test - # - - def test_cast_casts_input_using_type - config = Config.new(:key, :type => IntegerType.new) - assert_equal 1, config.cast('1') - end - - # - # uncast test - # - - def test_uncast_uncasts_value_using_type - config = Config.new(:key, :type => IntegerType.new) - assert_equal '1', config.uncast(1) - end end diff --git a/test/configurable/config_types/float_type_test.rb b/test/configurable/config_classes/float_config_test.rb similarity index 68% rename from test/configurable/config_types/float_type_test.rb rename to test/configurable/config_classes/float_config_test.rb index f8aa564..6e5a923 100644 --- a/test/configurable/config_types/float_type_test.rb +++ b/test/configurable/config_classes/float_config_test.rb @@ -1,13 +1,13 @@ require File.expand_path('../../../test_helper', __FILE__) -require 'configurable/config_types' +require 'configurable/config_classes' -class FloatTypeTest < Test::Unit::TestCase - include Configurable::ConfigTypes +class FloatConfigTest < Test::Unit::TestCase + include Configurable::ConfigClasses attr_reader :type def setup - @type = FloatType.new + @type = FloatConfig.new(:key) end # diff --git a/test/configurable/config_types/integer_type_test.rb b/test/configurable/config_classes/integer_config_test.rb similarity index 67% rename from test/configurable/config_types/integer_type_test.rb rename to test/configurable/config_classes/integer_config_test.rb index dc44cb8..4184718 100644 --- a/test/configurable/config_types/integer_type_test.rb +++ b/test/configurable/config_classes/integer_config_test.rb @@ -1,13 +1,13 @@ require File.expand_path('../../../test_helper', __FILE__) -require 'configurable/config_types' +require 'configurable/config_classes' -class IntegerTypeTest < Test::Unit::TestCase - include Configurable::ConfigTypes +class IntegerConfigTest < Test::Unit::TestCase + include Configurable::ConfigClasses attr_reader :type def setup - @type = IntegerType.new + @type = IntegerConfig.new(:key) end # diff --git a/test/configurable/config_classes/list_test.rb b/test/configurable/config_classes/list_test.rb index cd284d4..79b6e1c 100644 --- a/test/configurable/config_classes/list_test.rb +++ b/test/configurable/config_classes/list_test.rb @@ -3,12 +3,12 @@ class ListTest < Test::Unit::TestCase include Configurable::ConfigClasses - include Configurable::ConfigTypes + include Configurable::ConfigClasses attr_reader :list def setup - @list = List.new(:key) + @list = Config.new(:key).extend List end # @@ -16,7 +16,7 @@ def setup # def test_cast_casts_each_value_of_the_input - list = List.new(:key, :type => IntegerType.new) + list = IntegerConfig.new(:key).extend List input = [1,'2',3] output = list.cast(input) @@ -30,7 +30,7 @@ def test_cast_casts_each_value_of_the_input # def test_uncast_uncasts_each_value_of_the_input - list = List.new(:key, :type => IntegerType.new) + list = IntegerConfig.new(:key).extend List input = [1,'2',3] output = list.uncast(input) diff --git a/test/configurable/config_classes/nest_test.rb b/test/configurable/config_classes/nest_test.rb index b2df39b..dc08c3a 100644 --- a/test/configurable/config_classes/nest_test.rb +++ b/test/configurable/config_classes/nest_test.rb @@ -1,12 +1,12 @@ require File.expand_path('../../../test_helper', __FILE__) require 'configurable/config_classes' -require 'configurable/config_types' +require 'configurable/config_classes' require 'configurable/config_hash' require 'ostruct' class NestTest < Test::Unit::TestCase include Configurable::ConfigClasses - include Configurable::ConfigTypes + include Configurable::ConfigClasses ConfigHash = Configurable::ConfigHash class Parent < OpenStruct diff --git a/test/configurable/config_types/string_type_test.rb b/test/configurable/config_classes/string_config_test.rb similarity index 66% rename from test/configurable/config_types/string_type_test.rb rename to test/configurable/config_classes/string_config_test.rb index 1d92aaa..3ceb64a 100644 --- a/test/configurable/config_types/string_type_test.rb +++ b/test/configurable/config_classes/string_config_test.rb @@ -1,13 +1,13 @@ require File.expand_path('../../../test_helper', __FILE__) -require 'configurable/config_types' +require 'configurable/config_classes' -class StringTypeTest < Test::Unit::TestCase - include Configurable::ConfigTypes +class StringConfigTest < Test::Unit::TestCase + include Configurable::ConfigClasses attr_reader :type def setup - @type = StringType.new + @type = StringConfig.new(:key) end # diff --git a/test/configurable/config_types/object_type_test.rb b/test/configurable/config_types/object_type_test.rb deleted file mode 100644 index 5241819..0000000 --- a/test/configurable/config_types/object_type_test.rb +++ /dev/null @@ -1,30 +0,0 @@ -require File.expand_path('../../../test_helper', __FILE__) -require 'configurable/config_types' - -class ObjectTypeTest < Test::Unit::TestCase - include Configurable::ConfigTypes - - attr_reader :type - - def setup - @type = ObjectType.new - end - - # - # cast test - # - - def test_cast_returns_input - obj = Object.new - assert_equal obj.object_id, type.cast(obj).object_id - end - - # - # uncast test - # - - def test_uncast_returns_value - obj = Object.new - assert_equal obj.object_id, type.uncast(obj).object_id - end -end \ No newline at end of file diff --git a/test/configurable/conversions_test.rb b/test/configurable/conversions_test.rb index f841567..9ff27bb 100644 --- a/test/configurable/conversions_test.rb +++ b/test/configurable/conversions_test.rb @@ -1,10 +1,10 @@ require File.expand_path('../../test_helper', __FILE__) require 'configurable/conversions' -require 'configurable/config_types' +require 'configurable/config_classes' class ConversionsTest < Test::Unit::TestCase include Configurable::ConfigClasses - include Configurable::ConfigTypes + include Configurable::ConfigClasses Conversions = Configurable::Conversions attr_accessor :configs @@ -14,9 +14,9 @@ def setup @configs.extend Conversions end - def config(key, attrs={}, &caster) - attrs[:type] = StringType.subclass(&caster).new(attrs) if caster - configs[key] = Config.new(key, attrs) + def config(key, attrs={}, config_class = Config, &caster) + config_class = caster ? StringConfig.subclass(&caster) : config_class + configs[key] = config_class.new(key, attrs) end # @@ -122,7 +122,7 @@ def test_export_maps_config_keys_to_config_names end def test_export_exports_values - config(:one, :type => IntegerType.new) + config(:one, {}, IntegerConfig) assert_equal({ 'one' => '1' diff --git a/test/configurable_test.rb b/test/configurable_test.rb index ec20073..16a3af8 100644 --- a/test/configurable_test.rb +++ b/test/configurable_test.rb @@ -4,7 +4,7 @@ class ConfigurableTest < Test::Unit::TestCase include Configurable::ConfigClasses - include Configurable::ConfigTypes + include Configurable::ConfigClasses ConfigHash = Configurable::ConfigHash # @@ -110,7 +110,6 @@ class ConfigTypeClass def test_config_type_registers_a_config_type config_type = ConfigTypeClass.config_types[:upcase] - assert_equal 'XYZ', config_type.new.cast('xyz') assert_equal 'XYZ', ConfigTypeClass.configs[:key].cast('xyz') end @@ -177,7 +176,7 @@ def test_config_types_do_not_float_up module ConfigTypeSpecificity include Configurable - # increase specificity for Bignum, over IntegerType + # increase specificity for Bignum, over IntegerConfig config_type(:bignum, Bignum) config :one, 10**10 @@ -185,32 +184,32 @@ module ConfigTypeSpecificity end def test_config_types_can_increase_specificity - assert_equal IntegerType, ConfigTypeSpecificity.configs[:one].type.class - assert_equal ConfigTypeSpecificity::BignumType, ConfigTypeSpecificity.configs[:two].type.class + assert_equal IntegerConfig, ConfigTypeSpecificity.configs[:one].class + assert_equal ConfigTypeSpecificity::BignumType, ConfigTypeSpecificity.configs[:two].class end module ConfigTypeOverrideByMatch include Configurable - # match integers, instead of IntegerType + # match integers, instead of IntegerConfig config_type(:num, Integer) config :one, 1 end def test_config_types_can_be_overridden_by_match - assert_equal ConfigTypeOverrideByMatch::NumType, ConfigTypeOverrideByMatch.configs[:one].type.class + assert_equal ConfigTypeOverrideByMatch::NumType, ConfigTypeOverrideByMatch.configs[:one].class end module ConfigTypeOverrideByName include Configurable - # match int type, instead of IntegerType + # match int type, instead of IntegerConfig config_type(:int) config :one, 1, :type => :int end def test_config_types_can_be_overridden_by_name - assert_equal ConfigTypeOverrideByName::IntType, ConfigTypeOverrideByName.configs[:one].type.class + assert_equal ConfigTypeOverrideByName::IntType, ConfigTypeOverrideByName.configs[:one].class end # @@ -468,7 +467,7 @@ class ListClass def test_config_generates_a_list_config_for_array_default config = ListClass.configs[:key] - assert_equal List, config.class + assert_equal true, config.kind_of?(List) end class ListOfIntegersClass @@ -500,9 +499,6 @@ def test_config_generates_a_nest_config_for_configurable_default config = NestClass.configs[:outer] assert_equal Nest, config.class assert_equal NestClass::Outer, config.configurable.class - - assert_equal NestType, config.type.class - assert_equal NestClass::Outer, config.type.configurable.class assert_equal({:inner => 1}, config.cast({'inner' => '1'})) end @@ -515,9 +511,6 @@ def test_config_generates_a_nest_config_and_configurable_class_for_hash_default config = HashNestClass.configs[:outer] assert_equal Nest, config.class assert_equal HashNestClass::Outer, config.configurable.class - - assert_equal NestType, config.type.class - assert_equal HashNestClass::Outer, config.type.configurable.class assert_equal({:inner => 1}, config.cast({'inner' => '1'})) end @@ -532,9 +525,6 @@ def test_config_generates_a_nest_config_and_configurable_class_for_block config = BlockNestClass.configs[:outer] assert_equal Nest, config.class assert_equal BlockNestClass::Outer, config.configurable.class - - assert_equal NestType, config.type.class - assert_equal BlockNestClass::Outer, config.type.configurable.class assert_equal({:inner => 1}, config.cast({'inner' => '1'})) end