module Calibrate::Configurable::ClassMethods

Describes class level DSL & machinery for working with configuration managment.

@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

Public Instance Methods

default_value_for(name) click to toggle source

@raises NoDefaultValue

# File lib/calibrate/configurable/class-methods.rb, line 58
def default_value_for(name)
  field = field_metadata(name)
  raise NoDefaultValue.new(name,self) unless field.is?(:defaulting)
  return field.default_value
end
default_values() click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 35
def default_values
  @default_values ||= []
end
field_metadata(name) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 48
def field_metadata(name)
  field = default_values.find{|field| field.name == name}
  if field.nil? and Configurable > superclass
    superclass.field_metadata(name)
  else
    field
  end
end
field_names() click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 39
def field_names
  names = default_values.map{|field| field.name}
  if Configurable > superclass
    names | superclass.field_names
  else
    names
  end
end
from_hash(obj, hash) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 196
def from_hash(obj, hash) #XXX It'd be really nice if this could report unused fields
  if Configurable > superclass
    superclass.from_hash(obj, hash)
  end
  default_values.each do |field|
    catch :next do
      key = field.reader_method.to_s
      value = hash.fetch(key.to_s) do
        key = key.to_sym
        hash.fetch(key) do
          throw :next
        end
      end

      existing_value = obj.__send__(field.reader_method)
      if Configurable === existing_value and value.is_a? Hash
        existing_value.from_hash(value)
      else
        obj.__send__(field.writer_method, value)
      end
    end
  end
end
included(mod) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 220
def included(mod)
  mod.extend ClassMethods
end
inspect_instance(instance, indent="") click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 28
def inspect_instance(instance, indent="")
  field_names.map do |name|
    meta = field_metadata(name)
    "#{indent}#{meta.inspect_on(instance, indent * 2)}"
  end.join("\n")
end
missing_required_fields_on(instance) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 154
def missing_required_fields_on(instance)
  missing = []
  if Configurable > superclass
    missing = superclass.missing_required_fields_on(instance)
  end
  default_values.each do |field|
    if field.missing_on?(instance)
      missing << field.name
    else
      set_value = instance.__send__(field.reader_method)
      if Configurable === set_value
        missing += set_value.class.missing_required_fields_on(set_value).map do |sub_field|
          [field.name, sub_field].join(".")
        end
      end
    end
  end
  return missing
end
nested(hash=nil, &block) click to toggle source

Creates an anonymous Configurable - useful in complex setups for nested settings @example SSH options

setting :ssh => nested(:username => "me", :password => nil)
# File lib/calibrate/configurable/class-methods.rb, line 68
def nested(hash=nil, &block)
  nested = Class.new(Struct)
  nested.settings(hash || {})
  if block_given?
    nested.instance_eval(&block)
  end
  return nested
end
nil_field(*names)
Alias for: nil_fields
nil_fields(*names) click to toggle source

Quick list of setting fields with a default value of nil. Useful especially with {CascadingDefinition#resolve_configuration}

# File lib/calibrate/configurable/class-methods.rb, line 79
def nil_fields(*names)
  names.each do |name|
    setting(name, nil)
  end
  self
end
Also aliased as: nil_field
required_field(*names)
Alias for: required_fields
required_fields(*names) click to toggle source

List fields with no default for with a value must be set before definition.

# File lib/calibrate/configurable/class-methods.rb, line 89
def required_fields(*names)
  names.each do |name|
    setting(name)
  end
  self
end
Also aliased as: required_field
runtime_required_field(*names)
runtime_required_fields(*names) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 121
def runtime_required_fields(*names)
  names.each do |name|
    runtime_setting(name)
  end
  self
end
Also aliased as: runtime_required_field
runtime_setting(name, default_value = RequiredField) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 129
def runtime_setting(name, default_value = RequiredField)
  setting(name, default_value).is(:runtime)
end
runtime_settings(hash)
Alias for: settings
set_defaults_on(instance) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 143
def set_defaults_on(instance)
  if Configurable > superclass
    superclass.set_defaults_on(instance)
  end
  default_values.each do |field|
    next unless field.is? :defaulting
    value = field.build_default_value
    instance.__send__(field.writer_method, value)
  end
end
setting(name, default_value = RequiredField) click to toggle source

Defines a setting on this class - much like a attr_accessible call, but allows for defaults and required settings

# File lib/calibrate/configurable/class-methods.rb, line 99
def setting(name, default_value = RequiredField)
  name = name.to_sym
  metadata =
    if default_value == RequiredField
      FieldMetadata.new(name, nil).is(:required).isnt(:defaulting)
    else
      FieldMetadata.new(name, default_value)
    end

  attr_writer(name)
  define_method(metadata.reader_method) do
    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})"
  end
  default_values << metadata
  metadata
end
settings(hash) click to toggle source

@param [Hash] hash Pairs of name/value to be converted into

setting/default
# File lib/calibrate/configurable/class-methods.rb, line 135
def settings(hash)
  hash.each_pair do |name, value|
    setting(name, value)
  end
  return self
end
Also aliased as: runtime_settings
to_hash(obj) click to toggle source
# File lib/calibrate/configurable/class-methods.rb, line 174
def to_hash(obj)
  hash = if Configurable > superclass
           superclass.to_hash(obj)
         else
           {}
         end
  hash.merge( Hash[default_values.map{|field|
    begin
      value = obj.__send__(field.reader_method)
      value =
        case value
        when Configurable
          value.to_hash
        else
          value
        end
      [field.name, value]
    rescue NoMethodError
    end
  }])
end