cloud-templates 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +29 -0
- data/.simplecov +6 -0
- data/Gemfile +2 -0
- data/LICENSE +201 -0
- data/NOTICE +13 -0
- data/README.md +124 -0
- data/Rakefile +27 -0
- data/cloud-templates.gemspec +27 -0
- data/examples/lib/user_directory/artifacts/catalogized.rb +11 -0
- data/examples/lib/user_directory/artifacts/group.rb +37 -0
- data/examples/lib/user_directory/artifacts/ided.rb +11 -0
- data/examples/lib/user_directory/artifacts/organization.rb +17 -0
- data/examples/lib/user_directory/artifacts/pathed.rb +22 -0
- data/examples/lib/user_directory/artifacts/person.rb +20 -0
- data/examples/lib/user_directory/artifacts/team.rb +31 -0
- data/examples/lib/user_directory/artifacts/unit.rb +24 -0
- data/examples/lib/user_directory/artifacts/user.rb +29 -0
- data/examples/lib/user_directory/render/etc/artifact_view.rb +15 -0
- data/examples/lib/user_directory/render/etc/composite_view.rb +26 -0
- data/examples/lib/user_directory/render/etc/group_view.rb +23 -0
- data/examples/lib/user_directory/render/etc/person_view.rb +19 -0
- data/examples/lib/user_directory/render/etc/registry.rb +33 -0
- data/examples/lib/user_directory/render/etc/user_view.rb +35 -0
- data/examples/lib/user_directory/render/etc.rb +3 -0
- data/examples/lib/user_directory/render/ldap/artifact_view.rb +27 -0
- data/examples/lib/user_directory/render/ldap/composite_view.rb +32 -0
- data/examples/lib/user_directory/render/ldap/group_view.rb +28 -0
- data/examples/lib/user_directory/render/ldap/organization_view.rb +26 -0
- data/examples/lib/user_directory/render/ldap/person_view.rb +39 -0
- data/examples/lib/user_directory/render/ldap/registry.rb +16 -0
- data/examples/lib/user_directory/render/ldap/unit_view.rb +26 -0
- data/examples/lib/user_directory/render/ldap/user_view.rb +39 -0
- data/examples/lib/user_directory/render/ldap.rb +3 -0
- data/examples/lib/user_directory/utils.rb +18 -0
- data/examples/lib/user_directory.rb +23 -0
- data/examples/lib_path.rb +2 -0
- data/examples/spec/spec_helper.rb +1 -0
- data/examples/spec/user_directory_spec.rb +568 -0
- data/lib/aws/templates/artifact.rb +140 -0
- data/lib/aws/templates/composite.rb +178 -0
- data/lib/aws/templates/exceptions.rb +221 -0
- data/lib/aws/templates/render/registry.rb +60 -0
- data/lib/aws/templates/render/utils/base_type_views.rb +131 -0
- data/lib/aws/templates/render/view.rb +127 -0
- data/lib/aws/templates/render.rb +72 -0
- data/lib/aws/templates/utils/artifact_storage.rb +141 -0
- data/lib/aws/templates/utils/contextualized/filters.rb +437 -0
- data/lib/aws/templates/utils/contextualized/hash.rb +13 -0
- data/lib/aws/templates/utils/contextualized/nil.rb +13 -0
- data/lib/aws/templates/utils/contextualized/proc.rb +13 -0
- data/lib/aws/templates/utils/contextualized.rb +113 -0
- data/lib/aws/templates/utils/default.rb +185 -0
- data/lib/aws/templates/utils/dependency/enumerable.rb +13 -0
- data/lib/aws/templates/utils/dependency/object.rb +46 -0
- data/lib/aws/templates/utils/dependency.rb +121 -0
- data/lib/aws/templates/utils/dependent.rb +28 -0
- data/lib/aws/templates/utils/inheritable.rb +52 -0
- data/lib/aws/templates/utils/late_bound.rb +89 -0
- data/lib/aws/templates/utils/memoized.rb +27 -0
- data/lib/aws/templates/utils/named.rb +19 -0
- data/lib/aws/templates/utils/options.rb +279 -0
- data/lib/aws/templates/utils/parametrized/constraints.rb +423 -0
- data/lib/aws/templates/utils/parametrized/getters.rb +293 -0
- data/lib/aws/templates/utils/parametrized/guarded.rb +32 -0
- data/lib/aws/templates/utils/parametrized/mapper.rb +73 -0
- data/lib/aws/templates/utils/parametrized/nested.rb +72 -0
- data/lib/aws/templates/utils/parametrized/transformations.rb +660 -0
- data/lib/aws/templates/utils/parametrized.rb +240 -0
- data/lib/aws/templates/utils.rb +219 -0
- data/lib/aws/templates.rb +16 -0
- data/spec/aws/templates/artifact_spec.rb +161 -0
- data/spec/aws/templates/composite_spec.rb +361 -0
- data/spec/aws/templates/render/utils/base_type_views_spec.rb +104 -0
- data/spec/aws/templates/render_spec.rb +62 -0
- data/spec/aws/templates/utils/as_named_spec.rb +31 -0
- data/spec/aws/templates/utils/contextualized/filters_spec.rb +108 -0
- data/spec/aws/templates/utils/contextualized_spec.rb +115 -0
- data/spec/aws/templates/utils/late_bound_spec.rb +52 -0
- data/spec/aws/templates/utils/options_spec.rb +67 -0
- data/spec/aws/templates/utils/parametrized/constraint_spec.rb +175 -0
- data/spec/aws/templates/utils/parametrized/getters_spec.rb +139 -0
- data/spec/aws/templates/utils/parametrized/transformation_spec.rb +314 -0
- data/spec/aws/templates/utils/parametrized_spec.rb +241 -0
- data/spec/spec_helper.rb +6 -0
- metadata +244 -0
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'aws/templates/utils'
|
2
|
+
require 'aws/templates/utils/options'
|
3
|
+
require 'aws/templates/utils/inheritable'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module Templates
|
7
|
+
module Utils
|
8
|
+
##
|
9
|
+
# Default mixin.
|
10
|
+
#
|
11
|
+
# It implements class instance-based definitions of so-called
|
12
|
+
# defaults. Defaults are input hash alterations and transformations
|
13
|
+
# which are defined per-class basis and applied according to class
|
14
|
+
# hierarchy when invoked. The target mixing entity should be either
|
15
|
+
# Module or Class. In the former case it's possible to model set of
|
16
|
+
# object which have common traits organized as an arbitrary graph
|
17
|
+
# with many-to-many relationship.
|
18
|
+
module Default
|
19
|
+
include Inheritable
|
20
|
+
|
21
|
+
##
|
22
|
+
# Hash wrapper
|
23
|
+
#
|
24
|
+
# The hash wrapper does intermediate calculations of nested lambdas in the specified
|
25
|
+
# context as they are encountered
|
26
|
+
class Definition
|
27
|
+
##
|
28
|
+
# Defined hash keys
|
29
|
+
def keys
|
30
|
+
@hash.keys
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Transform to hash
|
35
|
+
def to_hash
|
36
|
+
_recurse_into(@hash)
|
37
|
+
end
|
38
|
+
|
39
|
+
def dependency?
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
def dependencies
|
44
|
+
to_hash.dependencies
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Index operator
|
49
|
+
#
|
50
|
+
# Performs intermediate transformation of value if needed (if value is a lambda) and
|
51
|
+
# returns it wrapping into Definition instance with the same context if needed
|
52
|
+
# (if value is a map)
|
53
|
+
def [](k)
|
54
|
+
result = _process_value(@hash[k])
|
55
|
+
result.respond_to?(:to_hash) ? self.class.new(result, @context) : result
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Check if the key is present in the hash
|
60
|
+
def include?(k)
|
61
|
+
@hash.include?(k)
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Create wrapper object
|
66
|
+
#
|
67
|
+
# Creates wrapper object with attached hash and context to evaluate lambdas in
|
68
|
+
def initialize(hsh, ctx)
|
69
|
+
@hash = hsh
|
70
|
+
@context = ctx
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def _process_value(value)
|
76
|
+
if value.respond_to?(:to_hash)
|
77
|
+
value
|
78
|
+
elsif value.respond_to?(:to_proc)
|
79
|
+
@context.instance_eval(&value)
|
80
|
+
else
|
81
|
+
value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def _recurse_into(value)
|
86
|
+
value.each_with_object({}) do |(k, v), memo|
|
87
|
+
processed = _process_value(v)
|
88
|
+
processed = _recurse_into(processed.to_hash) if Utils.hashable?(processed)
|
89
|
+
memo[k] = processed
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
instance_scope do
|
95
|
+
##
|
96
|
+
# Apply specified defaults to options
|
97
|
+
#
|
98
|
+
# It's a mixin method which depends on presence of options accessor
|
99
|
+
# methods in the consuming class. The options property should contain
|
100
|
+
# an object implementing to_hash method. The method is mutating for
|
101
|
+
# options. The algorithm is to walk down the hierarchy of the
|
102
|
+
# class and collect and merge all defaults from its ancestors
|
103
|
+
# prioritizing the ones made later in the class hierarchy. The method
|
104
|
+
# is working correctly with both parent classes and all Default
|
105
|
+
# mixins used in between.
|
106
|
+
def process_options(params = nil)
|
107
|
+
# iterating through all ancestors with defaults
|
108
|
+
ancestors_with_defaults.reverse_each do |mod|
|
109
|
+
# ... through all defaults of particular ancestor
|
110
|
+
mod.defaults.each do |defaults_definition|
|
111
|
+
# merge the default definition with options
|
112
|
+
options.merge!(Definition.new(defaults_definition, self))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# re-inforce caller-specified overrides
|
117
|
+
options.merge!(params) if params
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def ancestors_with_defaults
|
123
|
+
self
|
124
|
+
.class
|
125
|
+
.ancestors
|
126
|
+
.select do |mod|
|
127
|
+
(mod != Default) && mod.ancestors.include?(Default)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Class-level mixins
|
134
|
+
#
|
135
|
+
# It's a DSL extension to declaratively define defaults
|
136
|
+
class_scope do
|
137
|
+
##
|
138
|
+
# Defaults for the input hash
|
139
|
+
#
|
140
|
+
# Class-level accessor of a hash which will be merged into input
|
141
|
+
# parameters hash. The hash can't be changed directly or set to
|
142
|
+
# another value. Only incremental changes are allowed with
|
143
|
+
# default method which is a part of the framework DSL. The method
|
144
|
+
# returns only defaults for the current class without
|
145
|
+
# consideration of the class hierarchy.
|
146
|
+
def defaults
|
147
|
+
@defaults ||= []
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# Put an default/calculation for the input hash
|
152
|
+
#
|
153
|
+
# The class method is the main knob which is used to build
|
154
|
+
# hierarchical hash mutation pipeline using language-provided
|
155
|
+
# features such as class inheritance and introspection. You can
|
156
|
+
# specify either hash (or an object which has :to_hash method) or
|
157
|
+
# a lambda/Proc as a parameter.
|
158
|
+
#
|
159
|
+
# If you specify a hash then it will be merged with the current
|
160
|
+
# value of default where the hash passed will take preference
|
161
|
+
# during the merge.
|
162
|
+
#
|
163
|
+
# If you specify a lambda it will be added to calculations stack
|
164
|
+
#
|
165
|
+
# If the parameter you passed is neither a hash nor callable or
|
166
|
+
# no parameters are passed at all, ArgumentError will be thrown.
|
167
|
+
def default(defaults_hash = nil)
|
168
|
+
raise_defaults_is_nil unless defaults_hash
|
169
|
+
raise_default_type_mismatch(defaults_hash) unless defaults_hash.respond_to?(:to_hash)
|
170
|
+
|
171
|
+
defaults << defaults_hash.to_hash
|
172
|
+
end
|
173
|
+
|
174
|
+
def raise_defaults_is_nil
|
175
|
+
raise ArgumentError.new('Map should be specified')
|
176
|
+
end
|
177
|
+
|
178
|
+
def raise_default_type_mismatch(defaults_hash)
|
179
|
+
raise ArgumentError.new("#{defaults_hash.inspect} is not a hash")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'aws/templates/utils/dependency'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Dependency method stubs
|
6
|
+
#
|
7
|
+
# To avoid checking classes directly to filter out dependencies and non-dependencies, we're
|
8
|
+
# monkey-patching Object class with stubs for Dependency class.
|
9
|
+
#
|
10
|
+
# TODO: Devise a better approach and remove the extension
|
11
|
+
class Object
|
12
|
+
EMPTY_SET = Set.new.freeze
|
13
|
+
|
14
|
+
# By default an object is not a dependency
|
15
|
+
def dependency?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
# It returns self
|
20
|
+
def object
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Object root
|
26
|
+
#
|
27
|
+
# It is used to gracefully process dependencies
|
28
|
+
def root; end
|
29
|
+
|
30
|
+
alias not_a_dependency object
|
31
|
+
|
32
|
+
# it returns a set containing a single dependency on itself
|
33
|
+
def dependencies
|
34
|
+
EMPTY_SET
|
35
|
+
end
|
36
|
+
|
37
|
+
# mark the object as dependency
|
38
|
+
def as_a_dependency
|
39
|
+
Aws::Templates::Utils::Dependency.new(object)
|
40
|
+
end
|
41
|
+
|
42
|
+
# mark the object as dependency of itself
|
43
|
+
def as_a_self_dependency
|
44
|
+
as_a_dependency.to_self
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'aws/templates/utils/dependency/object'
|
3
|
+
require 'aws/templates/utils/dependency/enumerable'
|
4
|
+
|
5
|
+
module Aws
|
6
|
+
module Templates
|
7
|
+
module Utils
|
8
|
+
##
|
9
|
+
# Dependency marker proxy
|
10
|
+
#
|
11
|
+
# Used internally in the framework to mark an object as potential dependency. There are other
|
12
|
+
# alternatives for doing the same like singleton class and reference object. There are a few
|
13
|
+
# advantages of the approach taken:
|
14
|
+
# * Dependency can be used whereever original object is expected
|
15
|
+
# * Dependecy can be applied case-by-case basis whereas singleton is attached to the object
|
16
|
+
# itself
|
17
|
+
class Dependency < BasicObject
|
18
|
+
##
|
19
|
+
# Equality
|
20
|
+
#
|
21
|
+
# Two Dependency objects are equal if it's the same object or if they are pointing to the
|
22
|
+
# same target.
|
23
|
+
def eql?(other)
|
24
|
+
equal?(other) || ((self.class == other.class) && (object == other.object))
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Alias for #eql?
|
29
|
+
def ==(other)
|
30
|
+
eql?(other)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Non-equality
|
34
|
+
def !=(other)
|
35
|
+
!eql?(other)
|
36
|
+
end
|
37
|
+
|
38
|
+
# BasicObject is so basic that this part is missing too
|
39
|
+
def class
|
40
|
+
Dependency
|
41
|
+
end
|
42
|
+
|
43
|
+
# It's a dependency
|
44
|
+
def dependency?
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
# mark the object as dependency
|
49
|
+
def as_dependency
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_reader :object
|
54
|
+
attr_reader :dependencies
|
55
|
+
|
56
|
+
##
|
57
|
+
# Redirect every method call to the proxied object if the object supports it
|
58
|
+
def method_missing(name, *args, &block)
|
59
|
+
object.respond_to?(name) ? object.send(name, *args, &block) : super
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# It supports every method proxied object supports
|
64
|
+
def respond_to_missing?(name, include_private = false)
|
65
|
+
object.respond_to?(name, include_private) || super(name, include_private)
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Add dependency
|
70
|
+
#
|
71
|
+
# Add a link to the target to the current Dependency object
|
72
|
+
def to(target)
|
73
|
+
if target.dependency?
|
74
|
+
dependencies.merge(target.dependencies)
|
75
|
+
else
|
76
|
+
dependencies << target
|
77
|
+
end
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Link the value to the source
|
84
|
+
#
|
85
|
+
# Links source or result of calculation of the block to the target object of the dependency.
|
86
|
+
# The mecahanism is a middle ground between extreme case of indefinite recursive dependency
|
87
|
+
# propagation and no propagation at all
|
88
|
+
#
|
89
|
+
# some_artifact.as_a_dependency.with { some_attribute }
|
90
|
+
# # => Dependency(@object = <some_attribute value>, <link to some_artifact>)
|
91
|
+
def with(source = nil, &source_calculation_block)
|
92
|
+
value = if source_calculation_block.nil?
|
93
|
+
source
|
94
|
+
else
|
95
|
+
object.instance_exec(value, &source_calculation_block)
|
96
|
+
end
|
97
|
+
|
98
|
+
value.as_a_dependency.to(self)
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Set dependency to the target
|
103
|
+
def to_self
|
104
|
+
to(object)
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Initialize the proxy
|
109
|
+
def initialize(source_object)
|
110
|
+
@object = source_object.object
|
111
|
+
|
112
|
+
@dependencies = if source_object.dependency?
|
113
|
+
source_object.dependencies.dup
|
114
|
+
else
|
115
|
+
::Set.new
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'aws/templates/utils/dependency/object'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Aws
|
5
|
+
module Templates
|
6
|
+
module Utils
|
7
|
+
##
|
8
|
+
# Dependency node mixin
|
9
|
+
#
|
10
|
+
# Introduces methods needed to track dependencies of an object. The object needs to implement
|
11
|
+
# options method and root method.
|
12
|
+
module Dependent
|
13
|
+
##
|
14
|
+
# Introduce dependencies manually
|
15
|
+
#
|
16
|
+
# Dependencies are calculated from "options" recursive structure by traversal and location
|
17
|
+
# of all dependencies automatically. If some dependency is not logical/parametrical but
|
18
|
+
# purely chronological, it can be introduced into the dependency list with this method.
|
19
|
+
def depends_on(*depends)
|
20
|
+
new_dependencies = depends.dependencies
|
21
|
+
new_dependencies.select! { |obj| obj.root == root } unless root.nil?
|
22
|
+
dependencies.merge(new_dependencies)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Aws
|
2
|
+
module Templates
|
3
|
+
module Utils
|
4
|
+
##
|
5
|
+
# Introduces class method inheritance through module hierarchy
|
6
|
+
module Inheritable
|
7
|
+
##
|
8
|
+
# Core class-level mixins
|
9
|
+
#
|
10
|
+
# Contains core logic of the inheritance feature. This module is used as extention
|
11
|
+
# in every including module/class to expose appropriate module-level primitives for
|
12
|
+
# handling inheritance of class-scope methods.
|
13
|
+
module ClassMethods
|
14
|
+
DEFAULT_MODULE = Module.new.freeze
|
15
|
+
|
16
|
+
##
|
17
|
+
# To add class methods also while including the module
|
18
|
+
def included(base)
|
19
|
+
super(base)
|
20
|
+
base.extend(Inheritable::ClassMethods)
|
21
|
+
base._merge_class_scope(class_scope || DEFAULT_MODULE)
|
22
|
+
end
|
23
|
+
|
24
|
+
def instance_scope(&blk)
|
25
|
+
module_eval(&blk)
|
26
|
+
end
|
27
|
+
|
28
|
+
def class_scope(&blk)
|
29
|
+
if blk
|
30
|
+
@class_scope.module_eval(&blk)
|
31
|
+
extend @class_scope
|
32
|
+
end
|
33
|
+
|
34
|
+
@class_scope
|
35
|
+
end
|
36
|
+
|
37
|
+
def _merge_class_scope(mod)
|
38
|
+
if @class_scope.nil?
|
39
|
+
@class_scope = mod.dup
|
40
|
+
else
|
41
|
+
@class_scope.include(mod)
|
42
|
+
end
|
43
|
+
|
44
|
+
extend @class_scope
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
extend ClassMethods
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'aws/templates/utils/inheritable'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module Templates
|
5
|
+
module Utils
|
6
|
+
##
|
7
|
+
# Late binding utilities
|
8
|
+
#
|
9
|
+
# Late binding is a technique of referencing values which don't exist at the template
|
10
|
+
# calculation stage. Examples could be Process ID, SQL record calculated ID or AWS object
|
11
|
+
# ARN you're creating through a script or CFN template.
|
12
|
+
#
|
13
|
+
# The module provides DSL for creating late binding points known as References.
|
14
|
+
module LateBound
|
15
|
+
include Inheritable
|
16
|
+
|
17
|
+
##
|
18
|
+
# Reference
|
19
|
+
#
|
20
|
+
# Reference is a special placeholder object designed to point to the object reference was
|
21
|
+
# created for with optional path and args attached.
|
22
|
+
#
|
23
|
+
# References are used when the final value of an object property is unknown at the template
|
24
|
+
# calculation stage and can be extracted only when the final rendered view is submitted to
|
25
|
+
# the target system (late binding)
|
26
|
+
class Reference
|
27
|
+
attr_reader :instance
|
28
|
+
attr_reader :path
|
29
|
+
attr_reader :arguments
|
30
|
+
|
31
|
+
FAILURE_MESSAGES = {
|
32
|
+
to_s: 'string',
|
33
|
+
to_i: 'integer',
|
34
|
+
to_f: 'float',
|
35
|
+
to_a: 'array',
|
36
|
+
to_h: 'hash',
|
37
|
+
to_str: 'string',
|
38
|
+
to_int: 'integer',
|
39
|
+
to_ary: 'array',
|
40
|
+
to_hash: 'hash',
|
41
|
+
to_proc: 'proc'
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
FAILURE_MESSAGES.each_pair do |method_name, type_name|
|
45
|
+
define_method(method_name) do
|
46
|
+
raise(
|
47
|
+
"Reference can't be transformed to #{type_name} or paricipate in any operations" \
|
48
|
+
'References are placeholders for values which don\'t exist at the template ' \
|
49
|
+
'calculation stage (late binding)'
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize(target_instance, target_path = nil, args = nil)
|
55
|
+
@instance = target_instance
|
56
|
+
@path = target_path
|
57
|
+
@arguments = args
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
instance_scope do
|
62
|
+
##
|
63
|
+
# Create reference
|
64
|
+
#
|
65
|
+
# Create and return Reference object attached to the current instance with specified path
|
66
|
+
# and arguments
|
67
|
+
def reference(path = nil, *args)
|
68
|
+
Reference.new(self, path, args)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Class-level DSL
|
74
|
+
class_scope do
|
75
|
+
##
|
76
|
+
# Wrap reference for postponed instantiation
|
77
|
+
#
|
78
|
+
# References are instance-level objects so they can be attached only to an instance, not
|
79
|
+
# to a class. So, to be able to do that in "default" section in an artifact, for instance,
|
80
|
+
# you need to specify a proc/lambda object for the option. This method makes the wrappin
|
81
|
+
# unnecessary.
|
82
|
+
def reference(path = nil, *args)
|
83
|
+
-> { reference(path, *args) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Aws
|
2
|
+
module Templates
|
3
|
+
module Utils
|
4
|
+
##
|
5
|
+
# Simple memoization facility
|
6
|
+
module Memoized
|
7
|
+
# Cancel all memoizations
|
8
|
+
def dirty!
|
9
|
+
@memoized = nil
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Memoize block result
|
15
|
+
#
|
16
|
+
# Return memoized value with the ID. If slot is empty - call the block
|
17
|
+
def memoize(id)
|
18
|
+
memoized[id] ||= yield
|
19
|
+
end
|
20
|
+
|
21
|
+
def memoized
|
22
|
+
@memoized ||= {}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'aws/templates/utils/parametrized'
|
2
|
+
require 'aws/templates/utils/parametrized/constraints'
|
3
|
+
|
4
|
+
module Aws
|
5
|
+
module Templates
|
6
|
+
module Utils
|
7
|
+
##
|
8
|
+
# Named parametrized object mixin
|
9
|
+
#
|
10
|
+
# Provides a simple utility to define artifacts/objects which have
|
11
|
+
# "name" parameter which should be present as :name in the input hash
|
12
|
+
module AsNamed
|
13
|
+
include Parametrized
|
14
|
+
|
15
|
+
parameter :name, description: 'Name of the object', constraint: not_nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|