cloud_compose 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/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: []
|