chemtrail 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b55d85bd6bb36bc1f6b169a3806544b9df96db28
4
- data.tar.gz: 1f2537d1b31d10f54e32d3d2391d64f774939ec8
3
+ metadata.gz: e54ce07e90240967020fa7a8dc856b944338f78e
4
+ data.tar.gz: 132975f191f9df48d66606e27648852cb29a8608
5
5
  SHA512:
6
- metadata.gz: 27c03f23e82d4429bee7cac5ccb464e408ba7b6a6d7d146bfde9c46557785e677509c66757162317a31bbc55926b138ea075f1e513f3ab54fb54ad4f953362d5
7
- data.tar.gz: 312879ef2f152e0b9a92eaf5f28bb874065749cb20ff2808e219421da935b77b7d1767663053eab9125c0e0061a89afdc50f5f13ed097ab8bd5b5a90dd9f2806
6
+ metadata.gz: 0cd2a647db49fb8ecef0863955670ea9dadbec2087e68a561376fbd2c4ca5ea3e55eb883fa404a8d17e2f1b180c5dfbc12d49e42b6d1f5d87e88bdf37f541c25
7
+ data.tar.gz: 22f400b9b20b389bec87ba1951f374cb37cd16a5c72359c8debe4913db6d7528cd3106477fb9ea659873cee5d270d06bd9a18d757a6e6155f2dbf57a73a078d0
data/bin/chemtrail ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path("../../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "chemtrail"
5
+ require "chemtrail/cli"
6
+ Chemtrail::Cli.start
@@ -0,0 +1,14 @@
1
+ class Chemtrail::ClassNameInflector
2
+ attr_reader :class_name
3
+
4
+ def initialize(class_name)
5
+ @class_name = class_name.to_s.dup
6
+ end
7
+
8
+ def underscore
9
+ class_name.gsub(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
10
+ .gsub(/([a-z\d])([A-Z])/,'\1_\2')
11
+ .gsub(/::/,':')
12
+ .downcase
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ require "thor"
2
+ require "json"
3
+
4
+ class Chemtrail::Cli < Thor
5
+ default_task :list
6
+
7
+ desc "list", "Lists all available templates"
8
+ method_option :path, :default => File.expand_path("lib/templates")
9
+ def list
10
+ require_templates_from(options[:path])
11
+ Chemtrail::Template.subclass_map.keys.each { |k| Kernel.puts(k) }
12
+ end
13
+
14
+ desc "build TEMPLATE", "Builds the selected template"
15
+ method_option :path, :default => File.expand_path("lib/templates")
16
+ def build(template_name)
17
+ require_templates_from(options[:path])
18
+ template_class = fetch_template_class_named(template_name)
19
+ template_json = JSON.pretty_generate(template_class.new.to_hash)
20
+ Kernel.puts(template_json)
21
+ end
22
+
23
+ protected
24
+
25
+ def require_templates_from(path)
26
+ Dir.glob(File.expand_path("**/*_template.rb", path)).each { |t| require t }
27
+ end
28
+
29
+ def fetch_template_class_named(name)
30
+ template = Chemtrail::Template.subclass_map[name]
31
+ raise Thor::Error.new("Template #{name} does not exist") if template.nil?
32
+ template
33
+ end
34
+ end
@@ -12,13 +12,7 @@ class Chemtrail::Mapping
12
12
  end
13
13
 
14
14
  def find(top_level, second_level)
15
- {
16
- "Fn::FindInMap" => [
17
- id,
18
- Chemtrail::ReferencePresenter.new(top_level).to_parameter,
19
- Chemtrail::ReferencePresenter.new(second_level).to_parameter
20
- ]
21
- }
15
+ Chemtrail::Function.new("Fn::FindInMap", id, top_level, second_level).to_hash
22
16
  end
23
17
 
24
18
  def to_hash
@@ -12,11 +12,9 @@ class Chemtrail::Output
12
12
  end
13
13
 
14
14
  def description_hash
15
- if description.nil?
16
- {}
17
- else
18
- {"Description" => description}
19
- end
15
+ hash = {}
16
+ hash["Description"] = description unless description.nil?
17
+ hash
20
18
  end
21
19
 
22
20
  def to_hash
@@ -1,4 +1,4 @@
1
- class Chemtrail::Declaration
1
+ class Chemtrail::Parameter
2
2
  attr_reader :id, :type
3
3
 
4
4
  def initialize(id, type, specifications = {})
@@ -0,0 +1,16 @@
1
+ class Chemtrail::SectionPresenter
2
+ attr_reader :name, :entries
3
+
4
+ def initialize(name, entries)
5
+ @name = name
6
+ @entries = entries
7
+ end
8
+
9
+ def to_hash
10
+ if entries.empty?
11
+ {}
12
+ else
13
+ {name => entries.map(&:to_hash).reduce(Hash.new, :merge)}
14
+ end
15
+ end
16
+ end
@@ -1,36 +1,69 @@
1
- require "chemtrail/section"
1
+ require "chemtrail/section_presenter"
2
+ require "chemtrail/class_name_inflector"
2
3
 
3
4
  class Chemtrail::Template
5
+ class << self
6
+ def subclass_map
7
+ @subclass_map ||= {}
8
+ end
9
+
10
+ def inherited(subclass)
11
+ subclass_map[Chemtrail::ClassNameInflector.new(subclass).underscore] = subclass
12
+ end
13
+ end
14
+
4
15
  attr_reader :description
5
16
 
6
- def initialize(description)
17
+ def initialize(description = nil)
7
18
  @description = description
8
19
  end
9
20
 
10
21
  def parameters
11
- @parameters ||= Chemtrail::Section.new
22
+ []
12
23
  end
13
24
 
14
25
  def mappings
15
- @mappings ||= Chemtrail::Section.new
26
+ []
16
27
  end
17
28
 
18
29
  def resources
19
- @resources ||= Chemtrail::Section.new
30
+ []
20
31
  end
21
32
 
22
33
  def outputs
23
- @outputs ||= Chemtrail::Section.new
34
+ []
24
35
  end
25
36
 
26
37
  def to_hash
27
- {
28
- "AWSTemplateFormatVersion" => "2010-09-09",
29
- "Description" => description,
30
- "Parameters" => parameters.to_hash,
31
- "Mappings" => mappings.to_hash,
32
- "Resources" => resources.to_hash,
33
- "Outputs" => outputs.to_hash
34
- }
38
+ version_hash = {"AWSTemplateFormatVersion" => "2010-09-09"}
39
+ version_hash.merge(description_hash)
40
+ .merge(parameters_hash)
41
+ .merge(mappings_hash)
42
+ .merge(resources_hash)
43
+ .merge(outputs_hash)
44
+ end
45
+
46
+ protected
47
+
48
+ def description_hash
49
+ hash = {}
50
+ hash["Description"] = description unless description.nil?
51
+ hash
52
+ end
53
+
54
+ def parameters_hash
55
+ Chemtrail::SectionPresenter.new("Parameters", parameters).to_hash
56
+ end
57
+
58
+ def mappings_hash
59
+ Chemtrail::SectionPresenter.new("Mappings", mappings).to_hash
60
+ end
61
+
62
+ def resources_hash
63
+ Chemtrail::SectionPresenter.new("Resources", resources).to_hash
64
+ end
65
+
66
+ def outputs_hash
67
+ Chemtrail::SectionPresenter.new("Outputs", outputs).to_hash
35
68
  end
36
69
  end
@@ -1,3 +1,3 @@
1
1
  module Chemtrail
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/chemtrail.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require "chemtrail/version"
2
2
  require "chemtrail/template"
3
- require "chemtrail/declaration"
3
+ require "chemtrail/parameter"
4
4
  require "chemtrail/mapping"
5
5
  require "chemtrail/resource"
6
6
  require "chemtrail/output"
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+
3
+ describe Chemtrail::ClassNameInflector do
4
+ subject(:inflector) { Chemtrail::ClassNameInflector.new(class_name) }
5
+
6
+ describe "#underscore" do
7
+ context "with a normal name" do
8
+ let(:class_name) { "Tacos" }
9
+
10
+ its(:underscore) { should == "tacos" }
11
+ end
12
+
13
+ context "with a normal camelcase name" do
14
+ let(:class_name) { "ZapZap" }
15
+
16
+ its(:underscore) { should == "zap_zap" }
17
+ end
18
+
19
+ context "with a slightly abnormal camelcase name" do
20
+ let(:class_name) { "DSLAreGreat" }
21
+
22
+ its(:underscore) { should == "dsl_are_great" }
23
+ end
24
+
25
+ context "with a namespace" do
26
+ let(:class_name) { "Geese::Adorable" }
27
+
28
+ its(:underscore) { should == "geese:adorable" }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ describe Chemtrail::Cli do
4
+ subject(:cli) { Chemtrail::Cli.new }
5
+
6
+ describe "#list" do
7
+ it "lists available templates" do
8
+ Kernel.should_receive(:puts).with("tacos")
9
+ cli.list
10
+ end
11
+ end
12
+
13
+ describe "#build" do
14
+ it "builds the specified template" do
15
+ Kernel.should_receive(:puts).with(JSON.pretty_generate(Tacos.new.to_hash))
16
+ cli.build("tacos")
17
+ end
18
+
19
+ context "when the template does not exist" do
20
+ it "blows up" do
21
+ expect { cli.build("house of cards") }.to raise_error(Thor::Error)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Chemtrail::Declaration do
4
- subject(:declaration) { Chemtrail::Declaration.new("parmesan", "String") }
3
+ describe Chemtrail::Parameter do
4
+ subject(:parameter) { Chemtrail::Parameter.new("parmesan", "String") }
5
5
 
6
6
  describe "#specifications" do
7
7
  context "when there are no specifications" do
@@ -9,7 +9,7 @@ describe Chemtrail::Declaration do
9
9
  end
10
10
 
11
11
  context "when a specification has been passed into the initializer" do
12
- subject(:declaration) { Chemtrail::Declaration.new("parmesan", "String", ok: "great") }
12
+ subject(:parameter) { Chemtrail::Parameter.new("parmesan", "String", ok: "great") }
13
13
 
14
14
  its(:specifications) { should == {ok: "great"} }
15
15
  end
@@ -21,12 +21,12 @@ describe Chemtrail::Declaration do
21
21
 
22
22
  describe "#to_hash" do
23
23
  its(:to_hash) { should have_key "parmesan" }
24
- specify { declaration.to_hash["parmesan"].should include("Type" => "String") }
24
+ specify { parameter.to_hash["parmesan"].should include("Type" => "String") }
25
25
 
26
26
  context "when there is a specification" do
27
- before { declaration.specifications[:ducks] = "amazing" }
27
+ before { parameter.specifications[:ducks] = "amazing" }
28
28
 
29
- specify { declaration.to_hash["parmesan"].should include(ducks: "amazing") }
29
+ specify { parameter.to_hash["parmesan"].should include(ducks: "amazing") }
30
30
  end
31
31
  end
32
32
  end
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe Chemtrail::SectionPresenter do
4
+ let(:entry) { double(:entry, to_hash: {tacos: "great"}) }
5
+ let(:entries) { [] }
6
+
7
+ subject(:section) { Chemtrail::SectionPresenter.new("Socks", entries) }
8
+
9
+ describe "#to_hash" do
10
+ context "when there are no entries" do
11
+ let(:entries) { [] }
12
+
13
+ its(:to_hash) { should == {} }
14
+ end
15
+
16
+ context "when there is an entry" do
17
+ let(:entries) { [entry] }
18
+
19
+ its(:to_hash) { should == {"Socks" => {tacos: "great"}} }
20
+ end
21
+ end
22
+ end
@@ -6,86 +6,75 @@ describe Chemtrail::Template do
6
6
  let(:fake_parameter) { double(:parameter, to_hash: {"parameter" => "json"}) }
7
7
  let(:fake_resource) { double(:resource, to_hash: {"resource" => "json"}) }
8
8
 
9
- subject(:template) { Chemtrail::Template.new("wat") }
9
+ subject(:template) { Chemtrail::Template.new }
10
10
 
11
- describe "#parameters" do
12
- context "when the template has parameters" do
13
- before { template.parameters << fake_parameter }
14
-
15
- its(:parameters) { should =~ [fake_parameter] }
16
- end
17
-
18
- context "when the template does not have parameters" do
19
- its(:parameters) { should be_empty }
20
- end
21
- end
22
-
23
- describe "#mappings" do
24
- context "when the template has mappings" do
25
- before { template.mappings << fake_mapping }
26
-
27
- its(:mappings) { should == [fake_mapping] }
28
- end
29
-
30
- context "when the template does not have mappings" do
31
- its(:mappings) { should be_empty }
32
- end
33
- end
34
-
35
- describe "#resources" do
36
- context "when the template has resources" do
37
- before { template.resources << fake_resource }
38
-
39
- its(:resources) { should == [fake_resource] }
40
- end
11
+ describe "#to_hash" do
12
+ its(:to_hash) { should include("AWSTemplateFormatVersion" => "2010-09-09") }
13
+ its(:to_hash) { should_not have_key "Parameters" }
14
+ its(:to_hash) { should_not have_key "Mappings" }
15
+ its(:to_hash) { should_not have_key "Resources" }
16
+ its(:to_hash) { should_not have_key "Outputs" }
41
17
 
42
- context "when the template does not have resources" do
43
- its(:resources) { should be_empty }
18
+ context "when the description is not set" do
19
+ its(:to_hash) { should_not have_key "Description" }
44
20
  end
45
- end
46
21
 
47
- describe "#outputs" do
48
- context "when the template has outputs" do
49
- before { template.outputs << fake_output }
50
-
51
- its(:outputs) { should == [fake_output] }
52
- end
22
+ context "when the description is set" do
23
+ subject(:template) { Chemtrail::Template.new("super great") }
53
24
 
54
- context "when the template does not have outputs" do
55
- its(:outputs) { should be_empty }
25
+ its(:to_hash) { should include("Description" => "super great") }
56
26
  end
57
- end
58
-
59
- describe "#to_hash" do
60
- its(:to_hash) { should include("AWSTemplateFormatVersion" => "2010-09-09") }
61
- its(:to_hash) { should include("Description" => "wat") }
62
- its(:to_hash) { should have_key "Parameters" }
63
- its(:to_hash) { should have_key "Mappings" }
64
- its(:to_hash) { should have_key "Resources" }
65
- its(:to_hash) { should have_key "Outputs" }
66
27
 
67
28
  context "when the template has parameters" do
68
- before { template.parameters << fake_parameter }
29
+ before { template.stub(parameters: [fake_parameter]) }
69
30
 
70
31
  its(:to_hash) { should include("Parameters" => {"parameter" => "json"}) }
71
32
  end
72
33
 
73
34
  context "when the template has mappings" do
74
- before { template.mappings << fake_mapping }
35
+ before { template.stub(mappings: [fake_mapping]) }
75
36
 
76
37
  its(:to_hash) { should include("Mappings" => {"mapping" => "json"}) }
77
38
  end
78
39
 
79
40
  context "when the template has resources" do
80
- before { template.resources << fake_resource }
41
+ before { template.stub(resources: [fake_resource]) }
81
42
 
82
43
  its(:to_hash) { should include("Resources" => {"resource" => "json"}) }
83
44
  end
84
45
 
85
46
  context "when the template has outputs" do
86
- before { template.outputs << fake_output }
47
+ before { template.stub(outputs: [fake_output]) }
87
48
 
88
49
  its(:to_hash) { should include("Outputs" => {"output" => "json"}) }
89
50
  end
90
51
  end
52
+
53
+ describe ".inherited" do
54
+ before { Chemtrail::Template.stub(subclass_map: {}) }
55
+
56
+ it "adds subclasses to the template map" do
57
+ expect {
58
+ Chemtrail::Template.send(:inherited, Object)
59
+ }.to change {
60
+ Chemtrail::Template.subclass_map
61
+ }.from({}).to("object" => Object)
62
+ end
63
+
64
+ it "adds namespaced subclasses to the template map" do
65
+ expect {
66
+ Chemtrail::Template.send(:inherited, Chemtrail::Template)
67
+ }.to change {
68
+ Chemtrail::Template.subclass_map
69
+ }.from({}).to("chemtrail:template" => Chemtrail::Template)
70
+ end
71
+
72
+ it "adds camelcased subclasses to the template map as snakecase" do
73
+ expect {
74
+ Chemtrail::Template.send(:inherited, Chemtrail::PropertyList)
75
+ }.to change {
76
+ Chemtrail::Template.subclass_map
77
+ }.from({}).to("chemtrail:property_list" => Chemtrail::PropertyList)
78
+ end
79
+ end
91
80
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  require "chemtrail"
2
+ require "chemtrail/cli"
3
+
4
+ Dir.glob(File.expand_path("../support/**/*.rb", __FILE__)).each { |f| require f }
2
5
 
3
6
  RSpec.configure do |config|
4
7
  config.treat_symbols_as_metadata_keys_with_true_values = true
@@ -0,0 +1,2 @@
1
+ class Tacos < Chemtrail::Template
2
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chemtrail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doc Ritezel
@@ -83,7 +83,8 @@ dependencies:
83
83
  description: Seed your CloudFormation stack
84
84
  email:
85
85
  - pair+doc@ministryofvelocity.com
86
- executables: []
86
+ executables:
87
+ - chemtrail
87
88
  extensions: []
88
89
  extra_rdoc_files: []
89
90
  files:
@@ -96,29 +97,35 @@ files:
96
97
  - Guardfile
97
98
  - LICENSE.txt
98
99
  - README.md
100
+ - bin/chemtrail
99
101
  - chemtrail.gemspec
100
102
  - lib/chemtrail.rb
101
- - lib/chemtrail/declaration.rb
103
+ - lib/chemtrail/class_name_inflector.rb
104
+ - lib/chemtrail/cli.rb
102
105
  - lib/chemtrail/function.rb
103
106
  - lib/chemtrail/mapping.rb
104
107
  - lib/chemtrail/output.rb
108
+ - lib/chemtrail/parameter.rb
105
109
  - lib/chemtrail/property_list.rb
106
110
  - lib/chemtrail/reference_presenter.rb
107
111
  - lib/chemtrail/resource.rb
108
- - lib/chemtrail/section.rb
112
+ - lib/chemtrail/section_presenter.rb
109
113
  - lib/chemtrail/template.rb
110
114
  - lib/chemtrail/version.rb
111
115
  - script/ci.sh
112
- - spec/lib/chemtrail/declaration_spec.rb
116
+ - spec/lib/chemtrail/class_name_inflector_spec.rb
117
+ - spec/lib/chemtrail/cli_spec.rb
113
118
  - spec/lib/chemtrail/function_spec.rb
114
119
  - spec/lib/chemtrail/mapping_spec.rb
115
120
  - spec/lib/chemtrail/output_spec.rb
121
+ - spec/lib/chemtrail/parameter_spec.rb
116
122
  - spec/lib/chemtrail/property_list_spec.rb
117
123
  - spec/lib/chemtrail/reference_presenter_spec.rb
118
124
  - spec/lib/chemtrail/resource_spec.rb
119
- - spec/lib/chemtrail/section_spec.rb
125
+ - spec/lib/chemtrail/section_presenter_spec.rb
120
126
  - spec/lib/chemtrail/template_spec.rb
121
127
  - spec/spec_helper.rb
128
+ - spec/support/fixtures/fixture_template.rb
122
129
  homepage: https://github.com/minifast/chemtrail
123
130
  licenses:
124
131
  - MIT
@@ -144,13 +151,16 @@ signing_key:
144
151
  specification_version: 4
145
152
  summary: Build, create and maintain your CloudFormation stack
146
153
  test_files:
147
- - spec/lib/chemtrail/declaration_spec.rb
154
+ - spec/lib/chemtrail/class_name_inflector_spec.rb
155
+ - spec/lib/chemtrail/cli_spec.rb
148
156
  - spec/lib/chemtrail/function_spec.rb
149
157
  - spec/lib/chemtrail/mapping_spec.rb
150
158
  - spec/lib/chemtrail/output_spec.rb
159
+ - spec/lib/chemtrail/parameter_spec.rb
151
160
  - spec/lib/chemtrail/property_list_spec.rb
152
161
  - spec/lib/chemtrail/reference_presenter_spec.rb
153
162
  - spec/lib/chemtrail/resource_spec.rb
154
- - spec/lib/chemtrail/section_spec.rb
163
+ - spec/lib/chemtrail/section_presenter_spec.rb
155
164
  - spec/lib/chemtrail/template_spec.rb
156
165
  - spec/spec_helper.rb
166
+ - spec/support/fixtures/fixture_template.rb
@@ -1,5 +0,0 @@
1
- class Chemtrail::Section < Array
2
- def to_hash
3
- map(&:to_hash).reduce(Hash.new, :merge)
4
- end
5
- end
@@ -1,13 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Chemtrail::Section do
4
- let(:entry) { double(:entry, to_hash: {tacos: "great"}) }
5
-
6
- subject(:section) { Chemtrail::Section.new }
7
-
8
- describe "#to_hash" do
9
- before { section << entry }
10
-
11
- its(:to_hash) { should == {tacos: "great"} }
12
- end
13
- end