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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +29 -0
  3. data/.simplecov +6 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE +201 -0
  6. data/NOTICE +13 -0
  7. data/README.md +124 -0
  8. data/Rakefile +27 -0
  9. data/cloud-templates.gemspec +27 -0
  10. data/examples/lib/user_directory/artifacts/catalogized.rb +11 -0
  11. data/examples/lib/user_directory/artifacts/group.rb +37 -0
  12. data/examples/lib/user_directory/artifacts/ided.rb +11 -0
  13. data/examples/lib/user_directory/artifacts/organization.rb +17 -0
  14. data/examples/lib/user_directory/artifacts/pathed.rb +22 -0
  15. data/examples/lib/user_directory/artifacts/person.rb +20 -0
  16. data/examples/lib/user_directory/artifacts/team.rb +31 -0
  17. data/examples/lib/user_directory/artifacts/unit.rb +24 -0
  18. data/examples/lib/user_directory/artifacts/user.rb +29 -0
  19. data/examples/lib/user_directory/render/etc/artifact_view.rb +15 -0
  20. data/examples/lib/user_directory/render/etc/composite_view.rb +26 -0
  21. data/examples/lib/user_directory/render/etc/group_view.rb +23 -0
  22. data/examples/lib/user_directory/render/etc/person_view.rb +19 -0
  23. data/examples/lib/user_directory/render/etc/registry.rb +33 -0
  24. data/examples/lib/user_directory/render/etc/user_view.rb +35 -0
  25. data/examples/lib/user_directory/render/etc.rb +3 -0
  26. data/examples/lib/user_directory/render/ldap/artifact_view.rb +27 -0
  27. data/examples/lib/user_directory/render/ldap/composite_view.rb +32 -0
  28. data/examples/lib/user_directory/render/ldap/group_view.rb +28 -0
  29. data/examples/lib/user_directory/render/ldap/organization_view.rb +26 -0
  30. data/examples/lib/user_directory/render/ldap/person_view.rb +39 -0
  31. data/examples/lib/user_directory/render/ldap/registry.rb +16 -0
  32. data/examples/lib/user_directory/render/ldap/unit_view.rb +26 -0
  33. data/examples/lib/user_directory/render/ldap/user_view.rb +39 -0
  34. data/examples/lib/user_directory/render/ldap.rb +3 -0
  35. data/examples/lib/user_directory/utils.rb +18 -0
  36. data/examples/lib/user_directory.rb +23 -0
  37. data/examples/lib_path.rb +2 -0
  38. data/examples/spec/spec_helper.rb +1 -0
  39. data/examples/spec/user_directory_spec.rb +568 -0
  40. data/lib/aws/templates/artifact.rb +140 -0
  41. data/lib/aws/templates/composite.rb +178 -0
  42. data/lib/aws/templates/exceptions.rb +221 -0
  43. data/lib/aws/templates/render/registry.rb +60 -0
  44. data/lib/aws/templates/render/utils/base_type_views.rb +131 -0
  45. data/lib/aws/templates/render/view.rb +127 -0
  46. data/lib/aws/templates/render.rb +72 -0
  47. data/lib/aws/templates/utils/artifact_storage.rb +141 -0
  48. data/lib/aws/templates/utils/contextualized/filters.rb +437 -0
  49. data/lib/aws/templates/utils/contextualized/hash.rb +13 -0
  50. data/lib/aws/templates/utils/contextualized/nil.rb +13 -0
  51. data/lib/aws/templates/utils/contextualized/proc.rb +13 -0
  52. data/lib/aws/templates/utils/contextualized.rb +113 -0
  53. data/lib/aws/templates/utils/default.rb +185 -0
  54. data/lib/aws/templates/utils/dependency/enumerable.rb +13 -0
  55. data/lib/aws/templates/utils/dependency/object.rb +46 -0
  56. data/lib/aws/templates/utils/dependency.rb +121 -0
  57. data/lib/aws/templates/utils/dependent.rb +28 -0
  58. data/lib/aws/templates/utils/inheritable.rb +52 -0
  59. data/lib/aws/templates/utils/late_bound.rb +89 -0
  60. data/lib/aws/templates/utils/memoized.rb +27 -0
  61. data/lib/aws/templates/utils/named.rb +19 -0
  62. data/lib/aws/templates/utils/options.rb +279 -0
  63. data/lib/aws/templates/utils/parametrized/constraints.rb +423 -0
  64. data/lib/aws/templates/utils/parametrized/getters.rb +293 -0
  65. data/lib/aws/templates/utils/parametrized/guarded.rb +32 -0
  66. data/lib/aws/templates/utils/parametrized/mapper.rb +73 -0
  67. data/lib/aws/templates/utils/parametrized/nested.rb +72 -0
  68. data/lib/aws/templates/utils/parametrized/transformations.rb +660 -0
  69. data/lib/aws/templates/utils/parametrized.rb +240 -0
  70. data/lib/aws/templates/utils.rb +219 -0
  71. data/lib/aws/templates.rb +16 -0
  72. data/spec/aws/templates/artifact_spec.rb +161 -0
  73. data/spec/aws/templates/composite_spec.rb +361 -0
  74. data/spec/aws/templates/render/utils/base_type_views_spec.rb +104 -0
  75. data/spec/aws/templates/render_spec.rb +62 -0
  76. data/spec/aws/templates/utils/as_named_spec.rb +31 -0
  77. data/spec/aws/templates/utils/contextualized/filters_spec.rb +108 -0
  78. data/spec/aws/templates/utils/contextualized_spec.rb +115 -0
  79. data/spec/aws/templates/utils/late_bound_spec.rb +52 -0
  80. data/spec/aws/templates/utils/options_spec.rb +67 -0
  81. data/spec/aws/templates/utils/parametrized/constraint_spec.rb +175 -0
  82. data/spec/aws/templates/utils/parametrized/getters_spec.rb +139 -0
  83. data/spec/aws/templates/utils/parametrized/transformation_spec.rb +314 -0
  84. data/spec/aws/templates/utils/parametrized_spec.rb +241 -0
  85. data/spec/spec_helper.rb +6 -0
  86. metadata +244 -0
