sparkle_formation 1.0.4 → 1.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 +4 -4
- data/CHANGELOG.md +5 -0
- data/docs/README.md +28 -0
- data/docs/anatomy.md +205 -0
- data/docs/building-blocks.md +360 -0
- data/docs/compile-time-parameters.md +182 -0
- data/docs/helper-methods.md +157 -0
- data/docs/nested-stacks.md +425 -0
- data/docs/overview.md +54 -0
- data/docs/sparkle-packs.md +211 -0
- data/docs/sparkleformation-dsl.md +303 -0
- data/docs/stack-policies.md +90 -0
- data/docs/translation.md +64 -0
- data/docs/v/0.3.2/marked.js +1272 -0
- data/docs/v/bootstrap.min.css +7 -0
- data/docs/v/finalizer.css +6 -0
- data/docs/v/highlight.min.css +1 -0
- data/docs/v/highlight.min.js +2 -0
- data/docs/v/jquery-2.1.3.min.js +4 -0
- data/docs/v/loader.js +34 -0
- data/lib/sparkle_formation/sparkle.rb +4 -0
- data/lib/sparkle_formation/sparkle_formation.rb +75 -14
- data/lib/sparkle_formation/sparkle_struct.rb +17 -0
- data/lib/sparkle_formation/version.rb +1 -1
- data/sparkle_formation.gemspec +1 -1
- metadata +21 -4
@@ -0,0 +1,425 @@
|
|
1
|
+
---
|
2
|
+
title: "Nested Stacks"
|
3
|
+
category: "dsl"
|
4
|
+
weight: 6
|
5
|
+
anchors:
|
6
|
+
- title: "Shallow Nesting"
|
7
|
+
url: "#shallow-nesting"
|
8
|
+
- title: "Deep Nesting"
|
9
|
+
url: "#deep-nesting"
|
10
|
+
---
|
11
|
+
|
12
|
+
## Nested Stacks
|
13
|
+
|
14
|
+
Most orchestration API templating systems provide support for a
|
15
|
+
"stack" resource which allows for a stack to define one or more
|
16
|
+
_nested_ stacks within its resources. SparkleFormation expands
|
17
|
+
stack nesting by adding extra functionality when compiling
|
18
|
+
SparkleFormation templates. Currently two styles of expanded
|
19
|
+
functionality are available and are explained in depth below:
|
20
|
+
|
21
|
+
- [Shallow Nesting](#shallow-nesting)
|
22
|
+
- [Deep Nesting](#deep-nesting)
|
23
|
+
|
24
|
+
The interface for using SparkleFormation's nested stack functionality
|
25
|
+
is via the `nest!` helper method. The method accepts a template
|
26
|
+
name and will insert the stack resource into the current template:
|
27
|
+
|
28
|
+
~~~ruby
|
29
|
+
SparkleFormation.new(:root_template) do
|
30
|
+
nest!(:networking)
|
31
|
+
nest!(:applications)
|
32
|
+
end
|
33
|
+
~~~
|
34
|
+
|
35
|
+
### Shallow Nesting
|
36
|
+
|
37
|
+
Shallow stack nesting is the original style of nesting functionality
|
38
|
+
implemented within SparkleFormation. Key features/restrictions of
|
39
|
+
shallow nesting:
|
40
|
+
|
41
|
+
* Support nesting _one_ level deep
|
42
|
+
* Automatic parameter bubbling to root stack
|
43
|
+
* Automatic output mapping
|
44
|
+
|
45
|
+
#### Shallow Nesting Depth
|
46
|
+
|
47
|
+
Shallow nesting is restricted to single level nesting. This restriction
|
48
|
+
is in place due to the shallow nesting style being the first successfully
|
49
|
+
implemented nesting strategy. The restriction remains due to the unique
|
50
|
+
behavior this style of nesting provides which does not work well past
|
51
|
+
a single level of nesting.
|
52
|
+
|
53
|
+
#### Nested Parameter Bubbling
|
54
|
+
|
55
|
+
On compilation SparkleFormation will process nested stacks in a top-down
|
56
|
+
order. It will first extract parameter names from the nested stack. If
|
57
|
+
the root stack has no matching parameter, the parameter will automatically
|
58
|
+
be added to the root stack. For example:
|
59
|
+
|
60
|
+
~~~ruby
|
61
|
+
SparkleFormation.new(:template_a) do
|
62
|
+
...
|
63
|
+
parameters.fubar do
|
64
|
+
type 'String'
|
65
|
+
default 'FOOBAR'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
~~~
|
69
|
+
|
70
|
+
~~~ruby
|
71
|
+
SparkleFormation.new(:root) do
|
72
|
+
nest!(:template_a)
|
73
|
+
end
|
74
|
+
~~~
|
75
|
+
|
76
|
+
when compiled would result in:
|
77
|
+
|
78
|
+
~~~json
|
79
|
+
...
|
80
|
+
"Parameters": {
|
81
|
+
"Fubar": {
|
82
|
+
"Type": "String",
|
83
|
+
"Default": "FOOBAR"
|
84
|
+
}
|
85
|
+
},
|
86
|
+
"Resources": {
|
87
|
+
"TemplateA": {
|
88
|
+
"Type": "AWS::CloudFormation::Stack",
|
89
|
+
"Properties": {
|
90
|
+
"Parameters": {
|
91
|
+
"Fubar": {
|
92
|
+
"Ref": "Fubar"
|
93
|
+
}
|
94
|
+
|
95
|
+
...
|
96
|
+
~~~
|
97
|
+
|
98
|
+
If a second stack is nested and it defines a parameter
|
99
|
+
with the same name as a previously defined parameter,
|
100
|
+
only the original parameter will be used and both stacks
|
101
|
+
will reference it.
|
102
|
+
|
103
|
+
This _parameter bubbling_ behavior allows all contained stacks
|
104
|
+
to be controlled from the root stack providing a single point
|
105
|
+
of interaction.
|
106
|
+
|
107
|
+
#### Nested Output Mapping
|
108
|
+
|
109
|
+
During compilation and processing of nested stacks, SparkleFormation
|
110
|
+
will also keep list of outputs available from previously processed
|
111
|
+
nested stack resources. If a parameter name on a nested stack
|
112
|
+
matches the name of an output defined in a nested stack, SparkleFormation
|
113
|
+
will automatically update the nested stack resource parameter to
|
114
|
+
use the output value. For example:
|
115
|
+
|
116
|
+
~~~ruby
|
117
|
+
SparkleFormation.new(:template_a) do
|
118
|
+
...
|
119
|
+
outputs.address do
|
120
|
+
description 'Address of thing'
|
121
|
+
value ref!(:thing)
|
122
|
+
end
|
123
|
+
...
|
124
|
+
end
|
125
|
+
~~~
|
126
|
+
|
127
|
+
~~~ruby
|
128
|
+
SparkleFormation.new(:template_b) do
|
129
|
+
...
|
130
|
+
parameters.address do
|
131
|
+
type 'String'
|
132
|
+
end
|
133
|
+
...
|
134
|
+
end
|
135
|
+
~~~
|
136
|
+
|
137
|
+
~~~ruby
|
138
|
+
SparkleFormation.new(:root_template) do
|
139
|
+
nest!(:template_a)
|
140
|
+
nest!(:template_b)
|
141
|
+
end
|
142
|
+
~~~
|
143
|
+
|
144
|
+
When the final template file is compiled SparkleFormation will not
|
145
|
+
bubble the `Address` parameter to the root stack. Because `template_b`
|
146
|
+
defines an output with a matching name, SparkleFormation automatically
|
147
|
+
uses that output value:
|
148
|
+
|
149
|
+
~~~json
|
150
|
+
...
|
151
|
+
"TemplateB": {
|
152
|
+
"Type": "AWS::CloudFormation::Stack",
|
153
|
+
"Properties": {
|
154
|
+
"Parameters": {
|
155
|
+
"Address": {
|
156
|
+
"Fn:GetAtt": [
|
157
|
+
"TemplateA",
|
158
|
+
"Outputs.Address"
|
159
|
+
]
|
160
|
+
}
|
161
|
+
...
|
162
|
+
~~~
|
163
|
+
|
164
|
+
Shallow nesting easily exposes the power of nesting stack resources
|
165
|
+
while maintaining a single point of access for managing a stack. This
|
166
|
+
is important to note when looking at the ease of use for updating
|
167
|
+
running stacks. Unless a template change is required, parameter changes
|
168
|
+
can be made via a single update call to the root stack. It also means
|
169
|
+
that parameter based updates can be provided from any acceptable interface,
|
170
|
+
be it a CLI tool, or web based UI.
|
171
|
+
|
172
|
+
_NOTE: One issue quickly encountered with parameter heavy nested stacks
|
173
|
+
is resource limits on the number of parameters allowed within a single
|
174
|
+
stack. Using deep stack nesting prevents this issue._
|
175
|
+
|
176
|
+
#### Shallow Nesting Usage
|
177
|
+
|
178
|
+
Shallow nesting is performed by calling `SparkleFormation#apply_nesting`.
|
179
|
+
The method expects a block to be provided. This block handles storage
|
180
|
+
of the nested stack template (if required) and any updates to the
|
181
|
+
original stack resource.
|
182
|
+
|
183
|
+
~~~ruby
|
184
|
+
sfn = SparkleFormation.compile(template_path, :sparkle)
|
185
|
+
|
186
|
+
sfn.apply_nesting(:shallow) do |stack_name, nested_stack_sfn, original_stack_resource|
|
187
|
+
template_content = nested_stack_cfn.compile.dump!
|
188
|
+
# store the template content as required, set remote location as `template_url`
|
189
|
+
original_stack_resource.properites.delete!(:stack)
|
190
|
+
original_stack_resource.properties.set!('TemplateURL', template_url)
|
191
|
+
end
|
192
|
+
~~~
|
193
|
+
|
194
|
+
### Deep Nesting
|
195
|
+
|
196
|
+
Deep stack nesting is an expansion of the shallow stack nesting functionality.
|
197
|
+
It loses some ease of use but gains greater functionality. Key features/
|
198
|
+
restrictions of deep stack nesting:
|
199
|
+
|
200
|
+
* No parameter bubbling
|
201
|
+
* Supports unlimited nesting depths
|
202
|
+
* Automatic output mapping
|
203
|
+
* Automatic output bubbling
|
204
|
+
|
205
|
+
#### Deep Nested Parameters
|
206
|
+
|
207
|
+
Deep stack nesting does not provide parameter bubbling. The biggest issue
|
208
|
+
in providing this type of behavior for deeply nested stacks are the limits
|
209
|
+
applied by the API. It also introduces more complexity to the implementation
|
210
|
+
since parameters would have to be propagated from the root stack to the
|
211
|
+
leaf stacks requiring the parameters.
|
212
|
+
|
213
|
+
Instead of bubbling parameters to the root stack, deep nesting behavior
|
214
|
+
does nothing with the parameters defined for nested stacks. It shifts that
|
215
|
+
responsibility to the application which can update resource's parameters
|
216
|
+
as it decides using its registered callback handler.
|
217
|
+
|
218
|
+
#### Unlimited Nesting Depth
|
219
|
+
|
220
|
+
Deep stack nesting does not enforce a limit on the number of levels deep
|
221
|
+
stacks may be nested. This _may_ not be true for the targeted API.
|
222
|
+
Supporting multiple levels of nesting makes it easy to logically
|
223
|
+
compartmentalize related resources into stacks, which can then be
|
224
|
+
collected and compartmentalized into category-style stacks which can be
|
225
|
+
nested into the root stack. This can make it easier to not only develop
|
226
|
+
stacks but easier to reason about as well.
|
227
|
+
|
228
|
+
#### Automatic Output Mapping and Bubbling
|
229
|
+
|
230
|
+
Much like the shallow nesting behavior, deep nesting provides automatic
|
231
|
+
output value mapping to parameters of a matching name. This behavior is
|
232
|
+
more challenging when using deep nesting behavior due to the possibility
|
233
|
+
of outputs being defined in a resource tree that is isolated from a
|
234
|
+
nested stack requiring its value. To solve this problem SparkleFormation
|
235
|
+
will automatically add an output entry to the parent stack(s) "bubbling"
|
236
|
+
the value until the output is available at the same level requesting stack.
|
237
|
+
If the requesting stack is nested from the common depth, then parameters
|
238
|
+
are added to the stacks to "push" the value down.
|
239
|
+
|
240
|
+
##### Output Bubbling Behavior
|
241
|
+
|
242
|
+
This example will illustrate the behavior seen when outputs are "bubbled":
|
243
|
+
|
244
|
+
~~~ruby
|
245
|
+
SparkleFormation.new(:networking) do
|
246
|
+
...
|
247
|
+
outputs.subnet do
|
248
|
+
description 'Networking subnet'
|
249
|
+
value ref!(:subnet_resource)
|
250
|
+
end
|
251
|
+
...
|
252
|
+
end
|
253
|
+
~~~
|
254
|
+
|
255
|
+
~~~ruby
|
256
|
+
SparkleFormation.new(:infrastructure) do
|
257
|
+
...
|
258
|
+
nest!(:networking)
|
259
|
+
...
|
260
|
+
end
|
261
|
+
~~~
|
262
|
+
|
263
|
+
~~~ruby
|
264
|
+
SparkleFormation.new(:applications) do
|
265
|
+
...
|
266
|
+
nest!(:moneymaker)
|
267
|
+
...
|
268
|
+
end
|
269
|
+
~~~
|
270
|
+
|
271
|
+
~~~ruby
|
272
|
+
SparkleFormation.new(:moneymaker) do
|
273
|
+
parameters.subnet do
|
274
|
+
type 'String'
|
275
|
+
end
|
276
|
+
...
|
277
|
+
end
|
278
|
+
~~~
|
279
|
+
|
280
|
+
~~~ruby
|
281
|
+
SparkleFormation.new(:root) do
|
282
|
+
nest!(:infrastructure)
|
283
|
+
nest!(:applications)
|
284
|
+
end
|
285
|
+
~~~
|
286
|
+
|
287
|
+
When the `root` stack is compiled, it will first process the `infrastructure`
|
288
|
+
nesting, which will in turn process the `networking` nesting. After processing
|
289
|
+
those stacks, SparkleFormation will know the location of the `Subnet` output.
|
290
|
+
It will then process the `application` nesting, which has a `Subnet` parameter
|
291
|
+
matching a known output. Because the `Subnet` output from `networking` stack
|
292
|
+
is not accessible from the root stack to provide to the `application` stack,
|
293
|
+
SparkleFormation will add an output to the `infrastructure` stack "bubbling"
|
294
|
+
the output to the root stack. Once it is available at the root stack, it can
|
295
|
+
be passed to the `application` stack resource:
|
296
|
+
|
297
|
+
_NOTE: The below example includes the nested stack contents. A real template
|
298
|
+
will simply include a URL endpoint for fetching the document._
|
299
|
+
|
300
|
+
~~~json
|
301
|
+
{
|
302
|
+
"Resources": {
|
303
|
+
"Infrastructure": {
|
304
|
+
"Type": "AWS::CloudFormation::Stack",
|
305
|
+
"Properties": {
|
306
|
+
"Stack": {
|
307
|
+
"Resources": {
|
308
|
+
"Networking": {
|
309
|
+
"Type": "AWS::CloudFormation::Stack",
|
310
|
+
"Properties": {
|
311
|
+
"Stack": {
|
312
|
+
...
|
313
|
+
"Outputs": {
|
314
|
+
"Subnet": {
|
315
|
+
"Description": "Networking subnet",
|
316
|
+
"Value": {
|
317
|
+
"Ref": "SubnetResource"
|
318
|
+
}
|
319
|
+
}
|
320
|
+
}
|
321
|
+
}
|
322
|
+
}
|
323
|
+
},
|
324
|
+
"TemplateURL": "http://example.com/Networking.json"
|
325
|
+
},
|
326
|
+
"Outputs": {
|
327
|
+
"Subnet": {
|
328
|
+
"Value": {
|
329
|
+
"Fn::Att": [
|
330
|
+
"Networking",
|
331
|
+
"Outputs.Subnet"
|
332
|
+
]
|
333
|
+
}
|
334
|
+
}
|
335
|
+
}
|
336
|
+
},
|
337
|
+
"TemplateURL": "http://example.com/Infrastructure.json"
|
338
|
+
}
|
339
|
+
},
|
340
|
+
"Applications": {
|
341
|
+
"Type": "AWS::CloudFormation::Stack",
|
342
|
+
"Properties": {
|
343
|
+
"Stack": {
|
344
|
+
"Parameters": {
|
345
|
+
"Subnet": {
|
346
|
+
"Type": "String"
|
347
|
+
}
|
348
|
+
},
|
349
|
+
"Resources": {
|
350
|
+
"Moneymaker": {
|
351
|
+
"Type": "AWS::CloudFormation::Stack",
|
352
|
+
"Properties": {
|
353
|
+
"Stack": {
|
354
|
+
"Parameters": {
|
355
|
+
"Subnet": {
|
356
|
+
"Type": "String"
|
357
|
+
}
|
358
|
+
}
|
359
|
+
...
|
360
|
+
},
|
361
|
+
"Parameters": {
|
362
|
+
"Subnet": {
|
363
|
+
"Ref": "Subnet"
|
364
|
+
}
|
365
|
+
},
|
366
|
+
"TemplateURL": "http://example.com/Moneymaker.json"
|
367
|
+
}
|
368
|
+
}
|
369
|
+
}
|
370
|
+
},
|
371
|
+
"Parameters": {
|
372
|
+
"Subnet": {
|
373
|
+
"Fn::Att": [
|
374
|
+
"Infrastructure",
|
375
|
+
"Outputs.Subnet"
|
376
|
+
]
|
377
|
+
}
|
378
|
+
},
|
379
|
+
"TemplateURL": "http://example.com/Applications.json"
|
380
|
+
}
|
381
|
+
}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
~~~
|
385
|
+
|
386
|
+
When the `root` template is compiled, it nests the `infrastructure` template, which in turn
|
387
|
+
nests the `networking` template. The `Subnet` output is found, registered, and the compilation
|
388
|
+
continues. At this point the `networking` template is the last of this "branch", so compilation
|
389
|
+
returns to the `root` template and starts on the nested `applications` template. It has
|
390
|
+
`moneymaker` nested and when the `moneymaker` template is processed, the parameter `Subnet` is
|
391
|
+
checked in the registered outputs. Since a match is found, two things happen:
|
392
|
+
|
393
|
+
1. The `Subnet` output is "bubbled" to the `infrastructure` template
|
394
|
+
2. The `Subnet` output from the `infrastructure` template is "dripped" into the `applications`
|
395
|
+
template and passed to the `moneymaker` template
|
396
|
+
|
397
|
+
When a parameter is encountered and a matching output has been registered, SparkleFormation will
|
398
|
+
add stack outputs to parent templates until a common context can be found between the requesting
|
399
|
+
template (template with the parameter) and the providing template (template with the output). The
|
400
|
+
common context for the two templates may not make it accessible to the requesting template, which is
|
401
|
+
where the "dripping" method is employed.
|
402
|
+
|
403
|
+
Since the requesting template may not have access to the common context (as the example above illustrates),
|
404
|
+
SparkleFormation will "drip" the value down to the template. It does this by injecting a `Subnet` parameter
|
405
|
+
into child templates and passing the value in the stack resource until it reaches a common depth with
|
406
|
+
the requesting template. Once this is completed, the requesting template will have access to the output
|
407
|
+
from the provider template.
|
408
|
+
|
409
|
+
#### Deep Nesting Usage
|
410
|
+
|
411
|
+
Deep nesting is performed by calling `SparkleFormation#apply_nesting`.
|
412
|
+
The method expects a block to be provided. This block handles storage
|
413
|
+
of the nested stack template (if required) and any updates to the
|
414
|
+
original stack resource.
|
415
|
+
|
416
|
+
~~~ruby
|
417
|
+
sfn = SparkleFormation.compile(template_path, :sparkle)
|
418
|
+
|
419
|
+
sfn.apply_nesting(:deep) do |stack_name, nested_stack_sfn, original_stack_resource|
|
420
|
+
template_content = nested_stack_cfn.compile.dump!
|
421
|
+
# store the template content as required, set remote location as `template_url`
|
422
|
+
original_stack_resource.properites.delete!(:stack)
|
423
|
+
original_stack_resource.properties.set!('TemplateURL', template_url)
|
424
|
+
end
|
425
|
+
~~~
|
data/docs/overview.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
---
|
2
|
+
title: "Overview"
|
3
|
+
category: "dsl"
|
4
|
+
weight: 1
|
5
|
+
next:
|
6
|
+
label: "SparkleFormation DSL"
|
7
|
+
url: "sparkleformation-dsl.md"
|
8
|
+
---
|
9
|
+
|
10
|
+
# Overview
|
11
|
+
|
12
|
+
SparkleFormation is a Ruby DSL library that assists in programmatically
|
13
|
+
composing template files commonly used by orchestration APIs. The library
|
14
|
+
has specific helper methods defined targeting the [AWS CloudFormation][cfn]
|
15
|
+
API, but the library is _not_ restricted to generating only
|
16
|
+
[AWS CloudFormation][cfn] templates.
|
17
|
+
|
18
|
+
SparkleFormation templates describe the state of infrastructure resources
|
19
|
+
as code. This allows for provisioning and updating of isolated stacks of
|
20
|
+
resources in a predictable and repeatable manner. These stacks can be
|
21
|
+
mangaged as single independent or interdependent collection which allow
|
22
|
+
for creation, modification, or deletion via a single API call.
|
23
|
+
|
24
|
+
SparkleFormation can be used to compose templates for any orchestration
|
25
|
+
API that accepts serialized documents to describe resources. This includes
|
26
|
+
AWS, Rackspace, OpenStack, GCE, and other similar services.
|
27
|
+
|
28
|
+
## Getting Started
|
29
|
+
|
30
|
+
SparkleFormation on its own is simply a library used to generate serialized
|
31
|
+
templates. This documentation is focused mainly on the library specific
|
32
|
+
features and functionality. For user documentation focused on building and
|
33
|
+
generating infrastructure with SparkleFormation, please refer to the
|
34
|
+
[sfn][sfn] documentation.
|
35
|
+
|
36
|
+
[cfn]: https://aws.amazon.com/cloudformation/
|
37
|
+
[sfn]: http://www.sparkleformation.io/docs/sfn
|
38
|
+
|
39
|
+
### Installation
|
40
|
+
|
41
|
+
SparkleFormation is available from [Ruby Gems](https://rubygems.org/gems/sparkle_formation). To install, simply execute:
|
42
|
+
|
43
|
+
~~~sh
|
44
|
+
$ gem install sparkle_formation
|
45
|
+
~~~
|
46
|
+
|
47
|
+
or, if you use [Bundler](http://bundler.io/), add the following to your Gemfile:
|
48
|
+
|
49
|
+
~~~sh
|
50
|
+
gem 'sparkle_formation', '~> 1.0.4'
|
51
|
+
~~~
|
52
|
+
|
53
|
+
This will install the SparkleFormation library. To install the `sfn`
|
54
|
+
CLI tool, please [refer to its documentation](http://www.sparkleformation.io/docs/sfn/overview.html#installation)
|
@@ -0,0 +1,211 @@
|
|
1
|
+
---
|
2
|
+
title: "SparklePacks"
|
3
|
+
category: "dsl"
|
4
|
+
weight: 7
|
5
|
+
anchors:
|
6
|
+
- title: "Cheatsheet"
|
7
|
+
url: "#cheatsheet-breakdown"
|
8
|
+
- title: "Requirements"
|
9
|
+
url: "#requirements"
|
10
|
+
- title: "Layout"
|
11
|
+
url: "#layout"
|
12
|
+
- title: "Usage"
|
13
|
+
url: "#usage"
|
14
|
+
---
|
15
|
+
|
16
|
+
## SparklePacks
|
17
|
+
|
18
|
+
SparklePacks are a way to package and ship SparkleFormation collections
|
19
|
+
for direct use, or to extend in customized usage. A SparklePack can be
|
20
|
+
composed of all the building blocks defined by SparkleFormation. Once
|
21
|
+
a SparklePack is built, it can then be loaded and registered making
|
22
|
+
its building blocks available in the current usage context. Multiple
|
23
|
+
SparklePacks can be loaded, and SparkleFormation performs its lookup
|
24
|
+
action based on load order (last loaded retains highest precedence).
|
25
|
+
|
26
|
+
### Cheatsheet Breakdown
|
27
|
+
|
28
|
+
* Composed of SparkleFormation any/all building blocks:
|
29
|
+
* Components
|
30
|
+
* Dynamics
|
31
|
+
* Registry
|
32
|
+
* Templates
|
33
|
+
* Packaged and distributed for reuse
|
34
|
+
* Supports standalone usage _and_ project integration
|
35
|
+
* Allows loading of multiple SparklePacks
|
36
|
+
* SparklePacks affect building block lookup behavior of SparkleFormation
|
37
|
+
* Last loaded SparklePack retains highest precedence
|
38
|
+
|
39
|
+
### Requirements
|
40
|
+
|
41
|
+
#### Explicit Building Block Methods
|
42
|
+
|
43
|
+
The [explicit building block methods](building-blocks.md#name-based-components)
|
44
|
+
must be used when creating a SparklePack. Usage of implicit methods (like
|
45
|
+
`SparkleFormation.build` instead of `SparkleFormation.component`) is currently working but
|
46
|
+
should be considered un-supported. The explicit methods also allow
|
47
|
+
more flexibility on the layout of files since the file system structure
|
48
|
+
and file naming are decoupled.
|
49
|
+
|
50
|
+
### Layout
|
51
|
+
|
52
|
+
A SparklePack is simply a directory containing a `sparkleformation`
|
53
|
+
subdirectory which contains all distributed building blocks:
|
54
|
+
|
55
|
+
~~~
|
56
|
+
> tree
|
57
|
+
.
|
58
|
+
|____sparkleformation
|
59
|
+
| |____dynamics
|
60
|
+
| |____components
|
61
|
+
| |____registry
|
62
|
+
~~~
|
63
|
+
|
64
|
+
### Usage
|
65
|
+
|
66
|
+
On instantiation, `SparkleFormation` will automatically generate a
|
67
|
+
SparklePack based on global configuration and current working directory.
|
68
|
+
A customized pack can be provided on instantiation to override this
|
69
|
+
behavior:
|
70
|
+
|
71
|
+
~~~ruby
|
72
|
+
root_pack = SparkleFormation::SparklePack.new(
|
73
|
+
:root => PATH_TO_PACK
|
74
|
+
)
|
75
|
+
sfn = SparkleFormation.new(:my_template, :sparkle => root_pack) do
|
76
|
+
# Define template
|
77
|
+
end
|
78
|
+
~~~
|
79
|
+
|
80
|
+
It is also possible to add additional SparklePacks to an existing
|
81
|
+
SparkleFormation.
|
82
|
+
|
83
|
+
> NOTE: The SparklePack used on instantiation of a SparkleFormation
|
84
|
+
> instance is considered the *root* SparklePack and will _*always*_
|
85
|
+
> have the highest precedence.
|
86
|
+
|
87
|
+
Building from the previous example, adding a additional pack:
|
88
|
+
|
89
|
+
~~~ruby
|
90
|
+
root_pack = SparkleFormation::SparklePack.new(
|
91
|
+
:root => PATH_TO_PACK
|
92
|
+
)
|
93
|
+
custom_pack = SparkleFormation::SparklePack.new(
|
94
|
+
:root => PATH_TO_PACK
|
95
|
+
)
|
96
|
+
|
97
|
+
sfn = SparkleFormation.new(
|
98
|
+
:my_template,
|
99
|
+
:sparkle => root_pack
|
100
|
+
)
|
101
|
+
sfn.sparkle.add_sparkle(custom_pack)
|
102
|
+
~~~
|
103
|
+
|
104
|
+
With this `custom_pack` added to the collection, the SparkleFormation
|
105
|
+
lookup for building blocks will follow the order:
|
106
|
+
|
107
|
+
1. `root_pack`
|
108
|
+
2. `custom_pack`
|
109
|
+
|
110
|
+
By default new packs added will retain higher precedence than existing
|
111
|
+
packs already added:
|
112
|
+
|
113
|
+
~~~ruby
|
114
|
+
root_pack = SparkleFormation::SparklePack.new(
|
115
|
+
:root => PATH_TO_PACK
|
116
|
+
)
|
117
|
+
custom_pack = SparkleFormation::SparklePack.new(
|
118
|
+
:root => PATH_TO_PACK
|
119
|
+
)
|
120
|
+
override_pack = SparkleFormation::SparklePack.new(
|
121
|
+
:root => PATH_TO_PACK
|
122
|
+
)
|
123
|
+
|
124
|
+
sfn = SparkleFormation.new(
|
125
|
+
:my_template,
|
126
|
+
:sparkle => root_pack
|
127
|
+
)
|
128
|
+
sfn.sparkle.add_sparkle(custom_pack)
|
129
|
+
sfn.sparkle.add_sparkle(override_pack)
|
130
|
+
~~~
|
131
|
+
|
132
|
+
|
133
|
+
In the above example `override_pack` holds the second highest precedence
|
134
|
+
(the `root_pack` always holding the highest). Lookups will now have the
|
135
|
+
following order:
|
136
|
+
|
137
|
+
1. `root_pack`
|
138
|
+
2. `override_pack`
|
139
|
+
3. `custom_pack`
|
140
|
+
|
141
|
+
It is possible to force a pack to the lowest precedence level when
|
142
|
+
adding:
|
143
|
+
|
144
|
+
~~~ruby
|
145
|
+
root_pack = SparkleFormation::SparklePack.new(
|
146
|
+
:root => PATH_TO_PACK
|
147
|
+
)
|
148
|
+
custom_pack = SparkleFormation::SparklePack.new(
|
149
|
+
:root => PATH_TO_PACK
|
150
|
+
)
|
151
|
+
base_pack = SparkleFormation::SparklePack.new(
|
152
|
+
:root => PATH_TO_PACK
|
153
|
+
)
|
154
|
+
|
155
|
+
sfn = SparkleFormation.new(
|
156
|
+
:my_template,
|
157
|
+
:sparkle => root_pack
|
158
|
+
)
|
159
|
+
sfn.sparkle.add_sparkle(custom_pack)
|
160
|
+
sfn.sparkle.add_sparkle(base_pack, :low)
|
161
|
+
~~~
|
162
|
+
|
163
|
+
This example demonstrates how to add a pack at the lowest precedence
|
164
|
+
level allowing currently registered SparklePacks to retain their
|
165
|
+
existing precedence. Lookups in this example will have the
|
166
|
+
following order:
|
167
|
+
|
168
|
+
1. `root_pack`
|
169
|
+
2. `custom_pack`
|
170
|
+
3. `base_pack`
|
171
|
+
|
172
|
+
This behavior is _non-default_ so ensure it is the expected behavior
|
173
|
+
within an implementation.
|
174
|
+
|
175
|
+
### Distribution
|
176
|
+
|
177
|
+
SparklePacks are structured such that it is easy to package and
|
178
|
+
distrbute them via RubyGems. An example file structure for `my-pack`
|
179
|
+
gem:
|
180
|
+
|
181
|
+
~~~
|
182
|
+
> tree
|
183
|
+
.
|
184
|
+
|____my-pack.gemspec
|
185
|
+
|____lib
|
186
|
+
| |____sparkleformation
|
187
|
+
| | |____dynamics
|
188
|
+
| | |____components
|
189
|
+
| | |____registry
|
190
|
+
| |____my-pack.rb
|
191
|
+
~~~
|
192
|
+
|
193
|
+
Then register the pack:
|
194
|
+
|
195
|
+
~~~ruby
|
196
|
+
# ./lib/my-pack.rb
|
197
|
+
|
198
|
+
SparkleFormation::SparklePack.register!
|
199
|
+
~~~
|
200
|
+
|
201
|
+
Once registered, packs can be loaded via name:
|
202
|
+
|
203
|
+
~~~ruby
|
204
|
+
require 'my-pack'
|
205
|
+
root_pack = SparkleFormation::SparklePack.new(:name => 'my-pack')
|
206
|
+
|
207
|
+
sfn = SparkleFormation.new(
|
208
|
+
:my_template,
|
209
|
+
:sparkle => root_pack
|
210
|
+
)
|
211
|
+
~~~
|