chemtrail 0.1.0 → 0.2.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 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