module Humidifier module Reservoir # The parent class for mapper classes. These classes are used to transform # arbitrary attributes coming from the user-provided YAML files into valid # CloudFormation attributes that can then be used in the template. This # class provides an easy-to-extend DSL that allows for default attributes # specifying custom attributes. class BaseMapper # The list of attributes that are common to all resources that need to be # handles separately. COMMON_ATTRIBUTES = Resource::COMMON_ATTRIBUTES.values class << self # Defines a custom attribute. The given block will receive the # user-provided value for the attribute. The block should return a hash # where the keys are valid humidifier properties and the values are # valid values for those properties. In the below example, we specify # the group attribute which maps to the groups attribute after some # transformation. # # attribute :group do |group| # groups = GROUPS[group] # groups.any? ? { groups: GROUPS[group] } : {} # end def attribute(name, &block) define_method(:"attribute_#{name}", &block) attribute_methods << name end # The names of the custom attribute methods. def attribute_methods @attribute_methods ||= [] end # Defines the default attributes that should be applied to all resources # of this type. The given block will be passed the logical resource # name that the user specified for the resource. The block should return # a hash where the keys are valid humidifier properties and the values # are valid values for those properties. In the example below, the # user_name property is set based on the logical name. # # defaults do |name| # { user_name: name } # end def defaults(&block) define_method(:attribute_defaults, &block) end end # Builds a humidifier resource using the given humidifier resource class, # the logical name for the resource, and the user-specified attributes. def resource_for(clazz, name, attributes) mapped = respond_to?(:attribute_defaults) ? attribute_defaults(name) : {} attributes.each do |key, value| mapped.merge!(mapped_from(clazz, key, value)) end common_attributes = common_attributes_from(mapped) resource = clazz.new(mapped) resource.update_attributes(common_attributes) resource end private def common_attributes_from(mapped) COMMON_ATTRIBUTES.each_with_object({}) do |common_attribute, extract| extracted = mapped.delete(common_attribute) extract[common_attribute] = extracted if extracted end end def mapped_from(clazz, key, value) # rubocop:disable Metrics/MethodLength if self.class.attribute_methods.include?(key.to_sym) public_send(:"attribute_#{key}", value) elsif clazz.prop?(key) { key.to_sym => value } elsif clazz.prop?("#{key}_id") { :"#{key}_id" => Humidifier.ref(value) } elsif COMMON_ATTRIBUTES.include?(key.to_sym) { key.to_sym => value } else raise Error, "Invalid attribute: #{key}" end end end end end