cloud-templates 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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