lib/distil/configurable.rb in distil-0.13.6 vs lib/distil/configurable.rb in distil-0.14.0.b
- old
+ new
@@ -1,168 +1,79 @@
-module Kernel
-
- def Boolean(string)
- return true if string == true || string =~ /^true$/i
- return false if string == false || string.nil? || string =~ /^false$/i
- raise ArgumentError.new("invalid value for Boolean: \"#{string}\"")
- end
-
-end
-
-class ValidationError < StandardError
-end
-
-
-class Configurable
- attr_reader :options
+module Distil
- @@options= {}
-
- def get_option(name)
- return nil if !@options.respond_to?(name)
- value=@options[name]
- value.respond_to?(:value_of) ? value.value_of(self) : value
- end
+ class Configurable
- def get_options(settings=nil, parent=nil)
- keys= @@options.keys
- values= @@options.map { |k,v| convert_type(v[:type], v[:value]) }
-
- s= @options ? @options : (@options=Struct.new(*keys).new(*values))
- return s if !settings
-
- setting_keys= settings.keys.map { |key| key.to_s }
-
- @@options.each { |key, value|
-
- intersect= value[:aliases] & setting_keys
- next if !parent && intersect.empty?
-
- if (intersect.empty?)
- s[key]= parent[key]
- next
- end
+ @@config_aliases={}
+ def self.alias_config_key(original, key_alias)
+ @@config_aliases[key_alias.to_s]= original.to_s
+ end
- if (intersect.length>1)
- raise ArgumentError, "Multiple variants for #{key.to_s} defined: #{intersect.join(", ")}"
- end
-
- setting_key= intersect[0]
- setting_value= settings[setting_key]
- settings.delete(setting_key)
+ def key_for_alias(key_alias)
+ key_alias= key_alias.to_s.gsub("-", "_").gsub(" ", "_")
+ @@config_aliases[key_alias] || key_alias
+ end
- # decide if any type conversions are needed...
- setting_value= convert_type(value[:type], setting_value)
-
- if (value.has_key?(:valid_values) && !value[:valid_values].include?(setting_value))
- raise ValidationError, "Invalid value for '#{setting_key}': #{setting_value}"
- end
-
- s[key]= setting_value
+ class ConfigDsl
- }
-
- @extras.merge!(settings)
- s
- end
-
- # option name, [type], [default], [options]
- def self.option(name, *rest)
-
- name_string= name.to_s
-
- info= {
- :aliases=>[name_string, name_string.gsub('_', '-'), name_string.gsub('_', ' ')].uniq
- }
-
- arg= rest.shift
-
- if (arg.is_a?(Class) || arg==URI)
- info[:type]= arg
- info[:value]= nil
- arg= rest.shift
- end
-
- if (!arg.nil? && !arg.is_a?(Hash))
- info[:value]= arg
- info[:type]= arg.class if !info.has_key?(:type)
- arg= rest.shift
- end
-
- # handle named arguments
- if (arg.is_a?(Hash))
- if arg.has_key?(:aliases)
- info[:aliases].concat(arg[:aliases]).uniq!
- arg.delete(:aliases)
+ def initialize(hash)
+ @hash= hash
+ @used= Set.new
end
- info.merge!(arg)
- end
- if @@options.has_key?(name)
- orig= @@options[name]
- if orig.has_key?(:type) && info.has_key?(:type) && info[:type]!=orig[:type]
- raise ArgumentError, "Redefinition of option #{self}##{name} changes type"
+ def with_each(key)
+ case when @hash.include?(key.to_sym)
+ value= @hash[key.to_sym]
+ when @hash.include?(key.to_s)
+ value= @hash[key.to_s]
+ else
+ return
+ end
+
+ value= value.split(",").map { |s| s.strip } if value.is_a?(String)
+ value.each { |v| yield v }
+ @used << key.to_s
end
- if orig.has_key?(:value) && !info[:value].nil? && info[:value]!=orig[:value]
- raise ArgumentError, "Redefinition of option #{name} changes value"
+
+ def with(key)
+ case when @hash.include?(key.to_sym)
+ yield @hash[key.to_sym]
+ when @hash.include?(key.to_s)
+ yield @hash[key.to_s]
+ else
+ return
+ end
+ @used << key.to_s
end
- orig[:type]||=info[:type]
- orig[:value]||=info[:value]
- orig[:aliases].concat(info[:aliases]).uniq!
- else
- @@options[name]= info
+
+ def used?(key)
+ @used.include?(key.to_s)
+ end
+
end
- self.send :define_method, name do
- value=@options[name]
- value.respond_to?(:value_of) ? value.value_of(self) : value
+ def configure_with(hash)
+ new_hash= {}
+ hash.each { |key, value|
+ new_hash[key_for_alias(key)]= value
+ }
+
+ dsl= ConfigDsl.new(new_hash)
+ yield dsl if block_given?
+
+ new_hash.each { |key, value|
+ next if dsl.used?(key.to_s)
+
+ key= key_for_alias(key)
+ case
+ when self.respond_to?("#{key}=")
+ self.send "#{key}=", value
+ when self.respond_to?(key) && 0!=self.method(key).arity
+ self.send key, value
+ else
+ self.instance_variable_set("@#{key}", value)
+ end
+ }
end
- self.send :define_method, "#{name}=" do |value|
- @options[name]= convert_type(@@options[name][:type], value)
- end
-
- # self.send :protected, "#{name}=".to_s
-
end
-
- def initialize(options={}, parent=nil)
- @extras= Hash.new
- if (parent.is_a?(Configurable))
- parent_options= parent.options
- end
- get_options(options, parent_options)
- end
- private
-
- def convert_type(type, value)
- case
- when FalseClass==type || TrueClass==type
- Boolean(value)
- when Array==type
- value.is_a?(String) ? value.split(/\s*,\s*/) : value
- when Fixnum==type
- value.to_i
- when nil==type || NilClass==type
- value
- when String==type
- value ? value.to_s : nil;
- when value.nil?
- value
- when URI==type
- URI.parse(value)
- else
- if type.respond_to?(:from_options)
- type.from_options(value, self)
- else
- puts "type=#{type} value=#{value}"
- type.new(value)
- end
- end
- end
-
-end
-
-Dir.glob("#{File.dirname(__FILE__)}/configurable/*.rb") { |file|
- require file
-}
+end
\ No newline at end of file