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,660 @@
|
|
1
|
+
require 'aws/templates/exceptions'
|
2
|
+
require 'aws/templates/utils/parametrized'
|
3
|
+
require 'aws/templates/utils/parametrized/nested'
|
4
|
+
require 'aws/templates/utils/parametrized/mapper'
|
5
|
+
require 'singleton'
|
6
|
+
|
7
|
+
module Aws
|
8
|
+
module Templates
|
9
|
+
module Utils
|
10
|
+
module Parametrized #:nodoc:
|
11
|
+
##
|
12
|
+
# Transformation functor class
|
13
|
+
#
|
14
|
+
# A transformation is a Proc accepting input value and providing output
|
15
|
+
# value which is expected to be a transformation of the input.
|
16
|
+
# The proc is executed in instance context so instance methods can
|
17
|
+
# be used for calculation.
|
18
|
+
#
|
19
|
+
# The class implements functor pattern through to_proc method and
|
20
|
+
# closure. Essentially, all transformations can be used everywhere where
|
21
|
+
# a block is expected.
|
22
|
+
#
|
23
|
+
# It provides protected method transform which should be overriden in
|
24
|
+
# all concrete transformation classes.
|
25
|
+
class Transformation
|
26
|
+
##
|
27
|
+
# Apply several transformation sequentially
|
28
|
+
#
|
29
|
+
# Useful when a few transformations need to be applied to a single value to get
|
30
|
+
# the final result
|
31
|
+
#
|
32
|
+
# === Example
|
33
|
+
#
|
34
|
+
# class Piece
|
35
|
+
# include Aws::Templates::Utils::Parametrized
|
36
|
+
#
|
37
|
+
# parameter :param,
|
38
|
+
# transform: as_chain(
|
39
|
+
# as_hash,
|
40
|
+
# as_object(Aws::Templates::Utils::AsNamed)
|
41
|
+
# )
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# i = Piece.new(param: [:name, 'Rex'])
|
45
|
+
# i.param.name # => 'Rex'
|
46
|
+
class AsChain < Transformation
|
47
|
+
attr_reader :components
|
48
|
+
|
49
|
+
def initialize(components)
|
50
|
+
@components = _check_components(components)
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def transform(parameter, value, instance)
|
56
|
+
return if value.nil?
|
57
|
+
components.inject(value) { |acc, elem| instance.instance_exec(parameter, acc, &elem) }
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def _check_components(components)
|
63
|
+
result = components.to_a
|
64
|
+
|
65
|
+
invalid_components = result.reject { |component| component.respond_to?(:to_proc) }
|
66
|
+
raise "Invalid components: #{invalid_components}" unless invalid_components.empty?
|
67
|
+
|
68
|
+
result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Transform input value into the object
|
74
|
+
#
|
75
|
+
# Input value can be either hash or object. The transformation performs
|
76
|
+
# nested object evaluation recusrsively as the input were Parametrized
|
77
|
+
# instance. As a parameter for the transformation you can
|
78
|
+
# specify either Module which mixes in Parametrized or to use
|
79
|
+
# a block which is to be evaluated as a part of Parametrized definition
|
80
|
+
# or both.
|
81
|
+
#
|
82
|
+
# With as_object transformation you can have as many nested levels
|
83
|
+
# as it's needed.
|
84
|
+
#
|
85
|
+
# === Example
|
86
|
+
#
|
87
|
+
# class Piece
|
88
|
+
# include Aws::Templates::Utils::Parametrized
|
89
|
+
#
|
90
|
+
# parameter :param1,
|
91
|
+
# :transform => as_object(Aws::Templates::Utils::AsNamed)
|
92
|
+
# parameter :param2, :transform => as_object {
|
93
|
+
# parameter :id, :description => 'Just ID',
|
94
|
+
# :constraint => not_nil
|
95
|
+
# }
|
96
|
+
# parameter :param3,
|
97
|
+
# :transform => as_object(Aws::Templates::Utils::AsNamed) {
|
98
|
+
# parameter :path, :description => 'Just path',
|
99
|
+
# :constraint => not_nil
|
100
|
+
# }
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# i = Piece.new
|
104
|
+
# i.param1 # => nil
|
105
|
+
# i = Piece.new(:param1 => {:name => 'Zed'})
|
106
|
+
# i.param1.name # => 'Zed'
|
107
|
+
# i = Piece.new(:param2 => {:id => 123})
|
108
|
+
# i.param2.id # => 123
|
109
|
+
# i = Piece.new(:param3 => {:path => 'a/b', :name => 'Rex'})
|
110
|
+
# i.param3.path # => 'a/b'
|
111
|
+
# i.param3.name # => 123
|
112
|
+
class AsObject < Transformation
|
113
|
+
attr_reader :klass
|
114
|
+
|
115
|
+
def initialize(scope, klass = nil, &definition)
|
116
|
+
@klass = if klass.nil?
|
117
|
+
Nested.create_class(scope)
|
118
|
+
elsif klass.is_a?(Class)
|
119
|
+
klass
|
120
|
+
elsif klass.is_a?(Module)
|
121
|
+
Nested.create_class(scope).with(klass)
|
122
|
+
else
|
123
|
+
raise "#{klass} is neither a class nor a module"
|
124
|
+
end
|
125
|
+
|
126
|
+
@klass.class_eval(&definition) unless definition.nil?
|
127
|
+
end
|
128
|
+
|
129
|
+
protected
|
130
|
+
|
131
|
+
def transform(_, value, instance)
|
132
|
+
return if value.nil?
|
133
|
+
klass.new instance.root,
|
134
|
+
if Utils.hashable?(value)
|
135
|
+
value
|
136
|
+
elsif Utils.parametrized?(value)
|
137
|
+
Mapper.new(value)
|
138
|
+
else
|
139
|
+
raise "Value #{value} doesn't have parameters"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
##
|
145
|
+
# Transform input value into a list
|
146
|
+
#
|
147
|
+
# Input value can be either an array or something which implements
|
148
|
+
# to_a method standard semantics. Each list entry is evaluated
|
149
|
+
# with specified constraints and transformations.
|
150
|
+
#
|
151
|
+
# With as_list transformation you can have as many nested levels
|
152
|
+
# as it's needed in terms of nested lists or nested objects.
|
153
|
+
#
|
154
|
+
# === Example
|
155
|
+
#
|
156
|
+
# class Piece
|
157
|
+
# include Aws::Templates::Utils::Parametrized
|
158
|
+
#
|
159
|
+
# parameter :param1, :transform => as_list(
|
160
|
+
# # alias for all elements. Plays a role during introspection
|
161
|
+
# :name => :element,
|
162
|
+
# # description of what the element represents
|
163
|
+
# :description => 'List element',
|
164
|
+
# # constraint for list element
|
165
|
+
# :constraint => not_nil
|
166
|
+
# )
|
167
|
+
# parameter :param2, :transform => as_list(
|
168
|
+
# :name => :element,
|
169
|
+
# :description => 'List element',
|
170
|
+
# :transform => as_list( # nested list
|
171
|
+
# :name => :sub_element,
|
172
|
+
# :description => 'Sub-list element',
|
173
|
+
# :constraint => not_nil
|
174
|
+
# )
|
175
|
+
# )
|
176
|
+
# parameter :param3, :transform => as_list(
|
177
|
+
# :name => :particle,
|
178
|
+
# :description => 'Small particle',
|
179
|
+
# :transform => as_object( # nested object
|
180
|
+
# Aws::Templates::Utils::AsNamed
|
181
|
+
# )
|
182
|
+
# )
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# i = Piece.new(:param1 => [1,2,3])
|
186
|
+
# i.param1 # => [1,2,3]
|
187
|
+
# i = Piece.new(:param1 => [1,nil,3])
|
188
|
+
# i.param1 # throws exception
|
189
|
+
# i = Piece.new(:param2 => [[1],[2],[3]])
|
190
|
+
# i.param2 # => [[1],[2],[3]]
|
191
|
+
# i = Piece.new(:param2 => [1,[2],[3]])
|
192
|
+
# i.param2 # throws exception
|
193
|
+
# i = Piece.new(:param2 => [[1],[nil],[3]])
|
194
|
+
# i.param2 # throws exception
|
195
|
+
# i = Piece.new(:param3 => [{:name => 'Zed'}])
|
196
|
+
# i.param3.first.name # => 'Zed'
|
197
|
+
class AsList < Transformation
|
198
|
+
attr_reader :sub_parameter
|
199
|
+
|
200
|
+
def initialize(klass = nil, options = nil)
|
201
|
+
return if options.nil?
|
202
|
+
|
203
|
+
@sub_parameter = Parameter.new(
|
204
|
+
options[:name],
|
205
|
+
klass,
|
206
|
+
description: options[:description],
|
207
|
+
transform: options[:transform],
|
208
|
+
constraint: options[:constraint]
|
209
|
+
)
|
210
|
+
end
|
211
|
+
|
212
|
+
protected
|
213
|
+
|
214
|
+
def transform(parameter, value, instance)
|
215
|
+
return if value.nil?
|
216
|
+
|
217
|
+
unless value.respond_to?(:to_a)
|
218
|
+
raise "#{parameter.name} is assigned to " \
|
219
|
+
"#{value.inspect} which is not a list"
|
220
|
+
end
|
221
|
+
|
222
|
+
if sub_parameter
|
223
|
+
value.to_a.map { |el| sub_parameter.process_value(instance, el) }
|
224
|
+
else
|
225
|
+
value.to_a
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Transform value with the specified render
|
232
|
+
#
|
233
|
+
# Input value can be anything which could be rendered by the
|
234
|
+
# specified render type. Returned value is rendered input.
|
235
|
+
#
|
236
|
+
# The transformation is useful when you have a document of some
|
237
|
+
# format embedded into a document of another format. An example
|
238
|
+
# could be Bash scripts embedded into AWS CFN template.
|
239
|
+
#
|
240
|
+
# === Example
|
241
|
+
#
|
242
|
+
# class Brush
|
243
|
+
# attr_reader :color
|
244
|
+
# attr_reader :thickness
|
245
|
+
# attr_reader :type
|
246
|
+
#
|
247
|
+
# def initialize(c, thick, t)
|
248
|
+
# @c = c
|
249
|
+
# @thick = thick
|
250
|
+
# @t = t
|
251
|
+
# end
|
252
|
+
# end
|
253
|
+
#
|
254
|
+
# class Circle
|
255
|
+
# attr_reader :radius
|
256
|
+
# attr_reader :brush
|
257
|
+
#
|
258
|
+
# def initialize(r, b)
|
259
|
+
# @radius = r
|
260
|
+
# @brush = b
|
261
|
+
# end
|
262
|
+
# end
|
263
|
+
#
|
264
|
+
# class Piece
|
265
|
+
# include Aws::Templates::Utils::Parametrized
|
266
|
+
#
|
267
|
+
# parameter :picture, :transform => as_rendered(
|
268
|
+
# # Render Type
|
269
|
+
# Graphics::Renders::JPEG,
|
270
|
+
# # parameter section for the render
|
271
|
+
# format: :base64
|
272
|
+
# )
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# i = Piece.new(picture: Circle.new(10, Brush.new(:red, 2, :dots)))
|
276
|
+
# i.picture # => <rendered representation>
|
277
|
+
class AsRendered < Transformation
|
278
|
+
attr_reader :type
|
279
|
+
attr_reader :parameters
|
280
|
+
|
281
|
+
def initialize(render_type, params)
|
282
|
+
@type = _check_render_type(render_type)
|
283
|
+
@parameters = params
|
284
|
+
end
|
285
|
+
|
286
|
+
protected
|
287
|
+
|
288
|
+
def transform(_, value, instance)
|
289
|
+
return if value.nil?
|
290
|
+
type.view_for(value, _compute_render_parameters(instance)).to_rendered
|
291
|
+
end
|
292
|
+
|
293
|
+
private
|
294
|
+
|
295
|
+
def _check_render_type(render_type)
|
296
|
+
unless render_type.respond_to?(:view_for)
|
297
|
+
raise(
|
298
|
+
"Wrong render type object #{params}. " \
|
299
|
+
'The instance should have #view_for method.'
|
300
|
+
)
|
301
|
+
end
|
302
|
+
|
303
|
+
render_type
|
304
|
+
end
|
305
|
+
|
306
|
+
def _compute_render_parameters(instance)
|
307
|
+
return if parameters.nil?
|
308
|
+
|
309
|
+
if parameters.respond_to?(:to_hash)
|
310
|
+
parameters
|
311
|
+
elsif parameters.respond_to?(:to_proc)
|
312
|
+
instance.instance_exec(¶meters)
|
313
|
+
else
|
314
|
+
parameters
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
##
|
320
|
+
# Convert input into integer
|
321
|
+
#
|
322
|
+
# Input value can be anything implementing :to_i method.
|
323
|
+
#
|
324
|
+
# === Example
|
325
|
+
#
|
326
|
+
# class Piece
|
327
|
+
# include Aws::Templates::Utils::Parametrized
|
328
|
+
#
|
329
|
+
# parameter :param, :transform => as_integer
|
330
|
+
# end
|
331
|
+
#
|
332
|
+
# i = Piece.new
|
333
|
+
# i.param # => nil
|
334
|
+
# i = Piece.new(:param => '23')
|
335
|
+
# i.param # => 23
|
336
|
+
class AsInteger < Transformation
|
337
|
+
include Singleton
|
338
|
+
|
339
|
+
protected
|
340
|
+
|
341
|
+
def transform(_, value, _)
|
342
|
+
return if value.nil?
|
343
|
+
Integer(value)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
##
|
348
|
+
# Convert input into string
|
349
|
+
#
|
350
|
+
# Input value can be anything implementing :to_s method.
|
351
|
+
#
|
352
|
+
# === Example
|
353
|
+
#
|
354
|
+
# class Piece
|
355
|
+
# include Aws::Templates::Utils::Parametrized
|
356
|
+
#
|
357
|
+
# parameter :param, :transform => as_string
|
358
|
+
# end
|
359
|
+
#
|
360
|
+
# i = Piece.new
|
361
|
+
# i.param # => nil
|
362
|
+
# i = Piece.new(:param => 23)
|
363
|
+
# i.param # => '23'
|
364
|
+
class AsString < Transformation
|
365
|
+
include Singleton
|
366
|
+
|
367
|
+
protected
|
368
|
+
|
369
|
+
def transform(_, value, _)
|
370
|
+
return if value.nil?
|
371
|
+
String(value)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
##
|
376
|
+
# Convert input into boolean
|
377
|
+
#
|
378
|
+
# Input value can be anything implementing :to_s method. Value considered false if it is:
|
379
|
+
# * +'false' as a string+
|
380
|
+
# * +FalseClass+
|
381
|
+
# Otherwise, value is true. If value is nil, it won't be replaced by "false"
|
382
|
+
#
|
383
|
+
# === Example
|
384
|
+
#
|
385
|
+
# class Piece
|
386
|
+
# include Aws::Templates::Utils::Parametrized
|
387
|
+
#
|
388
|
+
# parameter :param, :transform => as_boolean
|
389
|
+
# end
|
390
|
+
#
|
391
|
+
# i = Piece.new
|
392
|
+
# i.param # => false
|
393
|
+
# i = Piece.new(:param => 0)
|
394
|
+
# i.param # => true
|
395
|
+
class AsBoolean < Transformation
|
396
|
+
include Singleton
|
397
|
+
|
398
|
+
protected
|
399
|
+
|
400
|
+
def transform(_, value, _)
|
401
|
+
return if value.nil?
|
402
|
+
!value.to_s.casecmp('false').zero?
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
##
|
407
|
+
# Convert input into hash
|
408
|
+
#
|
409
|
+
# Input value can be anything implementing :to_hash method.
|
410
|
+
#
|
411
|
+
# === Example
|
412
|
+
#
|
413
|
+
# class Piece
|
414
|
+
# include Aws::Templates::Utils::Parametrized
|
415
|
+
#
|
416
|
+
# parameter :param, :transform => as_hash
|
417
|
+
# parameter :param2,
|
418
|
+
# transform: as_hash {
|
419
|
+
# value name: :number,
|
420
|
+
# description: 'Number',
|
421
|
+
# constraint: not_nil,
|
422
|
+
# transform: as_integer
|
423
|
+
# }
|
424
|
+
# end
|
425
|
+
#
|
426
|
+
# i = Piece.new
|
427
|
+
# i.param # => nil
|
428
|
+
# i = Piece.new(:param => [[1,2]])
|
429
|
+
# i.param # => {1=>2}
|
430
|
+
# i = Piece.new(:param2 => [[1,'3']])
|
431
|
+
# i.param # => {1=>3}
|
432
|
+
class AsHash < Transformation
|
433
|
+
include Parametrized.class_scope
|
434
|
+
|
435
|
+
def key(opts)
|
436
|
+
@key_parameter = _create_parameter(opts)
|
437
|
+
end
|
438
|
+
|
439
|
+
def value(opts)
|
440
|
+
@value_parameter = _create_parameter(opts)
|
441
|
+
end
|
442
|
+
|
443
|
+
def initialize(klass = nil, &blk)
|
444
|
+
@klass = klass
|
445
|
+
instance_eval(&blk) if blk
|
446
|
+
end
|
447
|
+
|
448
|
+
protected
|
449
|
+
|
450
|
+
def transform(_, value, instance)
|
451
|
+
return if value.nil?
|
452
|
+
|
453
|
+
Hash[
|
454
|
+
Hash[value].map do |k, v|
|
455
|
+
[
|
456
|
+
_process_value(@key_parameter, instance, k),
|
457
|
+
_process_value(@value_parameter, instance, v)
|
458
|
+
]
|
459
|
+
end
|
460
|
+
]
|
461
|
+
end
|
462
|
+
|
463
|
+
def _process_value(parameter, instance, value)
|
464
|
+
return value if parameter.nil?
|
465
|
+
parameter.process_value(instance, value)
|
466
|
+
end
|
467
|
+
|
468
|
+
private
|
469
|
+
|
470
|
+
def _create_parameter(opts)
|
471
|
+
Parameter.new(
|
472
|
+
opts[:name],
|
473
|
+
@klass,
|
474
|
+
description: opts[:description],
|
475
|
+
transform: opts[:transform],
|
476
|
+
constraint: opts[:constraint]
|
477
|
+
)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
##
|
482
|
+
# Convert to a Ruby class
|
483
|
+
#
|
484
|
+
# The transformation allows to use elements of metaprogramming in the framework. It
|
485
|
+
# tries to transform passed value to a Ruby class.
|
486
|
+
#
|
487
|
+
# === Example
|
488
|
+
#
|
489
|
+
# class Piece
|
490
|
+
# include Aws::Templates::Utils::Parametrized
|
491
|
+
#
|
492
|
+
# parameter :param, :transform => as_module
|
493
|
+
# end
|
494
|
+
#
|
495
|
+
# i = Piece.new
|
496
|
+
# i.param # => nil
|
497
|
+
# i = Piece.new(:param => 'Object')
|
498
|
+
# i.param # => Object
|
499
|
+
class AsModule < Transformation
|
500
|
+
include Singleton
|
501
|
+
|
502
|
+
protected
|
503
|
+
|
504
|
+
def transform(_, value, _)
|
505
|
+
return if value.nil?
|
506
|
+
return value if value.is_a?(Module)
|
507
|
+
return _lookup(value.to_s) if value.respond_to?(:to_s)
|
508
|
+
raise "#{value} can't be transformed to a class"
|
509
|
+
end
|
510
|
+
|
511
|
+
private
|
512
|
+
|
513
|
+
PATH_REGEXP = Regexp.compile('::|[.]|/')
|
514
|
+
|
515
|
+
def _lookup(class_name)
|
516
|
+
target = class_name.split(PATH_REGEXP)
|
517
|
+
.inject(::Kernel) { |acc, elem| acc.const_get(elem) }
|
518
|
+
|
519
|
+
raise "#{class_name} == #{target} which is not a class" unless target.is_a?(Module)
|
520
|
+
|
521
|
+
target
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
##
|
526
|
+
# Creates closure with transformation invocation
|
527
|
+
#
|
528
|
+
# It's an interface method required for Transformation to expose
|
529
|
+
# functor properties. It encloses invocation of Transformation
|
530
|
+
# transform_wrapper method into a closure. The closure itself is
|
531
|
+
# executed in the context of Parametrized instance which provides
|
532
|
+
# proper set "self" variable.
|
533
|
+
#
|
534
|
+
# The closure itself accepts 2 parameters:
|
535
|
+
# * +parameter+ - the Parameter object which the transformation
|
536
|
+
# will be performed for
|
537
|
+
# * +value+ - parameter value to be transformed
|
538
|
+
# ...where instance is assumed from self
|
539
|
+
def to_proc
|
540
|
+
transform = self
|
541
|
+
|
542
|
+
lambda do |parameter, value|
|
543
|
+
transform.transform_wrapper(parameter, value, self)
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
##
|
548
|
+
# Wraps transformation-dependent method
|
549
|
+
#
|
550
|
+
# It wraps constraint-dependent "transform" method into a rescue block
|
551
|
+
# to standardize exception type and information provided by failed
|
552
|
+
# transformation calculation
|
553
|
+
# * +parameter+ - the Parameter object which the transformation will
|
554
|
+
# be performed for
|
555
|
+
# * +value+ - parameter value to be transformed
|
556
|
+
# * +instance+ - the instance value is transform
|
557
|
+
def transform_wrapper(parameter, value, instance)
|
558
|
+
transform(parameter, value, instance)
|
559
|
+
rescue StandardError
|
560
|
+
raise NestedParameterException.new(parameter)
|
561
|
+
end
|
562
|
+
|
563
|
+
protected
|
564
|
+
|
565
|
+
##
|
566
|
+
# Transform method
|
567
|
+
#
|
568
|
+
# * +parameter+ - the Parameter object which the transformation is
|
569
|
+
# performed for
|
570
|
+
# * +value+ - parameter value to be transformed
|
571
|
+
# * +instance+ - the instance value is transform
|
572
|
+
def transform(parameter, value, instance); end
|
573
|
+
end
|
574
|
+
|
575
|
+
##
|
576
|
+
# Syntax sugar for transformations definition
|
577
|
+
#
|
578
|
+
# It injects the methods as class-scope methods into mixing classes.
|
579
|
+
# The methods are factories to create particular type of transformation
|
580
|
+
class_scope do
|
581
|
+
##
|
582
|
+
# Chain a few transformations into a single one
|
583
|
+
#
|
584
|
+
# alias for AsChain class
|
585
|
+
def as_chain(*components)
|
586
|
+
Transformation::AsChain.new(components)
|
587
|
+
end
|
588
|
+
|
589
|
+
##
|
590
|
+
# Transform the value into an object
|
591
|
+
#
|
592
|
+
# alias for AsObject class
|
593
|
+
def as_object(klass = nil, &definition)
|
594
|
+
Transformation::AsObject.new(self, klass, &definition)
|
595
|
+
end
|
596
|
+
|
597
|
+
##
|
598
|
+
# Transform the value into a list
|
599
|
+
#
|
600
|
+
# alias for AsList class
|
601
|
+
def as_list(parameters = nil)
|
602
|
+
Transformation::AsList.new(self, parameters)
|
603
|
+
end
|
604
|
+
|
605
|
+
##
|
606
|
+
# Transform value with the specified render
|
607
|
+
#
|
608
|
+
# alias for AsRendered class
|
609
|
+
def as_rendered(render_type, params = nil, ¶ms_block)
|
610
|
+
Transformation::AsRendered.new(render_type, params || params_block)
|
611
|
+
end
|
612
|
+
|
613
|
+
##
|
614
|
+
# Convert input into integer
|
615
|
+
#
|
616
|
+
# alias for AsInteger class
|
617
|
+
def as_integer
|
618
|
+
Transformation::AsInteger.instance
|
619
|
+
end
|
620
|
+
|
621
|
+
##
|
622
|
+
# Convert input into string
|
623
|
+
#
|
624
|
+
# alias for AsString class
|
625
|
+
def as_string
|
626
|
+
Transformation::AsString.instance
|
627
|
+
end
|
628
|
+
|
629
|
+
##
|
630
|
+
# Convert input into boolean
|
631
|
+
#
|
632
|
+
# alias for AsBoolean class
|
633
|
+
def as_boolean
|
634
|
+
Transformation::AsBoolean.instance
|
635
|
+
end
|
636
|
+
|
637
|
+
##
|
638
|
+
# Convert input into hash
|
639
|
+
#
|
640
|
+
# alias for AsHash class
|
641
|
+
def as_hash(&blk)
|
642
|
+
Transformation::AsHash.new(self, &blk)
|
643
|
+
end
|
644
|
+
|
645
|
+
##
|
646
|
+
# Convert input into a class
|
647
|
+
#
|
648
|
+
# alias for AsModule class
|
649
|
+
def as_module
|
650
|
+
Transformation::AsModule.instance
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
class Nested #:nodoc:
|
655
|
+
include Parametrized
|
656
|
+
end
|
657
|
+
end
|
658
|
+
end
|
659
|
+
end
|
660
|
+
end
|