cloud-templates 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|