dyna 0.1.9 → 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
- SHA1:
3
- metadata.gz: bf7e0af4635d19cc04464734c752ec8f68032ea3
4
- data.tar.gz: 68e76221165d0268c622001e07190ca753894c81
2
+ SHA256:
3
+ metadata.gz: e4c57e85bcc9f5bce4b084da7b9c6c7338529d1b83512b1549bc31f47d48bc1e
4
+ data.tar.gz: 5a14ba531ff8a96bb56ccd09af7db82d8c9e6a3024f3051be520203a890d382e
5
5
  SHA512:
6
- metadata.gz: 9940c92ee88b999d0a9a5a8ba7f745b4d9afd900773fdd7b512c85d289318dbbd81877c4217e569a7ee2b697dabcb0c61d9ac2be45c67cc3ff464dc01def0914
7
- data.tar.gz: 0a2aee89b5f14f22171dfd4a43b9235d9143af4b39b44e66023b0137b53037874b57d89975d70ec9f7864c74ed440f17d5108dbc706c023d5e02b2924a055e0b
6
+ metadata.gz: cf9547e5373b6b690623732de1c70a2efce0128863f53a92a1cbffcc7539ca5294299a993ecf587af339a1fce3fd7ef3f549e5f4313e3b3283003ccb9a54f28c
7
+ data.tar.gz: cbefd166bad5e80202ef3d0f9e5f73da90642fbb0dbce0e6a1c406e85143cae539fc0f7464c0240c88d6c31a21c1f1f6c3c6d4d2d654e069342243c14c7a0d67
data/dyna.gemspec CHANGED
@@ -20,7 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.bindir = "bin"
21
21
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
- spec.add_dependency 'aws-sdk', '~> 2'
23
+ spec.add_dependency 'aws-sdk-dynamodb', '~> 1.18'
24
+ spec.add_dependency 'aws-sdk-applicationautoscaling', '~> 1.16'
24
25
  spec.add_dependency 'term-ansicolor', '~> 1.4'
25
26
  spec.add_dependency 'diffy', '~> 3.1'
26
27
  spec.add_dependency 'hashie', '~> 3.4'
data/lib/dyna.rb CHANGED
@@ -6,7 +6,8 @@ require 'hashie'
6
6
  require 'singleton'
7
7
  require 'pp'
8
8
 
9
- require 'aws-sdk'
9
+ require 'aws-sdk-applicationautoscaling'
10
+ require 'aws-sdk-dynamodb'
10
11
 
11
12
  require 'dyna/version'
12
13
  require 'dyna/logger'
data/lib/dyna/client.rb CHANGED
@@ -15,6 +15,8 @@ module Dyna
15
15
  )
16
16
  else
17
17
  @options.ddb = Aws::DynamoDB::Client.new
18
+ @options.aas = Aws::ApplicationAutoScaling::Client.new
19
+ Exporter.aas(@options.aas)
18
20
  end
19
21
  end
20
22
 
@@ -35,41 +35,42 @@ end
35
35
  stream_specification = ''
36
36
  if table[:local_secondary_indexes]
37
37
  local_secondary_indexes_tmpl = <<-EOS.chomp
38
- <% table[:local_secondary_indexes].each do |index| %>
38
+ <% table[:local_secondary_indexes].each do |index| -%>
39
39
  local_secondary_index <%= index[:index_name].inspect %> do
40
40
  key_schema hash: <%= index[:key_schema][0][:attribute_name].inspect %>, range: <%= index[:key_schema][1][:attribute_name].inspect %><% if index[:projection] %>
41
41
  projection projection_type: <%= index[:projection][:projection_type].inspect %><% end %>
42
42
  end
43
- <% end %>
43
+ <%- end %>
44
44
  EOS
45
- local_secondary_indexes = ERB.new(local_secondary_indexes_tmpl).result(binding)
45
+ local_secondary_indexes = ERB.new(local_secondary_indexes_tmpl, nil, '-').result(binding)
46
46
  end
47
47
 
48
48
  if table[:global_secondary_indexes]
