lib/mattock/configurable.rb in mattock-0.3.4 vs lib/mattock/configurable.rb in mattock-0.4.0
- old
+ new
@@ -8,10 +8,19 @@
#Mattock also includes a yard-extension that will document settings of a
#Configurable
#
#@example (see ClassMethods)
module Configurable
+ class Exception < ::StandardError
+ end
+
+ class NoDefaultValue < Exception
+ def initialize(field_name, klass)
+ super("No default value for field #{field_name} on class #{klass.name}")
+ end
+ end
+
class FieldMetadata
attr_accessor :name, :default_value
DEFAULT_PROPERTIES = {
:copiable => true,
@@ -130,11 +139,11 @@
@source, @field = source, field
end
attr_reader :source, :field
def inspect
- "#{self.class.name.split(':').last}: #{value}"
+ "#{self.class.name.split(':').last}: #{source.class.name}.#{field.inspect}"
end
end
class ProxyDecorator
def initialize(configurable)
@@ -220,10 +229,17 @@
# ce.bar #=> 1
# ce.hoo #=> nil
# ce.hoo = "hallo"
# ce.check_required #=> raises error because :must and :foo aren't set
module ClassMethods
+ def inspect_instance(instance, indent="")
+ field_names.map do |name|
+ meta = field_metadata(name)
+ "#{indent}#{meta.inspect} => #{meta.immediate_value_on(instance).inspect}(#{meta.value_on(instance).inspect})"
+ end.join("\n")
+ end
+
def default_values
@default_values ||= []
end
def field_names
@@ -242,10 +258,17 @@
else
field
end
end
+ #@raises NoDefaultValue
+ def default_value_for(name)
+ field = field_metadata(name)
+ raise NoDefaultValue.new(name,self) unless field.is?(:defaulting)
+ return field.default_value
+ end
+
#Creates an anonymous Configurable - useful in complex setups for nested
#settings
#@example SSH options
# setting :ssh => nested(:username => "me", :password => nil)
def nested(hash=nil, &block)
@@ -295,12 +318,12 @@
value = metadata.value_on(self)
end
if existing = default_values.find{|field| field.name == name} and existing.default_value != default_value
source_line = caller.drop_while{|line| /#{__FILE__}/ =~ line}.first
- warn "Changing default value of #{self.name}##{name} from #{existing.default_value.inspect} to #{default_value.inspect}"
- " (at: #{source_line})"
+ warn "Changing default value of #{self.name}##{name} from #{existing.default_value.inspect} to #{default_value.inspect}"
+ " (at: #{source_line})"
end
default_values << metadata
metadata
end
@@ -410,9 +433,67 @@
mod.extend ClassMethods
end
end
extend ClassMethods
+
+ module DirectoryStructure
+ module ClassMethods
+ RequiredField = ::Mattock::Configurable::ClassMethods::RequiredField
+
+ attr_accessor :path_heirarchy
+ attr_accessor :path_fields
+
+ def dir(field_name, *args)
+ rel_path = RequiredField
+ if String === args.first
+ rel_path = args.shift
+ end
+ parent_field = path(field_name, rel_path)
+ self.path_heirarchy += args.map do |child_field|
+ [parent_field, child_field]
+ end
+ return parent_field
+ end
+
+ def path(field_name, rel_path=RequiredField)
+ field = setting(field_name, nested{
+ required_field :absolute_path
+ setting :relative_path, rel_path
+ })
+ path_fields << field
+ return field
+ end
+ end
+
+ def self.included(sub)
+ sub.extend ClassMethods
+ sub.path_heirarchy = []
+ sub.path_fields = []
+ end
+
+ def resolve_paths
+ missing_relatives = []
+ self.class.path_heirarchy.reverse.each do |parent_field, child_field|
+ child = child_field.value_on(self)
+ next unless child.field_unset?(:absolute_path)
+ if child.field_unset?(:relative_path)
+ missing_relatives << child_field
+ next
+ end
+ parent = parent_field.value_on(self)
+ child.absolute_path = File::join(parent.absolute_path, child.relative_path)
+ end
+ unless missing_relatives.empty?
+ raise "Required field#{missing_relatives.length == 1 ? "" : "s"} #{missing_relatives.map{|field| "#{field.name}.relative_path".inspect}.join(", ")} unset on #{self.inspect}"
+ end
+ self.class.path_fields.each do |field|
+ value = field.value_on(self)
+ next unless value.field_unset?(:relative_path)
+ value.relative_path = value.absolute_path
+ end
+ end
+ end
def copy_settings
SettingsCopier.new(self)
end