class Innate::Options

Provides a minimal DSL to describe options with defaults and metadata.

The example below should demonstrate the major features, note that key lookup wanders up the hierarchy until there is a match found or the parent of the Options class is itself, in which case nil will be returned.

Usage:

class Calculator
  @options = Options.new(:foo)
  def self.options; @options; end

  options.dsl do
    o "Which method to use", :method, :plus
    o "Default arguments", :args, [1, 2]
    sub(:minus){ o("Default arguments", :args, [4, 3]) }
  end

  def self.calculate(method = nil, *args)
    method ||= options[:method]
    args = args.empty? ? options[method, :args] : args
    self.send(method, *args)
  end

  def self.plus(n1, n2)
    n1 + n2
  end

  def self.minus(n1, n2)
    n1 - n2
  end
end

Calculator.calculate
# => 3
Calculator.options[:method] = :minus
# => :minus
Calculator.calculate
# => 1
Calculator.calculate(:plus, 4, 5)
# => 9

Public Class Methods

new(name, parent = self) { |self| ... } click to toggle source
# File lib/innate/options/dsl.rb, line 45
def initialize(name, parent = self)
  @name, @parent, = name, parent
  @hash = {}
  yield(self) if block_given?
end

Public Instance Methods

[](*keys) click to toggle source

Retrieve only the :value from the value hash if found via keys.

# File lib/innate/options/dsl.rb, line 125
def [](*keys)
  if value = get(*keys)
    value.is_a?(Hash) ? value[:value] : value
  end
end
[]=(key, value) click to toggle source

Assign new :value to the value hash on the current instance.

TODO: allow arbitrary assignments

# File lib/innate/options/dsl.rb, line 134
def []=(key, value)
  ks = key.to_sym
  if @hash.has_key? ks
    ns = @hash[ks]
    ns[:value] = value
    ns[:trigger].call(value) if ns[:trigger].respond_to?(:call)
  elsif existing = get(key)
    option(existing[:doc].to_s.dup, key, value)
  else
    raise(ArgumentError, "No key for %p exists" % [key])
  end
end
default(doc, value, other = {}) click to toggle source

To avoid lookup on the parent, we can set a default to the internal Hash. Parameters as in {Options#o}, but without the key.

# File lib/innate/options/dsl.rb, line 89
def default(doc, value, other = {})
  @hash.default = other.merge(:doc => doc, :value => value)
end
dsl(&block) click to toggle source

Shortcut for instance_eval

# File lib/innate/options/dsl.rb, line 52
def dsl(&block)
  instance_eval(&block) if block
  self
end
each_option(&block) click to toggle source
# File lib/innate/options/dsl.rb, line 166
def each_option(&block)
  @hash.each(&block)
end
each_pair() { |key, self| ... } click to toggle source
# File lib/innate/options/dsl.rb, line 170
def each_pair
  @hash.each do |key, values|
    yield(key, self[key])
  end
end
get(key, *keys) click to toggle source

Try to retrieve the corresponding Hash for the passed keys, will try to retrieve the key from a parent if no match is found on the current instance. If multiple keys are passed it will try to find a matching child and pass the request on to it.

# File lib/innate/options/dsl.rb, line 102
def get(key, *keys)
  if keys.empty?
    if value = @hash[key.to_sym]
      value
    elsif @parent != self
      @parent.get(key)
    else
      nil
    end
  elsif sub_options = get(key)
    sub_options.get(*keys)
  end
end
inspect() click to toggle source
# File lib/innate/options/dsl.rb, line 176
def inspect
  @hash.inspect
end
merge!(hash) click to toggle source
# File lib/innate/options/dsl.rb, line 156
def merge!(hash)
  hash.each_pair do |key, value|
    set_value(key.to_s.split('.'), value)
  end
end
method_missing(meth, *args) click to toggle source
# File lib/innate/options/dsl.rb, line 147
def method_missing(meth, *args)
  case meth.to_s
  when /^(.*)=$/
    self[$1] = args.first
  else
    self[meth]
  end
end
o(doc, key, value, other = {}, &block)
Alias for: option
option(doc, key, value, other = {}, &block) click to toggle source

Store an option in the Options instance.

@param [#to_s] doc describing the purpose of this option @param [#to_sym] key used to access @param [Object] value may be anything @param [Hash] other optional Hash containing meta-data

:doc, :value keys will be ignored
# File lib/innate/options/dsl.rb, line 79
def option(doc, key, value, other = {}, &block)
  trigger = block || other[:trigger]
  convert = {:doc => doc.to_s, :value => value}
  convert[:trigger] = trigger if trigger
  @hash[key.to_sym] = other.merge(convert)
end
Also aliased as: o
pretty_print(q) click to toggle source
# File lib/innate/options/dsl.rb, line 180
def pretty_print(q)
  q.pp_hash @hash
end
set_value(keys, value) click to toggle source

@param [Array] keys @param [Object] value

# File lib/innate/options/dsl.rb, line 118
def set_value(keys, value)
  got = get(*keys)
  return got[:value] = value if got
  raise(IndexError, "There is no option available for %p" % [keys])
end
sub(name, &block) click to toggle source

Create a new Options instance with name and pass block on to its dsl. Assigns the new instance to the name Symbol on current instance.

# File lib/innate/options/dsl.rb, line 59
def sub(name, &block)
  name = name.to_sym

  case found = @hash[name]
  when Options
    found.dsl(&block)
  else
    found = @hash[name] = Options.new(name, self).dsl(&block)
  end

  found
end
to_hash() click to toggle source
# File lib/innate/options/dsl.rb, line 162
def to_hash
  @hash
end
trigger(key, &block) click to toggle source

Add a block that will be called when a new value is set.

# File lib/innate/options/dsl.rb, line 94
def trigger(key, &block)
  @hash[key.to_sym][:trigger] = block
end