rubycfn 0.4.3 → 0.4.4

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: a68bc5a68e2c5d5e17afd182cc6584ecd7cbd2a0
4
- data.tar.gz: 8ea2e232f188466493fc1549a1bd4df5940b0d00
3
+ metadata.gz: ad6c0ee3940074c02e77ec200940b30cd04c88a9
4
+ data.tar.gz: 02df17c17bfb5d0a27065fa3507309426cd11fe0
5
5
  SHA512:
6
- metadata.gz: adb271c31360abcbb0526ecb9b967ff519aec21ba6a8f1cefb2f9405e4a468e2be8f3ed983e3b8b73ffa363fdf8a53c10b5939fb0510a13b6fbf93781534a332
7
- data.tar.gz: 93dcf56467cc1b90e6b6912488111b41b4d0e5f4203adef9ea02ff3656317566747665363f6a51801297302c50e221086de58182762cc310a0233918b3abb5f6
6
+ metadata.gz: 00960d82e125677be467a2578c08bbeb0396530d8e3d9c058398f30580886c98a2f0a8985cee19292bcd30f8e430856ce982a10cce5d25d8381997df6268ff7d
7
+ data.tar.gz: a3161e628b18490ac66aa330d6cc41ec3c4de798a68e5b350483f253e2452fdd6a9a02d54f197725b33223e0caa6093407dd27029762a047e672c4fab4d703d4
data/.rubocop.yml CHANGED
@@ -20,6 +20,9 @@ Metrics/AbcSize:
20
20
  - "test/**/*"
21
21
  - "spec/**/*"
22
22
 
23
+ Metrics/BlockNesting:
24
+ Enabled: false
25
+
23
26
  Metrics/ClassLength:
24
27
  Max: 500
25
28
  Exclude:
data/CHANGELOG.md CHANGED
@@ -2,7 +2,11 @@
2
2
  All notable changes to Rubycfn will be documented in this file.