@@ -0,0 +1,293 @@
1
+ require 'aws/templates/exceptions'
2
+ require 'aws/templates/utils/parametrized'
3
+ require 'singleton'
4
+
5
+ module Aws
6
+ module Templates
7
+ module Utils
8
+ module Parametrized #:nodoc:
9
+ ##
10
+ # Getter functor class
11
+ #
12
+ # A getter is a Proc without parameters and it is expected to return
13
+ # a value. Since the proc is to be executed in instance context
14
+ # the value can be calculated based on other methods or extracted from
15
+ # options attrribute
16
+ #
17
+ # The class implements functor pattern through to_proc method and
18
+ # closure. Essentially, all getters can be used everywhere where
19
+ # a block is expected.
20
+ #
21
+ # It provides protected method get which should be overriden in
22
+ # all concrete getter classes.
23
+ class Getter
24
+ ##
25
+ # Get parameter from instance variables as is
26
+ #
27
+ # Gets value from instance variable by parameter's name without
28
+ # any other operations performed.
29
+ #
30
+ # === Example
31
+ #
32
+ # class Piece
33
+ # include Aws::Templates::Utils::Parametrized
34
+ #
35
+ # parameter :param1, getter: as_instance_variable
36
+ #
37
+ # def initialize(x)
38
+ # @param1 = x
39
+ # end
40
+ # end
41
+ #
42
+ # i = Piece.new(3)
43
+ # i.param1 # => 3
44
+ class AsInstanceVariable < Getter
45
+ include Singleton
46
+
47
+ protected
48
+
49
+ def get(parameter, instance)
50
+ instance.instance_variable_get("@#{parameter.name}")
51
+ end
52
+ end
53
+
54
+ ##
55
+ # Get options value "as is"
56
+ #
57
+ # Gets value from options attribute by parameter's name without
58
+ # any other operations performed.
59
+ #
60
+ # === Example
61
+ #
62
+ # class Piece
63
+ # include Aws::Templates::Utils::Parametrized
64
+ #
65
+ # parameter :param1, :getter => as_is
66
+ # end
67
+ #
68
+ # i = Piece.new(:param1 => 3)
69
+ # i.param1 # => 3
70
+ class AsIs < Getter
71
+ include Singleton
72
+
73
+ protected
74
+
75
+ def get(parameter, instance)
76
+ instance.options[parameter.name]
77
+ end
78
+ end
79
+
80
+ ##
81
+ # Lookup value in options by path
82
+ #
83
+ # Looks up value from options attribute by specified path. The path
84
+ # can be either statically specified or a block can be provided.
85
+ # The block shouldn't have parameters and should return an array
86
+ # containing path. The block will be executed in the instance context.
87
+ #
88
+ # === Example
89
+ #
90
+ # class Piece
91
+ # include Aws::Templates::Utils::Parametrized
92
+ #
93
+ # parameter :param1, :getter => path(:a, :b)
94
+ # end
95
+ #
96
+ # i = Piece.new(:a => { :b => 3 })
97
+ # i.param1 # => 3
98
+ class Path < Getter
99
+ attr_reader :path
100
+
101
+ def initialize(path)
102
+ unless path.respond_to?(:to_proc) || path.respond_to?(:to_a)
103
+ raise ArgumentError.new(
104
+ "Path can be either array or Proc: #{path.inspect}"
105
+ )
106
+ end
107
+
108
+ @path = path
109
+ end
110
+
111
+ protected
112
+
113
+ def get(_, instance)
114
+ if path.respond_to?(:to_proc)
115
+ instance.options[*instance.instance_eval(&path)]
116
+ elsif path.respond_to?(:to_a)
117
+ instance.options[*path]
118
+ end
119
+ end
120
+ end
121
+
122
+ ##
123
+ # Calculate value
124
+ #
125
+ # If a block is specified, it will be executed in the instance
126
+ # context and return will be used as parameter value. If a value
127
+ # specified then it will be used as parameter value instead.
128
+ #
129
+ # === Example
130
+ #
131
+ # class Piece
132
+ # include Aws::Templates::Utils::Parametrized
133
+ #
134
+ # parameter :param1, :getter => value(1)
135
+ # parameter :param2, :getter => value { options[:z] + 1 }
136
+ # end
137
+ #
138
+ # i = Piece.new(:z => 3)
139
+ # i.param2 # => 4
140
+ # i.param1 # => 1
141
+ class Value < Getter
142
+ attr_reader :calculation
143
+
144
+ def initialize(calculation)
145
+ @calculation = calculation
146
+ end
147
+
148
+ protected
149
+
150
+ def get(_, instance)
151
+ if calculation.respond_to?(:to_hash)
152
+ calculation
153
+ elsif calculation.respond_to?(:to_proc)
154
+ instance.instance_eval(&calculation)
155
+ else
156
+ calculation
157
+ end
158
+ end
159
+ end
160
+
161
+ ##
162
+ # Pick one of non-nil values returned by nested getters
163
+ #
164
+ # In general it plays the same role as || operator in Ruby. It
165
+ # just picks first non-nil value returned by a list of getters
166
+ #
167
+ # === Example
168
+ #
169
+ # class Piece
170
+ # include Aws::Templates::Utils::Parametrized
171
+ #
172
+ # parameter :param1, :getter => one_of(
173
+ # path(:a, :b),
174
+ # path(:b, :c)
175
+ # )
176
+ # end
177
+ #
178
+ # i = Piece.new( :a => { :b => 3 } )
179
+ # i.param1 # => 3
180
+ # i = Piece.new( :b => { :c => 4 } )
181
+ # i.param1 # => 4
182
+ class OneOf < Getter
183
+ attr_reader :getters
184
+
185
+ def initialize(getters)
186
+ @getters = getters
187
+ end
188
+
189
+ protected
190
+
191
+ def get(parameter, instance)
192
+ getters.inject(nil) do |value, g|
193
+ value = instance.instance_exec(parameter, &g)
194
+ break value unless value.nil?
195
+ end
196
+ end
197
+ end
198
+
199
+ ##
200
+ # Creates closure with getter invocation
201
+ #
202
+ # It's an interface method required for Getter to expose
203
+ # functor properties. It encloses invocation of Getter get_wrapper
204
+ # method into a closure. The closure itself is executed in the context
205
+ # of Parametrized instance which provides proper set "self" variable.
206
+ #
207
+ # The closure itself accepts 1 parameters
208
+ # * +parameter+ - the Parameter object which the getter is executed for
209
+ # ...where instance is assumed from self
210
+ def to_proc
211
+ getter = self
212
+
213
+ lambda do |parameter|
214
+ getter.get_wrapper(parameter, self)
215
+ end
216
+ end
217
+
218
+ ##
219
+ # Wraps getter-dependent method
220
+ #
221
+ # It wraps constraint-dependent "get" method into a rescue block
222
+ # to standardize exception type and information provided by failed
223
+ # value calculation
224
+ # * +parameter+ - the Parameter object which the getter is executed for
225
+ # * +instance+ - the instance value is taken from
226
+ def get_wrapper(parameter, instance)
227
+ get(parameter, instance)
228
+ rescue StandardError
229
+ raise NestedParameterException.new(parameter)
230
+ end
231
+
232
+ protected
233
+
234
+ ##
235
+ # Getter method
236
+ #
237
+ # * +parameter+ - the Parameter object which the getter is executed for
238
+ # * +instance+ - the instance value is taken from
239
+ def get(parameter, instance); end
240
+ end
241
+
242
+ ##
243
+ # Syntax sugar for getters definition
244
+ #
245
+ # It injects the methods as class-scope methods into mixing classes.
246
+ # The methods are factories to create particular type of getter
247
+ class_scope do
248
+ ##
249
+ # Get parameter from instance variables as is
250
+ #
251
+ # alias for AsInstanceVariable class
252
+ def as_instance_variable
253
+ Getter::AsInstanceVariable.instance
254
+ end
255
+
256
+ ##
257
+ # Get parameter from Options as is
258
+ #
259
+ # alias for AsIs class
260
+ def as_is
261
+ Getter::AsIs.instance
262
+ end
263
+
264
+ ##
265
+ # Calculate value of parameter
266
+ #
267
+ # alias for Value class
268
+ def value(v = nil, &blk)
269
+ Getter::Value.new(v.nil? ? blk : v)
270
+ end
271
+
272
+ ##
273
+ # Look up value of the parameter with path
274
+ #
275
+ # alias for Path class
276
+ def path(*v, &blk)
277
+ Getter::Path.new(
278
+ v.empty? ? blk : v
279
+ )
280
+ end
281
+
282
+ ##
283
+ # Choose one non-nil value from nested getters
284
+ #
285
+ # alias for OneOf class
286
+ def one_of(*getters)
287
+ Getter::OneOf.new(getters)
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,32 @@
1
+ require 'set'
2
+
3
+ module Aws
4
+ module Templates
5
+ module Utils
6
+ module Parametrized
7
+ ##
8
+ # Remember Alan Turing's halting problem and don't believe in miracles. The method will
9
+ # only work with parameters because they are supposed to be pure unmodifying functions.
10
+ # Hence we can terminate if a parameter method was invoked twice in the stack with the same
11
+ # context.
12
+ module Guarded
13
+ Call = Struct.new(:instance, :parameter)
14
+
15
+ def guarded_get(instance, parameter_object)
16
+ current_call = Call.new(instance, parameter_object)
17
+ return unless trace.add?(current_call)
18
+ ret = parameter_object.get(self)
19
+ trace.delete(current_call)
20
+ ret
21
+ end
22
+
23
+ private
24
+
25
+ def trace
26
+ Thread.current[Guarded.name] ||= Set.new
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,73 @@
1
+ require 'set'
2
+
3
+ module Aws
4
+ module Templates
5
+ module Utils
6
+ module Parametrized
7
+ ##
8
+ # Map from "parametrized" to "recursive"
9
+ #
10
+ # The class is adapter used to wrap any "parametrized" object (implementing "parametrized"
11
+ # concept) into an object implementing "hashable" and "recursive" concepts.
12
+ class Mapper
13
+ attr_reader :delegate
14
+
15
+ SPECIAL_CASE = [:root].freeze
16
+
17
+ def [](key)
18
+ @delegate.public_send(key) if @parameter_names.include?(key)
19
+ end
20
+
21
+ def include?(key)
22
+ @parameter_names.include?(key)
23
+ end
24
+
25
+ def to_hash
26
+ @parameter_names.each_with_object({}) do |method_name, hsh|
27
+ hsh[method_name] = @delegate.public_send(method_name)
28
+ end
29
+ end
30
+
31
+ def keys
32
+ @parameter_names.to_a
33
+ end
34
+
35
+ def dependency?
36
+ delegate.dependency?
37
+ end
38
+
39
+ def dependencies
40
+ delegate.dependencies
41
+ end
42
+
43
+ def object
44
+ delegate.object
45
+ end
46
+
47
+ def initialize(obj)
48
+ obj.parameter_names.each { |pname| _check_parameter(obj, pname) }
49
+ @delegate = obj
50
+ @parameter_names = Set.new(@delegate.parameter_names).merge(SPECIAL_CASE)
51
+ end
52
+
53
+ private
54
+
55
+ PROPERTY_LIKE = /^[^_!?][^!?]*$/
56
+
57
+ def _check_parameter(obj, name)
58
+ _raise_misnamed(obj, name) unless name.to_s =~ PROPERTY_LIKE
59
+ _raise_arity(obj, name) unless obj.public_method(name).arity.zero?
60
+ end
61
+
62
+ def _raise_misnamed(obj, name)
63
+ raise "Parameter #{name} of #{obj} is mis-named"
64
+ end
65
+
66
+ def _raise_arity(obj, name)
67
+ raise "Parameter #{name} of #{obj} has arity"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,72 @@
1
+ require 'set'
2
+ require 'aws/templates/utils/default'
3
+ require 'aws/templates/utils/parametrized'
4
+ require 'aws/templates/utils/parametrized/getters'
5
+ require 'aws/templates/utils/dependent'
6
+ require 'aws/templates/utils/options'
7
+
8
+ module Aws
9
+ module Templates
10
+ module Utils
11
+ module Parametrized
12
+ ##
13
+ # Parametrized wrapper
14
+ #
15
+ # Wraps hash or object into "parametrized" instance. Used for nested parameter definitions.
16
+ class Nested
17
+ include Parametrized
18
+ include Default
19
+ include Dependent
20
+
21
+ attr_reader :options
22
+
23
+ def self.getter
24
+ as_is
25
+ end
26
+
27
+ def self.create_class(scope)
28
+ klass = ::Class.new(self)
29
+ klass.singleton_class.send(:define_method, :scope) { scope }
30
+ klass
31
+ end
32
+
33
+ def self.with(mod)
34
+ include mod
35
+ self
36
+ end
37
+
38
+ def self.inspect
39
+ to_s
40
+ end
41
+
42
+ def self.scope
43
+ ::Object
44
+ end
45
+
46
+ def self.to_s
47
+ "<Nested object definition in #{scope}>"
48
+ end
49
+
50
+ def dependency?
51
+ true
52
+ end
53
+
54
+ attr_reader :root
55
+
56
+ def dependencies
57
+ @dependencies ||= Set.new
58
+ end
59
+
60
+ protected
61
+
62
+ def initialize(root_link, obj)
63
+ @root = root_link
64
+ depends_on(obj) if obj.dependency?
65
+ @options = Options.new(obj)
66
+ process_options(obj)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end