lib/mattock/configurable.rb in mattock-0.2.5 vs lib/mattock/configurable.rb in mattock-0.2.6

- old
+ new

@@ -1,6 +1,13 @@ module Mattock + #Handles setting options on objects its mixed into + # + #Settings can have default values or be required (as opposed to defaulting to + #nil). Settings and their defaults are inherited (and can be overridden) by + #subclasses. + # + #@example (see ClassMethods) module Configurable RequiredField = Object.new class << RequiredField def to_s "<unset>" @@ -10,12 +17,33 @@ to_s end end RequiredField.freeze + #Describes class level DSL & machinery for working with configuration + #managment. + # + #@example Quick example + # class ConfExample + # include Configurable + # + # setting :foo + # settings :bar => 1, :baz => 3 + # nil_fields :hoo, :ha, :harum + # required_fields :must + # + # def initialize + # setup_defaults + # end + # end + # + # ce = ConfExample.new + # ce.bar #=> 1 + # ce.hoo #=> nil + # ce.hoo = "hallo" + # ce.check_required #=> raises error because :must and :foo aren't set module ClassMethods - def default_values @default_values ||= {} end def set_defaults_on(instance) @@ -61,43 +89,51 @@ #shrug it off end end 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) obj = Class.new(Struct).new obj.settings(hash || {}) return obj end + #Quick list of setting fields with a default value of nil. Useful + #especially with {CascadingDefinition#resolve_configuration} def nil_fields(*names) names.each do |name| setting(name, nil) end end alias nil_field nil_fields + #List fields with no default for with a value must be set before + #definition. def required_fields(*names) names.each do |name| setting(name) end end alias required_field required_fields - # @macro [attack] configurable_property - # @method $1 - # @return [$2] The default value of $1 - # @method $1= + #Defines a setting on this class - much like a attr_accessible call, but + #allows for defaults and required settings def setting(name, default_value = RequiredField) name = name.to_sym attr_accessor(name) if default_values.has_key?(name) and default_values[name] != default_value warn "Changing default value of #{self.name}##{name} from #{default_values[name].inspect} to #{default_value.inspect}" end default_values[name] = default_value end + #@param [Hash] hash Pairs of name/value to be converted into + # setting/default def settings(hash) hash.each_pair do |name, value| setting(name, value) end return self @@ -105,21 +141,26 @@ def included(mod) mod.extend ClassMethods end end + extend ClassMethods def copy_settings_to(other) self.class.copy_settings(self, other) self end + #Call during initialize to set default values on settings - if you're using + #Configurable outside of Mattock, be sure this gets called. def setup_defaults self.class.set_defaults_on(self) self end + #Checks that all required fields have be set, otherwise raises an error + #@raise RuntimeError if any required fields are unset def check_required missing = self.class.missing_required_fields_on(self) unless missing.empty? raise "Required field#{missing.length > 1 ? "s" : ""} #{missing.map{|field| field.to_s.inspect}.join(", ")} unset on #{self.inspect}" end