3
3
  This project uses [Semantic Versioning](http://semver.org/).
4
4
 
5
- ## 0.4.4 (Next Release)
5
+ ## 0.4.5 (Next Release)
6
+
7
+ ## 0.4.4
8
+
9
+ * Added autocorrection to property names so that developers won't have to think about camel casing -- [@dennisvink][@dennisvink]
6
10
 
7
11
  ## 0.4.3
8
12
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubycfn (0.4.3)
4
+ rubycfn (0.4.4)
5
5
  activesupport (~> 5.1.5)
6
6
  dotenv (~> 2.4.0)
7
7
  json (~> 2.1.0)
data/README.md CHANGED
@@ -61,7 +61,7 @@ __________ ____ __________________.___._________ _____________________
61
61
  | _/ | /| | _// | |/ \ \/ | __) | | _/
62
62
  | | \ | / | | \\____ |\ \____| \ | | \
63
63
  |____|_ /______/ |______ // ______| \______ /\___ / |______ /
64
- \/ \/ \/ \/ \/ \/ [v0.4.3]
64
+ \/ \/ \/ \/ \/ \/ [v0.4.4]
65
65
  Project name? example
66
66
  Account ID? 1234567890
67
67
  Select region EU (Frankfurt)
@@ -0,0 +1,206 @@
1
+ class Symbol
2
+ def cfnize
3
+ return self.to_s if self.to_s !~ /_/ && self.to_s =~ /[A-Z]+.*/
4
+ to_s.split("_").map(&:capitalize).join
5
+ end
6
+
7
+ def ref(attr = nil)
8
+ unless attr
9
+ return { Ref: to_s.split("_").map(&:capitalize).join }
10
+ end
11
+ attr = attr.class == String ? attr : attr.to_s.split("_").map(&:capitalize).join
12
+ {
13
+ "Fn::GetAtt": [
14
+ to_s.split("_").map(&:capitalize).join, attr
15
+ ]
16
+ }
17
+ end
18
+
19
+ def fntransform(parameters = nil)
20
+ raise "fntransform parameters must be of type Hash" unless parameters.class == Hash
21
+ {
22
+ "Fn::Transform": {
23
+ "Name": to_s.split("_").map(&:capitalize).join,
24
+ "Parameters": parameters
25
+ }
26
+ }
27
+ end
28
+ end
29
+
30
+ class Hash
31
+ def fnsplit(separator = "")
32
+ {
33
+ "Fn::Split": [
34
+ separator,
35
+ self
36
+ ]
37
+ }
38
+ end
39
+ end
40
+
41
+ class String
42
+ def cfnize
43
+ return self if self !~ /_/ && self =~ /[A-Z]+.*/
44
+ split("_").map(&:capitalize).join
45
+ end
46
+
47
+ def ref(attr = nil)
48
+ unless attr
49
+ return { Ref: self }
50
+ end
51
+ attr = attr.class == String ? attr : attr.to_s.split("_").map(&:capitalize).join
52
+ {
53
+ "Fn::GetAtt": [
54
+ self,
55
+ attr
56
+ ]
57
+ }
58
+ end
59
+
60
+ def fntransform(parameters = nil)
61
+ raise "fntransform parameters must be of type Hash" unless parameters.class == Hash
62
+ {
63
+ "Fn::Transform": {
64
+ "Name": self,
65
+ "Parameters": parameters
66
+ }
67
+ }
68
+ end
69
+
70
+ def fnsplit(separator = "")
71
+ {
72
+ "Fn::Split": [
73
+ separator,
74
+ self
75
+ ]
76
+ }
77
+ end
78
+
79
+ def fnbase64
80
+ {
81
+ "Fn::Base64": self
82
+ }
83
+ end
84
+
85
+ def fngetazs
86
+ {
87
+ "Fn::GetAZs": self
88
+ }
89
+ end
90
+
91
+ def fnsub(variable_map = nil)
92
+ unless variable_map
93
+ return { "Fn::Sub": self }
94
+ end
95
+ {
96
+ "Fn::Sub": [
97
+ self,
98
+ variable_map
99
+ ]
100
+ }
101
+ end
102
+
103
+ def fnimportvalue
104
+ {
105
+ "Fn::Import": self
106
+ }
107
+ end
108
+ alias_method :fnimport, :fnimportvalue
109
+ end
110
+
111
+ class Array
112
+ def fncidr
113
+ {
114
+ "Fn::Cidr": self
115
+ }
116
+ end
117
+ alias_method :cidr, :fncidr
118
+
119
+ def fnequals
120
+ {
121
+ "Fn::Equals": self
122
+ }
123
+ end
124
+
125
+ def fnand
126
+ {
127
+ "Fn::And": self
128
+ }
129
+ end
130
+
131
+ def fnif
132
+ {
133
+ "Fn::If": self
134
+ }
135
+ end
136
+
137
+ def fnnot
138
+ {
139
+ "Fn::Not": self
140
+ }
141
+ end
142
+
143
+ def fnor
144
+ {
145
+ "Fn::Or": self
146
+ }
147
+ end
148
+
149
+ def fnfindinmap(name = nil)
150
+ unshift(name.cfnize) if name
151
+ {
152
+ "Fn::FindInMap": self
153
+ }
154
+ end
155
+ alias_method :find_in_map, :fnfindinmap
156
+ alias_method :findinmap, :fnfindinmap
157
+
158
+ def fnjoin(separator = "")
159
+ {
160
+ "Fn::Join": [
161
+ separator,
162
+ self
163
+ ]
164
+ }
165
+ end
166
+
167
+ def fnselect(index = 0)
168
+ {
169
+ "Fn::Select": [
170
+ index,
171
+ self
172
+ ]
173
+ }
174
+ end
175
+ end
176
+
177
+ class ::Hash
178
+ # rubocop:disable Style/CaseEquality
179
+ # rubocop:disable Lint/UnusedBlockArgument
180
+ def deep_merge(second)
181
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
182
+ self.merge(second.to_h, &merger)
183
+ end
184
+ # rubocop:enable Style/CaseEquality
185
+ # rubocop:enable Lint/UnusedBlockArgument
186
+
187
+ def recursive_compact
188
+ delete_if do |k, v|
189
+ next if v == false || k =~ /Fn\:/
190
+ (v.respond_to?(:empty?) ? v.empty? : !v) || v.instance_of?(Hash) && v.recursive_compact.empty?
191
+ end
192
+ end
193
+
194
+ def compact
195
+ delete_if { |_k, v| v.nil? }
196
+ end
197
+
198
+ def fnselect(index = 0)
199
+ {
200
+ "Fn::Select": [
201
+ index,
202
+ self
203
+ ]
204
+ }
205
+ end
206
+ end
@@ -1,4 +1,4 @@
1
1
  # Rubycfn version
2
2
  module Rubycfn
3
- VERSION = "0.4.3".freeze
3
+ VERSION = "0.4.4".freeze
4
4
  end
data/lib/rubycfn.rb CHANGED
@@ -3,6 +3,7 @@ require "active_support/concern"
3
3
  require "json"
4
4
  require "neatjson"
5
5
  require "rubycfn/version"
6
+ require_relative "monkeypatch"
6
7
 
7
8
  @description = ""
8
9
  @transform = ""
@@ -22,214 +23,6 @@ if File.file?("CloudFormationResourceSpecification.json")
22
23
  @resource_specification = JSON.parse(File.open("CloudFormationResourceSpecification.json").read)
23
24
  end
24
25
 
25
- # Monkey patching
26
- class Symbol
27
- def cfnize
28
- return self.to_s if self.to_s !~ /_/ && self.to_s =~ /[A-Z]+.*/
29
- to_s.split("_").map(&:capitalize).join
30
- end
31
-
32
- def ref(attr = nil)
33
- unless attr
34
- return { Ref: to_s.split("_").map(&:capitalize).join }
35
- end
36
- attr = attr.class == String ? attr : attr.to_s.split("_").map(&:capitalize).join
37
- {
38
- "Fn::GetAtt": [
39
- to_s.split("_").map(&:capitalize).join, attr
40
- ]
41
- }
42
- end
43
-
44
- def fntransform(parameters = nil)
45
- raise "fntransform parameters must be of type Hash" unless parameters.class == Hash
46
- {
47
- "Fn::Transform": {
48
- "Name": to_s.split("_").map(&:capitalize).join,
49
- "Parameters": parameters
50
- }
51
- }
52
- end
53
- end
54
-
55
- class Hash
56
- def fnsplit(separator = "")
57
- {
58
- "Fn::Split": [
59
- separator,
60
- self
61
- ]
62
- }
63
- end
64
- end
65
-
66
- class String
67
- def cfnize
68
- return self if self !~ /_/ && self =~ /[A-Z]+.*/
69
- split("_").map(&:capitalize).join
70
- end
71
-
72
- def ref(attr = nil)
73
- unless attr
74
- return { Ref: self }
75
- end
76
- attr = attr.class == String ? attr : attr.to_s.split("_").map(&:capitalize).join
77
- {
78
- "Fn::GetAtt": [
79
- self,
80
- attr
81
- ]
82
- }
83
- end
84
-
85
- def fntransform(parameters = nil)
86
- raise "fntransform parameters must be of type Hash" unless parameters.class == Hash
87
- {
88
- "Fn::Transform": {
89
- "Name": self,
90
- "Parameters": parameters
91
- }
92
- }
93
- end
94
-
95
- def fnsplit(separator = "")
96
- {
97
- "Fn::Split": [
98
- separator,
99
- self
100
- ]
101
- }
102
- end
103
-
104
- def fnbase64
105
- {
106
- "Fn::Base64": self
107
- }
108
- end
109
-
110
- def fngetazs
111
- {
112
- "Fn::GetAZs": self
113
- }
114
- end
115
-
116
- def fnsub(variable_map = nil)
117
- unless variable_map
118
- return { "Fn::Sub": self }
119
- end
120
- {
121
- "Fn::Sub": [
122
- self,
123
- variable_map
124
- ]
125
- }
126
- end
127
-
128
- def fnimportvalue
129
- {
130
- "Fn::Import": self
131
- }
132
- end
133
- alias_method :fnimport, :fnimportvalue
134
- end
135
-
136
- class Array
137
- def fncidr
138
- {
139
- "Fn::Cidr": self
140
- }
141
- end
142
- alias_method :cidr, :fncidr
143
-
144
- def fnequals
145
- {
146
- "Fn::Equals": self
147
- }
148
- end
149
-
150
- def fnand
151
- {
152
- "Fn::And": self
153
- }
154
- end
155
-
156
- def fnif
157
- {
158
- "Fn::If": self
159
- }
160
- end
161
-
162
- def fnnot
163
- {
164
- "Fn::Not": self
165
- }
166
- end
167
-
168
- def fnor
169
- {
170
- "Fn::Or": self
171
- }
172
- end
173
-
174
- def fnfindinmap(name = nil)
175
- unshift(name.cfnize) if name
176
- {
177
- "Fn::FindInMap": self
178
- }
179
- end
180
- alias_method :find_in_map, :fnfindinmap
181
- alias_method :findinmap, :fnfindinmap
182
-
183
- def fnjoin(separator = "")
184
- {
185
- "Fn::Join": [
186
- separator,
187
- self
188
- ]
189
- }
190
- end
191
-
192
- def fnselect(index = 0)
193
- {
194
- "Fn::Select": [
195
- index,
196
- self
197
- ]
198
- }
199
- end
200
- end
201
-
202
- class ::Hash
203
- # rubocop:disable Style/CaseEquality
204
- # rubocop:disable Lint/UnusedBlockArgument
205
- def deep_merge(second)
206
- merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
207
- self.merge(second.to_h, &merger)
208
- end
209
- # rubocop:enable Style/CaseEquality
210
- # rubocop:enable Lint/UnusedBlockArgument
211
-
212
- def recursive_compact
213
- delete_if do |k, v|
214
- next if v == false || k =~ /Fn\:/
215
- (v.respond_to?(:empty?) ? v.empty? : !v) || v.instance_of?(Hash) && v.recursive_compact.empty?
216
- end
217
- end
218
-
219
- def compact
220
- delete_if { |_k, v| v.nil? }
221
- end
222
-
223
- def fnselect(index = 0)
224
- {
225
- "Fn::Select": [
226
- index,
227
- self
228
- ]
229
- }
230
- end
231
- end
232
-
233
26
  module Rubycfn
234
27
  extend ActiveSupport::Concern
235
28
 
@@ -421,6 +214,8 @@ module Rubycfn
421
214
 
422
215
  arguments[:depends_on] ||= []
423
216
  rendered_depends_on = TOPLEVEL_BINDING.eval("@depends_on").nil? && arguments[:depends_on] || arguments[:depends_on] + TOPLEVEL_BINDING.eval("@depends_on")
217
+ rendered_properties = TOPLEVEL_BINDING.eval("@properties")
218
+ autocorrected_properties = {}
424
219
  if resource_specification["ResourceTypes"][arguments[:type].to_s]
425
220
  resource_specification = TOPLEVEL_BINDING.eval("@resource_specification")
426
221
  known_properties = resource_specification["ResourceTypes"][arguments[:type].to_s]["Properties"].keys
@@ -428,14 +223,23 @@ module Rubycfn
428
223
  known_properties.each do |prop|
429
224
  mandatory_properties.push(prop) if resource_specification["ResourceTypes"][arguments[:type].to_s]["Properties"][prop]["Required"] == true
430
225
  end
431
- TOPLEVEL_BINDING.eval("@properties").each do |k, _v|
226
+ rendered_properties.each do |k, v|
432
227
  unless known_properties.include? k.to_s
433
- TOPLEVEL_BINDING.eval("@depends_on = []")
434
- TOPLEVEL_BINDING.eval("@properties = {}")
435
- raise "Property `#{k}` for #{arguments[:type]} is not valid."
228
+ # Can we fix it ? Maybe we can
229
+ autocorrected = known_properties.find { |prop| prop.casecmp(k.to_s).zero? }
230
+ if autocorrected.nil?
231
+ TOPLEVEL_BINDING.eval("@depends_on = []")
232
+ TOPLEVEL_BINDING.eval("@properties = {}")
233
+ rendered_properties = {}
234
+ raise "Property `#{k}` for #{arguments[:type]} is not valid."
235
+ end
236
+ rendered_properties.delete(k)
237
+ autocorrected_properties[autocorrected.to_sym] = v
238
+ mandatory_properties.delete(autocorrected.to_s)
436
239
  end
437
240
  mandatory_properties.delete(k.to_s)
438
241
  end
242
+ rendered_properties = rendered_properties.deep_merge(autocorrected_properties)
439
243
  unless mandatory_properties.count.zero?
440
244
  TOPLEVEL_BINDING.eval("@depends_on = []")
441
245
  TOPLEVEL_BINDING.eval("@properties = {}")
@@ -444,7 +248,7 @@ module Rubycfn
444
248
  end
445
249
  res = {
446
250
  "#{name.to_s}#{i.zero? ? "" : resource_postpend}": {
447
- Properties: TOPLEVEL_BINDING.eval("@properties"),
251
+ Properties: rendered_properties,
448
252
  Type: arguments[:type],
449
253
  Condition: arguments[:condition],
450
254
  UpdatePolicy: arguments[:update_policy],
@@ -28,6 +28,39 @@ describe Rubycfn do
28
28
  r.property(:some_arn) { :rspec_resource.ref(:arn) }
29
29
  r.property(:some_other_arn) { :rspec_resource.ref("FooBar") }
30
30
  end
31
+
32
+ resource :asellion_com_database_instance,
33
+ type: "AWS::RDS::DBInstance" do |r|
34
+ r.property(:db_instance_identifier) { "rspec" }
35
+ r.property(:allocated_storage) { 100 }
36
+ r.property(:dbinstanceclass) { "db.t2.small" }
37
+ r.property(:engine) { "mariadb" }
38
+ r.property(:master_username) { "rspecroot" }
39
+ r.property(:master_user_password) { "rubycfn<3" }
40
+ r.property(:db_name) { "MyAwesomeDatabase" }
41
+ r.property(:preferred_backup_window) { "01:00-01:30" }
42
+ r.property(:backup_retention_period) { 14 }
43
+ r.property(:availability_zone) { "eu-central-1b" }
44
+ r.property(:preferred_maintenance_window) { "sun:06:00-sun:06:30" }
45
+ r.property(:multi_az) { true }
46
+ r.property(:engine_version) { "10.1.34" }
47
+ r.property(:auto_minor_version_upgrade) { true }
48
+ r.property(:license_model) { "general-public-license" }
49
+ r.property(:publicly_accessible) { true }
50
+ r.property(:storage_type) { "gp2" }
51
+ r.property(:port) { 3306 }
52
+ r.property(:copy_tags_to_snapshot) { true }
53
+ r.property(:monitoring_interval) { 60 }
54
+ r.property(:enable_iam_database_authentication) { false }
55
+ r.property(:enable_performance_insights) { false }
56
+ r.property(:deletion_protection) { true }
57
+ r.property(:db_subnet_group_name) { "default-vpc-123456789" }
58
+ r.property(:vpc_security_groups) do
59
+ [
60
+ "sg-0xc0ff3e"
61
+ ]
62
+ end
63
+ end
31
64
  end
32
65
  end
33
66
 
@@ -153,6 +186,24 @@ describe Rubycfn do
153
186
  it { should eq ["FooBar", "fooBar"] }
154
187
  end
155
188
  end
189
+
190
+ context "Database resource exists" do
191
+ subject { resources }
192
+
193
+ it { should have_key "AsellionComDatabaseInstance" }
194
+
195
+ context "Database resource has the right autocorrected properties" do
196
+ let(:properties) { resources["AsellionComDatabaseInstance"]["Properties"] }
197
+ subject { properties }
198
+
199
+ it { should have_key "DBInstanceClass" }
200
+ it { should have_key "DBInstanceIdentifier" }
201
+ it { should have_key "DBName" }
202
+ it { should have_key "DBSubnetGroupName" }
203
+ it { should have_key "MultiAZ" }
204
+ it { should have_key "VPCSecurityGroups" }
205
+ end
206
+ end
156
207
  end
157
208
  end
158
209
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubycfn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Vink
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-23 00:00:00.000000000 Z
11
+ date: 2019-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: neatjson
@@ -267,6 +267,7 @@ files:
267
267
  - bin/rubycfn
268
268
  - format.vim
269
269
  - lib/cli_methods.rb
270
+ - lib/monkeypatch.rb
270
271
  - lib/rubycfn.rb
271
272
  - lib/rubycfn/version.rb
272
273
  - rubycfn.gemspec