cloud_compose 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/README.md +74 -0
- data/Rakefile +2 -0
- data/lib/cloud_compose/config.rb +41 -0
- data/lib/cloud_compose/parser.rb +45 -0
- data/lib/cloud_compose/processor.rb +15 -0
- data/lib/cloud_compose/tags/base.rb +46 -0
- data/lib/cloud_compose/tags/get_att.rb +22 -0
- data/lib/cloud_compose/tags/map_type.rb +16 -0
- data/lib/cloud_compose/tags/scalar_type.rb +16 -0
- data/lib/cloud_compose/tags/sequenced_type.rb +16 -0
- data/lib/cloud_compose/tags/simple_type.rb +24 -0
- data/lib/cloud_compose/tags/sub.rb +23 -0
- data/lib/cloud_compose/template.rb +172 -0
- data/lib/cloud_compose/version.rb +3 -0
- data/lib/cloud_compose.rb +5 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8d01e1a9806a945e7b31002083f917ce6879392eb6238d0e26558a81f567b9b4
|
4
|
+
data.tar.gz: 004dac72cc30a68a8cd21bdc4be8b11aa7e28c7b6f9a45b9bfd83e94043008cc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9a60c29f02ec15e8297b1c46a72a1a6b0c95cf6756f48dfa99929fd67bba81588cd5fc7d0bd8e1c2117c8a7eefbbc79b57234785af301908c274d9ca57d40a23
|
7
|
+
data.tar.gz: d585de3c2d5eccd3fef396a54701457021beb05422042d4f5facd1f51ed151b63c946bf817f1b1872ac4adc0fbc63b21b990fc1dc64ecf70708bd4d8229caf45
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# CloudCompose
|
2
|
+
|
3
|
+
Compose multiple cloud formation templates into one file.
|
4
|
+
|
5
|
+
`cloud-compose ./template.yml ./output`
|
6
|
+
|
7
|
+
```yaml
|
8
|
+
# template.yml
|
9
|
+
---
|
10
|
+
$cloud_compose:
|
11
|
+
parameters:
|
12
|
+
GlobalName: 'TestTemplate'
|
13
|
+
imports:
|
14
|
+
- name: SubTemplateOne
|
15
|
+
path: ./sub_readme.yml
|
16
|
+
- name: SubTemplateTwo
|
17
|
+
path: ./sub_readme.yml
|
18
|
+
---
|
19
|
+
|
20
|
+
Resources:
|
21
|
+
$(GlobalName)MainResource:
|
22
|
+
Type: AWS::Fake::Thing
|
23
|
+
Properties:
|
24
|
+
Name: My Main Resource
|
25
|
+
SecondaryResource:
|
26
|
+
Type: AWS::Fake::Thing
|
27
|
+
Properties:
|
28
|
+
ParentThing: !Ref $(GlobalName)MainResource
|
29
|
+
```
|
30
|
+
|
31
|
+
```yaml
|
32
|
+
# sub_readme.yml
|
33
|
+
---
|
34
|
+
$cloud_compose:
|
35
|
+
partial: true
|
36
|
+
---
|
37
|
+
|
38
|
+
Resources:
|
39
|
+
$(name)Resource:
|
40
|
+
Type: AWS::Fake::Thing
|
41
|
+
Properties:
|
42
|
+
ParentThing: !Ref $(GlobalName)MainResource
|
43
|
+
Outputs:
|
44
|
+
$(name)ResourceOutput:
|
45
|
+
Value: !Ref $(name)Resource
|
46
|
+
|
47
|
+
```
|
48
|
+
|
49
|
+
```yaml
|
50
|
+
# Output
|
51
|
+
---
|
52
|
+
Resources:
|
53
|
+
TestTemplateMainResource:
|
54
|
+
Type: AWS::Fake::Thing
|
55
|
+
Properties:
|
56
|
+
Name: My Main Resource
|
57
|
+
SecondaryResource:
|
58
|
+
Type: AWS::Fake::Thing
|
59
|
+
Properties:
|
60
|
+
ParentThing: !Ref TestTemplateMainResource
|
61
|
+
SubTemplateOneResource:
|
62
|
+
Type: AWS::Fake::Thing
|
63
|
+
Properties:
|
64
|
+
ParentThing: !Ref TestTemplateMainResource
|
65
|
+
SubTemplateTwoResource:
|
66
|
+
Type: AWS::Fake::Thing
|
67
|
+
Properties:
|
68
|
+
ParentThing: !Ref TestTemplateMainResource
|
69
|
+
Outputs:
|
70
|
+
SubTemplateOneResourceOutput:
|
71
|
+
Value: !Ref SubTemplateOneResource
|
72
|
+
SubTemplateTwoResourceOutput:
|
73
|
+
Value: !Ref SubTemplateTwoResource
|
74
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'parser'
|
2
|
+
|
3
|
+
module CloudCompose
|
4
|
+
class Config
|
5
|
+
Import = Struct.new(:name, :path, :parameters)
|
6
|
+
|
7
|
+
def initialize(config, root)
|
8
|
+
@root = root
|
9
|
+
params = CloudCompose::Parser.load_yaml(config)
|
10
|
+
@config = params.fetch('$cloud_compose')
|
11
|
+
end
|
12
|
+
|
13
|
+
def partial?
|
14
|
+
@config.fetch('partial', false) == true
|
15
|
+
end
|
16
|
+
|
17
|
+
def imports
|
18
|
+
@config.fetch('imports', []).map do |obj|
|
19
|
+
Import.new(
|
20
|
+
obj.fetch('name'),
|
21
|
+
import_path(obj),
|
22
|
+
obj.fetch('parameters', {})
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def parameters
|
28
|
+
@config.fetch('parameters', {})
|
29
|
+
end
|
30
|
+
|
31
|
+
def required_parameters
|
32
|
+
@config.fetch('require', [])
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def import_path(obj)
|
38
|
+
File.expand_path(obj.fetch('path'), @root)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'psych'
|
2
|
+
|
3
|
+
require_relative 'tags/simple_type'
|
4
|
+
|
5
|
+
require_relative 'tags/get_att'
|
6
|
+
require_relative 'tags/sub'
|
7
|
+
|
8
|
+
module CloudCompose
|
9
|
+
class Parser
|
10
|
+
CUSTOM_TAGS = {
|
11
|
+
'!And' => CloudCompose::Tags::And,
|
12
|
+
'!Base64' => CloudCompose::Tags::Base64,
|
13
|
+
'!Cidr' => CloudCompose::Tags::Cidr,
|
14
|
+
'!Condition' => CloudCompose::Tags::Condition,
|
15
|
+
'!Equals' => CloudCompose::Tags::Equals,
|
16
|
+
'!FindInMap' => CloudCompose::Tags::FindInMap,
|
17
|
+
'!GetAZs' => CloudCompose::Tags::GetAzs,
|
18
|
+
'!GetAtt' => CloudCompose::Tags::GetAtt,
|
19
|
+
'!If' => CloudCompose::Tags::If,
|
20
|
+
'!ImportValue' => CloudCompose::Tags::ImportValue,
|
21
|
+
'!Join' => CloudCompose::Tags::Join,
|
22
|
+
'!Not' => CloudCompose::Tags::Not,
|
23
|
+
'!Or' => CloudCompose::Tags::Or,
|
24
|
+
'!Ref' => CloudCompose::Tags::Ref,
|
25
|
+
'!Select' => CloudCompose::Tags::Select,
|
26
|
+
'!Split' => CloudCompose::Tags::Split,
|
27
|
+
'!Sub' => CloudCompose::Tags::Sub,
|
28
|
+
'!Transform' => CloudCompose::Tags::Transform
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def load_yaml(content)
|
33
|
+
Psych.safe_load(content, CUSTOM_TAGS.values)
|
34
|
+
end
|
35
|
+
|
36
|
+
def dump_yaml(object)
|
37
|
+
Psych.dump(object)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
CloudCompose::Parser::CUSTOM_TAGS.each do |key, klass|
|
44
|
+
Psych.add_tag(key, klass)
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CloudCompose
|
2
|
+
class Processor
|
3
|
+
PRE_PROCESSOR_PARAMETER_REGEXP = Regexp.new('\$\((?:[a-zA-Z0-9_]+)\)?').freeze
|
4
|
+
PRE_PROCESSOR_PARAMETER_NAME_REGEXP = Regexp.new('\A\$\((?<token>[a-zA-Z0-9_]+)\)?\z').freeze
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def preprocess(content, context)
|
8
|
+
content.gsub(PRE_PROCESSOR_PARAMETER_REGEXP) do |matched|
|
9
|
+
key = PRE_PROCESSOR_PARAMETER_NAME_REGEXP.match(matched)['token']
|
10
|
+
context.fetch(key)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CloudCompose
|
2
|
+
module Tags
|
3
|
+
class InvalidTypeError < StandardError
|
4
|
+
attr_reader :tag
|
5
|
+
attr_reader :type
|
6
|
+
|
7
|
+
def initialize(tag, type)
|
8
|
+
@tag = tag
|
9
|
+
@type = type
|
10
|
+
super("Invalid Type (#{type}) for tag `#{tag}`")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Base
|
15
|
+
attr_reader :type
|
16
|
+
|
17
|
+
attr_reader :value
|
18
|
+
|
19
|
+
def type_from_coder(coder)
|
20
|
+
coder.type
|
21
|
+
end
|
22
|
+
|
23
|
+
def value_from_coder(_coder)
|
24
|
+
raise NotImplementedError, "Missing #{__method__} override."
|
25
|
+
end
|
26
|
+
|
27
|
+
def init_with(coder)
|
28
|
+
initialize(
|
29
|
+
type_from_coder(coder),
|
30
|
+
value_from_coder(coder)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def encode_with(coder)
|
35
|
+
coder.send("#{type.to_sym}=", value)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def initialize(type, value)
|
41
|
+
@type = type
|
42
|
+
@value = value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module CloudCompose
|
4
|
+
module Tags
|
5
|
+
class GetAtt < Base
|
6
|
+
def type_from_coder(_coder)
|
7
|
+
:seq
|
8
|
+
end
|
9
|
+
|
10
|
+
def value_from_coder(coder)
|
11
|
+
case coder.type
|
12
|
+
when :seq
|
13
|
+
coder.seq
|
14
|
+
when :scalar
|
15
|
+
coder.scalar.split('.', 2)
|
16
|
+
else
|
17
|
+
raise InvalidTypeError.new(coder.tag, coder.type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module CloudCompose
|
4
|
+
module Tags
|
5
|
+
class MapType < Base
|
6
|
+
def value_from_coder(coder)
|
7
|
+
case coder.type
|
8
|
+
when :map
|
9
|
+
coder.map
|
10
|
+
else
|
11
|
+
raise InvalidTypeError.new(coder.tag, coder.type)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module CloudCompose
|
4
|
+
module Tags
|
5
|
+
class ScalarType < Base
|
6
|
+
def value_from_coder(coder)
|
7
|
+
case coder.type
|
8
|
+
when :scalar
|
9
|
+
coder.scalar
|
10
|
+
else
|
11
|
+
raise InvalidTypeError.new(coder.tag, coder.type)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module CloudCompose
|
4
|
+
module Tags
|
5
|
+
class SequencedType < Base
|
6
|
+
def value_from_coder(coder)
|
7
|
+
case coder.type
|
8
|
+
when :seq
|
9
|
+
coder.seq
|
10
|
+
else
|
11
|
+
raise InvalidTypeError.new(coder.tag, coder.type)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'map_type'
|
2
|
+
require_relative 'scalar_type'
|
3
|
+
require_relative 'sequenced_type'
|
4
|
+
|
5
|
+
module CloudCompose
|
6
|
+
module Tags
|
7
|
+
class And < SequencedType; end
|
8
|
+
class Base64 < ScalarType; end
|
9
|
+
class Cidr < SequencedType; end
|
10
|
+
class Condition < ScalarType; end
|
11
|
+
class Equals < SequencedType; end
|
12
|
+
class FindInMap < SequencedType; end
|
13
|
+
class GetAzs < ScalarType; end
|
14
|
+
class If < SequencedType; end
|
15
|
+
class ImportValue < ScalarType; end
|
16
|
+
class Join < SequencedType; end
|
17
|
+
class Not < SequencedType; end
|
18
|
+
class Or < SequencedType; end
|
19
|
+
class Ref < ScalarType; end
|
20
|
+
class Select < SequencedType; end
|
21
|
+
class Split < SequencedType; end
|
22
|
+
class Transform < MapType; end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module CloudCompose
|
4
|
+
module Tags
|
5
|
+
class Sub < Base
|
6
|
+
def type_from_coder(_coder)
|
7
|
+
:seq
|
8
|
+
end
|
9
|
+
|
10
|
+
def value_from_coder(coder)
|
11
|
+
case coder.type
|
12
|
+
when :seq
|
13
|
+
seq = coder.seq.dup
|
14
|
+
seq.fill({}, seq.length...2)
|
15
|
+
when :scalar
|
16
|
+
[coder.scalar, {}]
|
17
|
+
else
|
18
|
+
raise InvalidTypeError.new(coder.tag, coder.type)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'time'
|
3
|
+
require 'digest'
|
4
|
+
|
5
|
+
require_relative 'parser'
|
6
|
+
require_relative 'config'
|
7
|
+
require_relative 'processor'
|
8
|
+
|
9
|
+
module CloudCompose
|
10
|
+
class Template
|
11
|
+
IMPORT_MERGE_KEYS = %w[
|
12
|
+
Metadata
|
13
|
+
Parameters
|
14
|
+
Mappings
|
15
|
+
Conditions
|
16
|
+
Transform
|
17
|
+
Resources
|
18
|
+
Outputs
|
19
|
+
].freeze
|
20
|
+
|
21
|
+
class Error < StandardError; end
|
22
|
+
|
23
|
+
Partial = Struct.new(:name, :template, :parameters) do
|
24
|
+
def context
|
25
|
+
Hash(parameters).merge('name' => name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :root, :config, :content, :file_name
|
30
|
+
|
31
|
+
def initialize(path, pwd)
|
32
|
+
@pwd = pwd
|
33
|
+
@file_name = File.basename(path)
|
34
|
+
@root = Pathname.new(File.dirname(path))
|
35
|
+
content = File.read(path)
|
36
|
+
@checksum = Digest::SHA256.hexdigest(content)
|
37
|
+
parts = content.split(/^---/, 3)
|
38
|
+
@config = CloudCompose::Config.new(parts[1], @root)
|
39
|
+
@content = parts[2]
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_h
|
43
|
+
template_body = create_hash(parameters)
|
44
|
+
imported.each do |imp|
|
45
|
+
formatted_imp = imp.template.send(:create_hash, imp.context)
|
46
|
+
merge_imported(template_body, formatted_imp, imp.name)
|
47
|
+
end
|
48
|
+
|
49
|
+
template_body.keys.each do |key|
|
50
|
+
template_body.delete(key) if template_body[key].empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
template_body
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
yaml = CloudCompose::Parser.dump_yaml(to_h)
|
58
|
+
|
59
|
+
<<~EOF
|
60
|
+
# This Template was generated on #{Time.now.utc.iso8601} by CloudCompose #{CloudCompose::VERSION}
|
61
|
+
#
|
62
|
+
# Structure
|
63
|
+
#{description(0)}
|
64
|
+
#
|
65
|
+
# Integrity
|
66
|
+
#{checksum_print}
|
67
|
+
#
|
68
|
+
#{yaml}
|
69
|
+
EOF
|
70
|
+
end
|
71
|
+
|
72
|
+
def imported
|
73
|
+
preload_imports!
|
74
|
+
@imported
|
75
|
+
end
|
76
|
+
|
77
|
+
def parameters
|
78
|
+
@config.parameters
|
79
|
+
end
|
80
|
+
|
81
|
+
def required_parameters
|
82
|
+
@config.required_parameters
|
83
|
+
end
|
84
|
+
|
85
|
+
def description(depth)
|
86
|
+
callouts = depth.zero? ? '├─' : '↳'
|
87
|
+
leading = depth.zero? ? '' : '|'
|
88
|
+
padding = ' ' * depth
|
89
|
+
joined = imported.map { |i| i.template.description(depth + 2) }
|
90
|
+
[
|
91
|
+
"# #{leading}#{padding}#{callouts} #{working_path}/#{file_name}",
|
92
|
+
*joined
|
93
|
+
].join("\n")
|
94
|
+
end
|
95
|
+
|
96
|
+
def checksums
|
97
|
+
return @checksums if @checksums
|
98
|
+
|
99
|
+
checksums = {}
|
100
|
+
checksums["#{working_path}/#{file_name}"] = @checksum
|
101
|
+
imported.each do |imp|
|
102
|
+
imp.template.checksums.each do |key, value|
|
103
|
+
checksums[key] = value
|
104
|
+
end
|
105
|
+
end
|
106
|
+
@checksums = checksums
|
107
|
+
@checksums
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def checksum_print
|
113
|
+
checksums.keys.sort.map do |key|
|
114
|
+
"# #{checksums[key]} ✓ #{key}"
|
115
|
+
end.join("\n")
|
116
|
+
end
|
117
|
+
|
118
|
+
def working_path
|
119
|
+
root.to_s.gsub("#{@pwd}/", '')
|
120
|
+
end
|
121
|
+
|
122
|
+
def merge_imported(body, imported, name)
|
123
|
+
IMPORT_MERGE_KEYS.each do |merge_key|
|
124
|
+
current = body.fetch(merge_key, {})
|
125
|
+
imported_current = imported.fetch(merge_key, {})
|
126
|
+
imported_current.keys.each do |merging|
|
127
|
+
next unless current.key?(merging)
|
128
|
+
|
129
|
+
raise Error, "Template #{file_name} already contains a key #{merge_key}.#{merging}. Merging from #{name}"
|
130
|
+
end
|
131
|
+
body[merge_key] = current.merge(imported_current)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def create_hash(context)
|
136
|
+
CloudCompose::Parser.load_yaml(
|
137
|
+
CloudCompose::Processor.preprocess(content, context)
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def preload_imports!
|
142
|
+
return if defined?(@imported)
|
143
|
+
|
144
|
+
@imported = @config.imports.map do |imported|
|
145
|
+
create_template(imported)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def validate_parameters!(imported, full_params, required)
|
150
|
+
required.each do |key|
|
151
|
+
next if full_params.key?(key)
|
152
|
+
|
153
|
+
raise Error, "Missing Required Parameter #{key} in #{imported.name}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def create_template(imported)
|
158
|
+
template = CloudCompose::Template.new(imported.path, @pwd)
|
159
|
+
raise Error, "Template #{File.basename(imported.path)} imported from #{@file_name} is not a partial" unless template.config.partial?
|
160
|
+
|
161
|
+
full_params = parameters.merge(imported.parameters).merge(template.parameters)
|
162
|
+
|
163
|
+
validate_parameters!(imported, full_params, template.required_parameters)
|
164
|
+
|
165
|
+
Partial.new(
|
166
|
+
imported.name,
|
167
|
+
template,
|
168
|
+
full_params
|
169
|
+
)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloud_compose
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Maddie Schipper
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.8'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.8'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.16'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.16'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.9'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.9'
|
97
|
+
description: ''
|
98
|
+
email:
|
99
|
+
- me@maddiesch.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- lib/cloud_compose.rb
|
107
|
+
- lib/cloud_compose/config.rb
|
108
|
+
- lib/cloud_compose/parser.rb
|
109
|
+
- lib/cloud_compose/processor.rb
|
110
|
+
- lib/cloud_compose/tags/base.rb
|
111
|
+
- lib/cloud_compose/tags/get_att.rb
|
112
|
+
- lib/cloud_compose/tags/map_type.rb
|
113
|
+
- lib/cloud_compose/tags/scalar_type.rb
|
114
|
+
- lib/cloud_compose/tags/sequenced_type.rb
|
115
|
+
- lib/cloud_compose/tags/simple_type.rb
|
116
|
+
- lib/cloud_compose/tags/sub.rb
|
117
|
+
- lib/cloud_compose/template.rb
|
118
|
+
- lib/cloud_compose/version.rb
|
119
|
+
homepage: ''
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
metadata: {}
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubygems_version: 3.0.3
|
139
|
+
signing_key:
|
140
|
+
specification_version: 4
|
141
|
+
summary: ''
|
142
|
+
test_files: []
|