49
49
  global_secondary_indexes_tmpl = <<-EOS.chomp
50
- <% table[:global_secondary_indexes].each do |index| %>
50
+ <% table[:global_secondary_indexes].each do |index| -%>
51
51
  global_secondary_index <%= index[:index_name].inspect %> do
52
52
  key_schema hash: <%= index[:key_schema][0][:attribute_name].inspect %><% if index[:key_schema].size == 2 %>, range: <%= index[:key_schema][1][:attribute_name].inspect %><% end %><% if index[:projection] %>
53
53
  projection projection_type: <%= index[:projection][:projection_type].inspect %><% end %>
54
54
  provisioned_throughput read_capacity_units: <%= index[:provisioned_throughput][:read_capacity_units] %>, write_capacity_units: <%= index[:provisioned_throughput][:read_capacity_units] %>
55
55
  end
56
- <% end %>
56
+ <%- end %>
57
57
  EOS
58
- global_secondary_indexes = ERB.new(global_secondary_indexes_tmpl).result(binding)
58
+ global_secondary_indexes = ERB.new(global_secondary_indexes_tmpl, nil, '-').result(binding)
59
59
  end
60
60
 
61
61
  attribute_definitions_tmpl = <<-EOS.chomp
62
- <% table[:attribute_definitions].each do |attr| %>
62
+ <% table[:attribute_definitions].each do |attr| -%>
63
+
63
64
  attribute_definition(
64
65
  attribute_name: <%= attr[:attribute_name].inspect %>,
65
66
  attribute_type: <%= attr[:attribute_type].inspect %>,
66
67
  )
67
- <% end %>
68
+ <%- end %>
68
69
  EOS
69
- attribute_definitions = ERB.new(attribute_definitions_tmpl).result(binding)
70
+ attribute_definitions = ERB.new(attribute_definitions_tmpl, nil, '-').result(binding)
70
71
 
71
72
  if table[:stream_specification]
72
- stream_specification_tmpl = <<-EOS.chomp
73
+ stream_specification_tmpl = <<-EOS
73
74
 
74
75
  stream_specification(
75
76
  stream_enabled: <%= table[:stream_specification][:stream_enabled] %>,
@@ -79,6 +80,35 @@ EOS
79
80
  stream_specification = ERB.new(stream_specification_tmpl).result(binding)
80
81
  end
81
82
 
83
+ if table[:scalable_targets]
84
+ scalable_targets_tmpl = <<-EOS.chomp
85
+ <% table[:scalable_targets].each do |target| -%>
86
+
87
+ scalable_target(
88
+ scalable_dimension: <%= target[:scalable_dimension].inspect %>,
89
+ min_capacity: <%= target[:min_capacity] %>,
90
+ max_capacity: <%= target[:max_capacity] %>,
91
+ )
92
+ <%- end %>
93
+ EOS
94
+ scalable_targets = ERB.new(scalable_targets_tmpl, nil, '-').result(binding)
95
+ end
96
+
97
+ if table[:scaling_policies]
98
+ scaling_policies_tmpl = <<-EOS.chomp
99
+ <% table[:scaling_policies].each do |policy| -%>
100
+
101
+ scaling_policy(
102
+ scalable_dimension: <%= policy[:scalable_dimension].inspect %>,
103
+ target_tracking_scaling_policy_configuration: {
104
+ target_value: <%= policy[:target_tracking_scaling_policy_configuration][:target_value] %>,
105
+ },
106
+ )
107
+ <%- end %>
108
+ EOS
109
+ scaling_policies = ERB.new(scaling_policies_tmpl, nil, '-').result(binding)
110
+ end
111
+
82
112
  <<-EOS
83
113
  table "#{name}" do
84
114
  key_schema(
@@ -90,7 +120,9 @@ EOS
90
120
  read_capacity_units: #{table[:provisioned_throughput][:read_capacity_units]},
91
121
  write_capacity_units: #{table[:provisioned_throughput][:write_capacity_units]},
92
122
  )
93
- #{local_secondary_indexes}#{global_secondary_indexes}#{stream_specification}
123
+
124
+ billing_mode #{table[:billing_mode].inspect}
125
+ #{local_secondary_indexes}#{global_secondary_indexes}#{stream_specification}#{scalable_targets}#{scaling_policies}
94
126
  end
95
127
  EOS
96
128
  end
@@ -11,6 +11,8 @@ module Dyna
11
11
 
12
12
  @result = Hashie::Mash.new({
13
13
  :table_name => table_name,
14
+ :scalable_targets => [],
15
+ :scaling_policies => [],
14
16
  })
15
17
  instance_eval(&block)
16
18
  end
@@ -69,6 +71,35 @@ module Dyna
69
71
  }.merge(index.result.symbolize_keys)
