Module: Yaks::Configurable

Included in:
Builder, Mapper
Defined in:
lib/yaks/configurable.rb

Overview

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.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#configObject

Returns the value of attribute config.



21
22
23
# File 'lib/yaks/configurable.rb', line 21

def config
  @config
end

Class Method Details

.extended(child) ⇒ Object



23
24
25
# File 'lib/yaks/configurable.rb', line 23

def self.extended(child)
  child.config = child::Config.new
end

Instance Method Details

#def_add(name, options) ⇒ Object

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



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# 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) ⇒ Object

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.



57
58
59
60
61
62
63
64
65
66
67
# 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) ⇒ Object

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.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 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) ⇒ Object



27
28
29
# File 'lib/yaks/configurable.rb', line 27

def inherited(child)
  child.config = config
end