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



72
73
74
75
76
77
78
79
80
# File 'lib/poise/helpers/option_collector.rb', line 72

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) ⇒ 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.

Raises:

Since:

  • 1.0.0



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/poise/helpers/option_collector.rb', line 89

def option_collector_attribute(name, default: {}, parser: nil)
  raise Poise::Error.new("Parser must be a Proc or Symbol: #{parser.inspect}") if parser && !(parser.is_a?(Proc) || parser.is_a?(Symbol))
  # 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)
      ctx.instance_exec(&block)
      value.update(ctx._options)
    end
    instance_variable_set(iv_sym, value)
    value
  end
end