lib/cfer/core/resource.rb
module Cfer::Core
class Resource < Cfer::BlockHash
include Cfer::Core::Hooks
class Handle
attr_reader :name
def initialize(name)
@name = name.to_s
end
def ref
Functions::Fn::ref(name)
end
def method_missing(method)
Functions::Fn::get_att(name, method.to_s.camelize)
end
end
@@types = {}
attr_reader :stack
def initialize(name, type, stack, options, &block)
@name = name
@stack = stack
self[:Type] = type
self.merge!(options)
self[:Properties] = HashWithIndifferentAccess.new
build_from_block(&block)
end
def handle
@handle ||= Handle.new(@name)
end
# Sets a tag on this resource. The resource must support the CloudFormation `Tags` property.
# @param k [String] The name of the tag to set
# @param v [String] The value for this tag
# @param options [Hash] An arbitrary set of additional properties to be added to this tag, for example `PropagateOnLaunch` on `AWS::AutoScaling::AutoScalingGroup`
def tag(k, v, **options)
self[:Properties][:Tags] ||= []
self[:Properties][:Tags].delete_if { |kv| kv["Key"] == k }
self[:Properties][:Tags].unshift({"Key" => k, "Value" => v}.merge(options))
end
# Directly sets raw properties in the underlying CloudFormation structure.
# @param keyvals [Hash] The properties to set on this object.
def properties(keyvals = {})
self[:Properties].merge!(keyvals)
end
# Gets the current value of a given property
# @param key [String] The name of the property to fetch
def get_property(key)
self[:Properties].fetch key
end
class << self
# Fetches the DSL class for a CloudFormation resource type
# @param type [String] The type of resource, for example `AWS::EC2::Instance`
# @return [Class] The DSL class representing this resource type, including all extensions
def resource_class(type)
@@types[type] ||= "CferExt::#{type}".split('::').inject(Object) { |o, c| o.const_get c if o && o.const_defined?(c) } || Class.new(Cfer::Core::Resource)
end
# Patches code into DSL classes for CloudFormation resources
# @param type [String] The type of resource, for example `AWS::EC2::Instance`
def extend_resource(type, &block)
resource_class(type).class_eval(&block)
end
# Registers a hook that will be run before properties are set on a resource
# @param type [String] The type of resource, for example `AWS::EC2::Instance`
def before(type, **options, &block)
resource_class(type).pre_hooks << options.merge(block: block)
end
# Registers a hook that will be run after properties have been set on a resource
# @param type [String] The type of resource, for example `AWS::EC2::Instance`
def after(type, **options, &block)
resource_class(type).post_hooks << options.merge(block: block)
end
end
end
end