module Yaks::Configurable

A “Configurable” class is one that keeps a configuration in a separate immutable object, of type class::Config. say you have

class MyMapper < Yaks::Mapper
  # use yaks configuration DSL in here
end

The links, associations, etc, that you set up for MyMapper, will be available in MyMapper.config, which is an instance of Yaks::Mapper::Config.

Each configuration step, like `link`, `has_many`, will replace MyMapper.config with an updated version, discarding the old config.

By extending Configurable, a number of “macros” become available to describe the DSL that subclasses can use. See the docs for `def_set`. `def_forward`, and `def_add`.

Attributes

config[RW]

Public Class Methods

extended(child) click to toggle source
# File lib/yaks/configurable.rb, line 23
def self.extended(child)
  child.config = child::Config.new
end

Public Instance Methods

def_add(name, options) click to toggle source

Generate a DSL method that creates a certain type of domain object, and adds it to a list on the config.

def_add :fieldset, create: Fieldset, append_to: :fields

This will generate a `fieldset` method, which will call `Fieldset.create`, and append the result to `config.fields`

# File lib/yaks/configurable.rb, line 76
def def_add(name, options)
  old_verbose, $VERBOSE = $VERBOSE, false # skip method redefinition warning
  define_singleton_method name do |*args, &block|
    defaults = options.fetch(:defaults, {})
    klass    = options.fetch(:create)

    if args.last.instance_of?(Hash)
      args[-1] = defaults.merge(args[-1])
    else
      args << defaults
    end

    self.config = config.append_to(
      options.fetch(:append_to),
      klass.create(*args, &block)
    )
  end
ensure
  $VERBOSE = old_verbose
end
def_forward(mappings, *names) click to toggle source

Forward a method to the config object. This assumes the method will return an updated config instance.

Either takes a list of methods to forward, or a mapping (hash) of source to destination method name.

# File lib/yaks/configurable.rb, line 57
def def_forward(mappings, *names)
  if mappings.instance_of? Hash
    mappings.each do |method_name, target|
      define_singleton_method method_name do |*args, &block|
        self.config = config.public_send(target, *args, &block)
      end
    end
  else
    def_forward([mappings, *names].map{|name| {name => name}}.inject(:merge))
  end
end
def_set(*method_names) click to toggle source

Create a DSL method to set a certain config property. The generated method will take either a plain value, or a block, which will be captured and stored instead.

# File lib/yaks/configurable.rb, line 34
def def_set(*method_names)
  method_names.each do |method_name|
    define_singleton_method method_name do |arg = Undefined, &block|
      if arg.equal?(Undefined)
        unless block
          raise ArgumentError, "setting #{method_name}: no value and no block given"
        end
        self.config = config.with(method_name => block)
      else
        if block
          raise ArgumentError, "ambiguous invocation setting #{method_name}: give either a value or a block, not both."
        end
        self.config = config.with(method_name => arg)
      end
    end
  end
end
inherited(child) click to toggle source
# File lib/yaks/configurable.rb, line 27
def inherited(child)
  child.config = config
end