70
72
  end
71
73
 
74
+ def billing_mode(billing_mode)
75
+ @result.billing_mode = billing_mode
76
+ end
77
+
78
+ def scalable_target(scalable_dimension:, min_capacity:, max_capacity:)
79
+ @result.scalable_targets << {
80
+ service_namespace: 'dynamodb',
81
+ scalable_dimension: scalable_dimension,
82
+ resource_id: "table/#{@result.table_name}",
83
+ min_capacity: min_capacity,
84
+ max_capacity: max_capacity,
85
+ }
86
+ end
87
+
88
+ def scaling_policy(scalable_dimension:, target_tracking_scaling_policy_configuration:)
89
+ predefined_metric_type = 'DynamoDBWriteCapacityUtilization'
90
+ if scalable_dimension == 'dynamodb:table:ReadCapacityUnits'
91
+ predefined_metric_type = 'DynamoDBReadCapacityUtilization'
92
+ end
93
+ @result.scaling_policies << {
94
+ policy_name: "#{predefined_metric_type}:table/#{@result.table_name}",
95
+ policy_type: 'TargetTrackingScaling',
96
+ resource_id: "table/#{@result.table_name}",
97
+ scalable_dimension: scalable_dimension,
98
+ service_namespace: 'dynamodb',
99
+ target_tracking_scaling_policy_configuration: target_tracking_scaling_policy_configuration.merge(predefined_metric_specification: {predefined_metric_type: predefined_metric_type}),
100
+ }
101
+ end
102
+
72
103
  class LocalSecondaryIndex
73
104
  attr_accessor :result
74
105
 
data/lib/dyna/exporter.rb CHANGED
@@ -15,12 +15,16 @@ module Dyna
15
15
  end
16
16
 
17
17
  def export
18
- @ddb.list_tables.table_names
19
- .reject { |name| should_skip(name) }
20
- .sort
21
- .each_with_object({}) do |table_name, result|
22
- result[table_name] = self.class.export_table(@ddb, table_name)
18
+ result = {}
19
+ @ddb.list_tables.map do |tables|
20
+ tables.table_names
21
+ .reject { |name| should_skip(name) }
22
+ .sort
23
+ .each do |table_name|
24
+ result[table_name] = self.class.export_table(@ddb, table_name)
25
+ end
23
26
  end
27
+ result
24
28
  end
25
29
 
26
30
  def self.table_definition(describe_table)
@@ -28,6 +32,7 @@ module Dyna
28
32
  table_name: describe_table.table_name,
29
33
  key_schema: key_schema(describe_table),
30
34
  attribute_definitions: attribute_definitions(describe_table),
35
+ billing_mode: describe_table.billing_mode_summary&.billing_mode,
31
36
  provisioned_throughput: {
32
37
  read_capacity_units: describe_table.provisioned_throughput.read_capacity_units,
33
38
  write_capacity_units: describe_table.provisioned_throughput.write_capacity_units,
@@ -35,9 +40,15 @@ module Dyna
35
40
  local_secondary_indexes: local_secondary_indexes(describe_table),
36
41
  global_secondary_indexes: global_secondary_indexes(describe_table),
37
42
  stream_specification: stream_specification(describe_table),
43
+ scalable_targets: scalable_targets(describe_table),
44
+ scaling_policies: scaling_policies(describe_table),
38
45
  }
39
46
  end
40
47
 
