Module: Poise::Helpers::OptionCollector

Included in:
TemplateContent, Resource
Defined in:
lib/poise/helpers/option_collector.rb

Overview

A resource mixin to add a new kind of attribute, an option collector. These attributes can act as mini-DSLs for things which would otherwise be key/value pairs.

Examples:

Defining an option collector

class MyResource < Chef::Resource
  include Poise::Helpers::OptionCollector
  attribute(:my_options, option_collector: true)
end

Using an option collector

my_resource 'name' do
  my_options do
    key1 'value1'
    key2 'value2'
  end
end

Since:

  • 1.0.0

Class Method Summary collapse

Class Method Details

.attribute(name, options = {}) ⇒ Object

Override the normal #attribute() method to support defining option collectors too.

Since:

  • 1.0.0



79
80
81
82
83
84
85
86
87
# File 'lib/poise/helpers/option_collector.rb', line 79

def attribute(name, options={})
  # If present but false-y, make sure it is removed anyway so it
  # doesn't confuse ParamsValidate.
  if options.delete(:option_collector)
    option_collector_attribute(name, options)
  else
    super
  end
end

.option_collector_attribute(name, default: {}, parser: nil, forced_keys: Set.new) ⇒ Object

Define an option collector attribute. Normally used via attribute.

Parameters:

  • name (String, Symbol)

    Name of the attribute to define.

  • default (Hash) (defaults to: {})

    Default value for the options.

  • parser (Proc, Symbol) (defaults to: nil)

    Optional parser method. If a symbol it is called as a method on self. Takes a non-hash value and returns a hash of its parsed representation.

  • forced_keys (Array<Symbol>, Set<Symbol>) (defaults to: Set.new)

    Method names that will be forced to be options rather than calls to the parent resource.

Raises:

Since:

  • 1.0.0



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/poise/helpers/option_collector.rb', line 98

def option_collector_attribute(name, default: {}, parser: nil, forced_keys: Set.new)
  raise Poise::Error.new("Parser must be a Proc or Symbol: #{parser.inspect}") if parser && !(parser.is_a?(Proc) || parser.is_a?(Symbol))
  # Cast to a set at definition time.
  forced_keys = Set.new(forced_keys) unless forced_keys.is_a?(Set)
  # Unlike LWRPBase.attribute, I don't care about Ruby 1.8. Worlds tiniest violin.
  define_method(name.to_sym) do |arg=nil, &block|
    iv_sym = :"@#{name}"

    value = instance_variable_get(iv_sym) || begin
      default = instance_eval(&default) if default.is_a?(Chef::DelayedEvaluator) # Handle lazy{}
      Mash.new(default) # Wrap in a mash because fuck str vs sym.
    end
    if arg
      if !arg.is_a?(Hash) && parser
        arg = case parser
              when Proc
                instance_exec(arg, &parser)
              when Symbol
                send(parser, arg)
              end
      end
      raise Exceptions::ValidationFailed, "Option #{name} must be a Hash" if !arg.is_a?(Hash)
      # Should this and the update below be a deep merge?
      value.update(arg)
    end
    if block
      ctx = OptionEvalContext.new(self, forced_keys)
      ctx.instance_exec(&block)
      value.update(ctx._options)
    end
    instance_variable_set(iv_sym, value)
    value
  end
end