48
+ def self.aas(aas)
49
+ @aas = aas
50
+ end
51
+
41
52
  private
42
53
  def self.export_table(ddb, table_name)
43
54
  describe_table = ddb.describe_table(table_name: table_name).table
@@ -102,5 +113,43 @@ module Dyna
102
113
  stream_view_type: stream_spec.stream_view_type,
103
114
  }
104
115
  end
116
+
117
+ def self.scalable_targets(table)
118
+ scalable_targets_by_resource_id["table/#{table.table_name}"] || []
119
+ end
120
+
121
+ def self.scalable_targets_by_resource_id
122
+ return @scalable_targets_by_resource_id if @scalable_targets_by_resource_id
123
+
124
+ results = []
125
+ next_token = nil
126
+ begin
127
+ resp = @aas.describe_scalable_targets(service_namespace: 'dynamodb', next_token: next_token)
128
+ resp.scalable_targets.each do |target|
129
+ results.push(target)
130
+ end
131
+ next_token = resp.next_token
132
+ end while next_token
133
+ @scalable_targets_by_resource_id = results.group_by(&:resource_id)
134
+ end
135
+
136
+ def self.scaling_policies(table)
137
+ scaling_policies_by_resource_id["table/#{table.table_name}"] || []
138
+ end
139
+
140
+ def self.scaling_policies_by_resource_id
141
+ return @scaling_policies_by_resource_id if @scaling_policies_by_resource_id
142
+
143
+ results = []
144
+ next_token = nil
145
+ begin
146
+ resp = @aas.describe_scaling_policies(service_namespace: 'dynamodb', next_token: next_token)
147
+ resp.scaling_policies.each do |policy|
148
+ results.push(policy)
149
+ end
150
+ next_token = resp.next_token
151
+ end while next_token
152
+ @scaling_policies_by_resource_id = results.group_by(&:resource_id)
153
+ end
105
154
  end
106
155
  end
data/lib/dyna/utils.rb CHANGED
@@ -1,6 +1,37 @@
1
1
  module Dyna
2
2
  class Utils
3
3
  class << self
4
+ def normalize_hash(hash)
5
+ hash.dup.each do |k, v|
6
+ if v.kind_of?(Array)
7
+ if v.first.kind_of?(Hash)
8
+ hash[k] = v.map { |o| normalize_hash(o) }
9
+ elsif v.first.respond_to?(:to_h)
10
+ hash[k] = v.map { |o| normalize_hash(o.to_h) }
11
+ else
12
+ v.sort!
13
+ end
14
+ elsif v.respond_to?(:to_h)
15
+ hash[k] = normalize_hash(v.to_h)
16
+ end
17
+ end
18
+ sort_keys(hash)
19
+ end
20
+
21
+ def sort_keys(hash)
22
+ hash = Hash[hash.sort]
23
+ hash.each do |k, v|
24
+ if v.kind_of?(Array)
25
+ if v.first.kind_of?(Hash)
26
+ hash[k] = v.map { |h| sort_keys(h) }
27
+ end
28
+ elsif v.kind_of?(Hash)
29
+ hash[k] = sort_keys(v)
30
+ end
31
+ end
32
+ hash
33
+ end
34
+
4
35
  def diff(obj1, obj2, options = {})
5
36
  diffy = Diffy::Diff.new(
6
37
  obj1.pretty_inspect,
data/lib/dyna/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dyna
2
- VERSION = '0.1.9'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -8,17 +8,22 @@ module Dyna
8
8
  end
9
9
 
10
10
  def tables
11
- @ddb.list_tables.table_names.map do |table_name|
12
- describe_table = @ddb.describe_table(table_name: table_name).table
13
- Table.new(@ddb, describe_table, @options)
14
- end
11
+ @ddb.list_tables.map { |tables|
12
+ tables.table_names.map do |table_name|
13
+ describe_table = @ddb.describe_table(table_name: table_name).table
14
+ Table.new(@ddb, describe_table, @options)
15
+ end
16
+ }.flatten
15
17
  end
16
18
 
17
19
  def create(dsl)
18
20
  log(:info, 'Create Table', :cyan, "#{dsl.table_name}")
19
21
 
20
22
  unless @options.dry_run
21
- result = @ddb.create_table(dsl.symbolize_keys)
23
+ params = dsl.symbolize_keys
24
+ params.delete(:scalable_targets)
25
+ params.delete(:scaling_policies)
26
+ result = @ddb.create_table(params)
22
27
  @options.updated = true
23
28
  result
24
29
  end
@@ -20,9 +20,8 @@ module Dyna
20
20
  end
21
21
 
22
22
  def update(dsl)
23
- unless provisioned_throughput_eql?(dsl)
24
- wait_until_table_is_active
25
- update_table(dsl_provisioned_throughput(dsl))
23
+ unless billing_mode_eql?(dsl) && provisioned_throughput_eql?(dsl)
24
+ update_table(dsl)
26
25
  end
27
26
  unless global_secondary_indexes_eql?(dsl)
28
27
  wait_until_table_is_active
@@ -32,6 +31,9 @@ module Dyna
32
31
  wait_until_table_is_active
33
32
  update_stream_specification(dsl_stream_specification(dsl))
34
33
  end
34
+ unless auto_scaling_eql?(dsl)
35
+ update_auto_scaling(dsl)
36
+ end
35
37
  end
36
38
 
37
39
  def delete
@@ -63,14 +65,54 @@ module Dyna
63
65
  end
64
66
 
65
67
  private
68
+ def auto_scaling_eql?(dsl)
69
+ scalable_targets_eql?(dsl) && scaling_policies_eql?(dsl)
70
+ end
71
+
72
+ def scalable_targets_eql?(dsl)
73
+ df = definition[:scalable_targets].map do |target|
74
+ cmp = target.to_h
75
+ cmp.delete(:creation_time)
76
+ cmp.delete(:role_arn)
77
+ Dyna::Utils.normalize_hash(cmp)
78
+ end
79
+ df.sort_by {|s| s[:scalable_dimension] } == dsl[:scalable_targets].map { |target| Dyna::Utils.normalize_hash(target) }.sort_by {|s| s[:scalable_dimension] }
80
+ end
81
+
82
+ def scaling_policies_for_diff
83
+ definition[:scaling_policies].map { |policy|
84
+ #Dyna::Utils.normalize_hash({target_tracking_scaling_policy_configuration: {target_value: policy.target_tracking_scaling_policy_configuration.target_value} })
85
+ cmp = policy.to_h
86
+ cmp.delete(:alarms)
87
+ cmp.delete(:creation_time)
88
+ cmp.delete(:policy_arn)
89
+ Dyna::Utils.normalize_hash(cmp)
90
+ }.sort_by {|s| s[:scalable_dimension] }
91
+ end
92
+
93
+ def scaling_policies_eql?(dsl)
94
+ scaling_policies_for_diff == dsl.scaling_policies.map { |policy| Dyna::Utils.normalize_hash(policy) }.sort_by {|s| s[:scalable_dimension] }
95
+ end
96
+
66
97
  def definition_eql?(dsl)
67
98
  definition == dsl.definition
68
99
  end
69
100
 
70
101
  def provisioned_throughput_eql?(dsl)
102
+ if definition[:billing_mode] == 'PROVISIONED' && billing_mode_eql?(dsl)
103
+ return true
104
+ end
71
105
  self_provisioned_throughput == dsl_provisioned_throughput(dsl)
72
106
  end
73
107
 
108
+ def billing_mode_eql?(dsl)
109
+ if definition[:billing_mode] == dsl[:billing_mode]
110
+ return true
111
+ end
112
+
113
+ definition[:billing_mode].nil? && dsl[:billing_mode].to_s == 'PROVISIONED'
114
+ end
115
+
74
116
  def self_provisioned_throughput
75
117
  definition.select {|k,v| k == :provisioned_throughput}
76
118
  end
@@ -169,11 +211,24 @@ module Dyna
169
211
  end
170
212
 
171
213
  def update_table(dsl)
172
- log(:info, " table: #{@table.table_name}\n".green + Dyna::Utils.diff(self_provisioned_throughput, dsl, :color => @options.color, :indent => ' '), false)
214
+ params = {}
215
+ df_params = {}
216
+ unless billing_mode_eql?(dsl)
217
+ params[:billing_mode] = dsl[:billing_mode]
218
+ df_params[:billing_mode] = definition[:billing_mode]
219
+ end
220
+
221
+ if provisioned_throughput_eql?(dsl) == false && dsl[:scalable_targets].empty?
222
+ params[:provisioned_throughput] = dsl[:provisioned_throughput].symbolize_keys
223
+ df_params[:provisioned_throughput] = self_provisioned_throughput[:provisioned_throughput]
224
+ end
225
+
226
+ return if params.empty?
227
+ log(:info, " table: #{@table.table_name}\n".green + Dyna::Utils.diff(df_params, params, :color => @options.color, :indent => ' '), false)
173
228
  unless @options.dry_run
174
- params = dsl.dup
229
+ wait_until_table_is_active
175
230
  params[:table_name] = @table.table_name
176
- @ddb.update_table(params)
231
+ @ddb.update_table(params.symbolize_keys)
177
232
  @options.updated = true
178
233
  end
179
234
  end
@@ -205,6 +260,48 @@ module Dyna
205
260
  @options.updated = true
206
261
  end
207
262
  end
263
+
264
+ def update_auto_scaling(dsl)
265
+ has_change = false
266
+ unless scalable_targets_eql?(dsl)
267
+ has_change = true
268
+ df_cmp = definition[:scalable_targets].sort_by { |target| target[:scalable_dimension] }.map do |target|
269
+ h = target.to_h
270
+ h.delete(:creation_time)
271
+ h.delete(:role_arn)
272
+ Dyna::Utils.normalize_hash(h)
273
+ end
274
+ dsl_cmp = dsl.scalable_targets.sort_by { |target| target[:scalable_dimension] }.map { |target| Dyna::Utils.normalize_hash(target) }
275
+ log(:info, " table: #{@table.table_name}(update scalable targets)\n".green + Dyna::Utils.diff(df_cmp, dsl_cmp, :color => @options.color, :indent => ' '), false)
276
+ end
277
+
278
+ unless scaling_policies_eql?(dsl)
279
+ has_change = true
280
+ dsl_cmp = dsl.scaling_policies.map { |policy| Dyna::Utils.normalize_hash(policy) }.sort_by {|s| s[:scalable_dimension] }
281
+ log(:info, " table: #{@table.table_name}(update scaling policies)\n".green + Dyna::Utils.diff(scaling_policies_for_diff, dsl_cmp, :color => @options.color, :indent => ' '), false)
282
+ end
283
+
284
+ unless @options.dry_run
285
+ if has_change
286
+ definition[:scalable_targets].each do |target|
287
+ @options.aas.deregister_scalable_target(
288
+ service_namespace: 'dynamodb',
289
+ resource_id: target.resource_id,
290
+ scalable_dimension: target.scalable_dimension,
291
+ )
292
+ end
293
+
294
+ dsl.scalable_targets.each do |target|
295
+ @options.aas.register_scalable_target(target)
296
+ end
297
+
298
+ dsl.scaling_policies.each do |policy|
299
+ @options.aas.put_scaling_policy(policy)
300
+ end
301
+ end
302
+ @options.updated = true
303
+ end
304
+ end
208
305
  end
209
306
  end
210
307
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dyna
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - wata
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-02 00:00:00.000000000 Z
11
+ date: 2019-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: aws-sdk
14
+ name: aws-sdk-dynamodb
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2'
19
+ version: '1.18'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2'
26
+ version: '1.18'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk-applicationautoscaling
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: term-ansicolor
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -174,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
188
  version: '0'
175
189
  requirements: []
176
190
  rubyforge_project:
177
- rubygems_version: 2.5.2
191
+ rubygems_version: 2.7.6
178
192
  signing_key:
179
193
  specification_version: 4
180
194
  summary: Codenize DynamoDB table