kovid 0.6.8 → 0.6.9

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
  SHA256:
3
- metadata.gz: 68cf72c0e99add59625ce1a9763db32b5eeecb69220d78b236e929f08adb1dec
4
- data.tar.gz: 84d95391d43e67b62f865f6e0ab585700aae3790e1f968793d11a99bf02e6ce8
3
+ metadata.gz: aa46d5f734b53509d084570bc4a0abc2527d02320ea67c9a85120389492a0d64
4
+ data.tar.gz: 72c0dd54efb153df1996c238a74f42bec0c46062876669051e346f4906feba38
5
5
  SHA512:
6
- metadata.gz: daf6517f2d15ab2670bb9ad1124faa683db07eb3308a37d057b6af08b0d5a3f2ada1a4f76f54048556878df14435a71a82632a2995c28a6c830755aff7263338
7
- data.tar.gz: 77862be6a1adf08d40568326bcf24a4aa1ae0c60ad5f0b462b7ef3e5e1b64292c812e0c96b47d70702dad2635ee3640739883a5afbd28b2e2411b2488a23c279
6
+ metadata.gz: d61d1956c6f309ad70beeb8fe1289bb9e7c15c0b8b26c7ddd72304e888803681f529bdb1c091be603351271b981d8e4b2e0f033972996bed4580aa077d8b4c4a
7
+ data.tar.gz: 82d702ef83e0307424191235d239cc27aad835e0191677e0540cecf359a3756e427fa6c427036e70d2550ef0c08679966d7d21b33bc2b7e691f603e33077bec4
data/Gemfile CHANGED
@@ -6,4 +6,4 @@ source 'https://rubygems.org'
6
6
  gemspec
7
7
 
8
8
  gem 'rake', '~> 12.0'
9
- gem 'rspec', '~> 3.0'
9
+ gem 'rspec', '~> 3.0'
data/Gemfile.lock CHANGED
@@ -2,7 +2,6 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  kovid (0.6.8)
5
- ascii_charts (~> 0.9.1)
6
5
  carmen (~> 1.1.3)
7
6
  rainbow (~> 3.0)
8
7
  terminal-table (~> 1.8)
@@ -18,7 +17,6 @@ GEM
18
17
  minitest (~> 5.1)
19
18
  tzinfo (~> 1.1)
20
19
  zeitwerk (~> 2.2)
21
- ascii_charts (0.9.1)
22
20
  carmen (1.1.3)
23
21
  activesupport (>= 3.0.0)
24
22
  concurrent-ruby (1.1.6)
data/README.md CHANGED
@@ -74,6 +74,7 @@ ___
74
74
  😷 **History**
75
75
  * `kovid history COUNTRY` (full history).
76
76
  * `kovid history COUNTRY N` (history in the last N days).
77
+ * `kovid history STATE --usa`
77
78
  ___
78
79
 
79
80
  **NOTE:** If you find it irritating to have to type `kovid state STATE`, `covid state STATE` works as well.
data/kovid.gemspec CHANGED
@@ -22,12 +22,11 @@ Gem::Specification.new do |spec|
22
22
  spec.metadata['source_code_uri'] = 'https://github.com/siaw23/kovid'
23
23
  spec.metadata['changelog_uri'] = 'https://github.com/siaw23/kovid'
24
24
 
25
- spec.add_dependency 'ascii_charts', '~> 0.9.1'
25
+ spec.add_dependency 'carmen', '~> 1.1.3'
26
26
  spec.add_dependency 'rainbow', '~> 3.0'
27
27
  spec.add_dependency 'terminal-table', '~> 1.8'
28
28
  spec.add_dependency 'thor', '~> 1.0'
29
29
  spec.add_dependency 'typhoeus', '~> 1.3'
30
- spec.add_dependency 'carmen', '~> 1.1.3'
31
30
  spec.add_development_dependency 'simplecov', '~> 0.18'
32
31
 
33
32
  # Specify which files should be added to the gem when it is released.
data/lib/kovid.rb CHANGED
@@ -68,8 +68,12 @@ module Kovid
68
68
  Kovid::Request.cases
69
69
  end
70
70
 
71
- def history(country, last)
72
- Kovid::Request.history(country, last)
71
+ def history(country, days=30)
72
+ Kovid::Request.history(country, days)
73
+ end
74
+
75
+ def history_us_state(state, days=30)
76
+ Kovid::Request.history_us_state(state, days)
73
77
  end
74
78
 
75
79
  def histogram(country, date)
@@ -0,0 +1,276 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2011 Ben Lund
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module Kovid
24
+ module AsciiCharts
25
+ VERSION = '0.9.1'
26
+
27
+ class Chart
28
+ attr_reader :options, :data
29
+
30
+ DEFAULT_MAX_Y_VALS = 20
31
+ DEFAULT_MIN_Y_VALS = 10
32
+
33
+ # data is a sorted array of [x, y] pairs
34
+
35
+ def initialize(data, options = {})
36
+ @data = data
37
+ @options = options
38
+ end
39
+
40
+ def rounded_data
41
+ @rounded_data ||= data.map { |pair| [pair[0], round_value(pair[1])] }
42
+ end
43
+
44
+ def step_size
45
+ unless defined? @step_size
46
+ if options[:y_step_size]
47
+ @step_size = options[:y_step_size]
48
+ else
49
+ max_y_vals = options[:max_y_vals] || DEFAULT_MAX_Y_VALS
50
+ min_y_vals = options[:max_y_vals] || DEFAULT_MIN_Y_VALS
51
+ y_span = (max_yval - min_yval).to_f
52
+
53
+ step_size = nearest_step(y_span.to_f / (data.size + 1))
54
+
55
+ if @all_ints && (step_size < 1)
56
+ step_size = 1
57
+ else
58
+ while (y_span / step_size) < min_y_vals
59
+ candidate_step_size = next_step_down(step_size)
60
+ if @all_ints && (candidate_step_size < 1)
61
+ break
62
+ end ## don't go below one
63
+
64
+ step_size = candidate_step_size
65
+ end
66
+ end
67
+
68
+ # go up if we undershot, or were never over
69
+ while (y_span / step_size) > max_y_vals
70
+ step_size = next_step_up(step_size)
71
+ end
72
+ @step_size = step_size
73
+ end
74
+ if !@all_ints && @step_size.is_a?(Integer)
75
+ @step_size = @step_size.to_f
76
+ end
77
+ end
78
+ @step_size
79
+ end
80
+
81
+ STEPS = [1, 2, 5].freeze
82
+
83
+ def from_step(val)
84
+ if val == 0
85
+ [0, 0]
86
+ else
87
+ order = Math.log10(val).floor.to_i
88
+ num = (val / (10**order))
89
+ [num, order]
90
+ end
91
+ end
92
+
93
+ def to_step(num, order)
94
+ s = num * (10**order)
95
+ if order < 0
96
+ s.to_f
97
+ else
98
+ s
99
+ end
100
+ end
101
+
102
+ def nearest_step(val)
103
+ num, order = from_step(val)
104
+ to_step(2, order) # #@@
105
+ end
106
+
107
+ def next_step_up(val)
108
+ num, order = from_step(val)
109
+ next_index = STEPS.index(num.to_i) + 1
110
+ if STEPS.size == next_index
111
+ next_index = 0
112
+ order += 1
113
+ end
114
+ to_step(STEPS[next_index], order)
115
+ end
116
+
117
+ def next_step_down(val)
118
+ num, order = from_step(val)
119
+ next_index = STEPS.index(num.to_i) - 1
120
+ if next_index == -1
121
+ STEPS.size - 1
122
+ order -= 1
123
+ end
124
+ to_step(STEPS[next_index], order)
125
+ end
126
+
127
+ # round to nearest step size, making sure we curtail precision to same order of magnitude as the step size to avoid 0.4 + 0.2 = 0.6000000000000001
128
+ def round_value(val)
129
+ remainder = val % step_size
130
+ unprecised = if (remainder * 2) >= step_size
131
+ (val - remainder) + step_size
132
+ else
133
+ val - remainder
134
+ end
135
+ if step_size < 1
136
+ precision = -Math.log10(step_size).floor
137
+ (unprecised * (10**precision)).to_i.to_f / (10**precision)
138
+ else
139
+ unprecised
140
+ end
141
+ end
142
+
143
+ def max_yval
144
+ scan_data unless defined? @max_yval
145
+ @max_yval
146
+ end
147
+
148
+ def min_yval
149
+ scan_data unless defined? @min_yval
150
+ @min_yval
151
+ end
152
+
153
+ def all_ints
154
+ scan_data unless defined? @all_ints
155
+ @all_ints
156
+ end
157
+
158
+ def scan_data
159
+ @max_yval = 0
160
+ @min_yval = 0
161
+ @all_ints = true
162
+
163
+ @max_xval_width = 1
164
+
165
+ data.each do |pair|
166
+ @max_yval = pair[1] if pair[1] > @max_yval
167
+ @min_yval = pair[1] if pair[1] < @min_yval
168
+ @all_ints = false if @all_ints && !pair[1].is_a?(Integer)
169
+
170
+ if (xw = pair[0].to_s.length) > @max_xval_width
171
+ @max_xval_width = xw
172
+ end
173
+ end
174
+ end
175
+
176
+ def max_xval_width
177
+ scan_data unless defined? @max_xval_width
178
+ @max_xval_width
179
+ end
180
+
181
+ def max_yval_width
182
+ scan_y_range unless defined? @max_yval_width
183
+ @max_yval_width
184
+ end
185
+
186
+ def scan_y_range
187
+ @max_yval_width = 1
188
+
189
+ y_range.each do |yval|
190
+ if (yw = yval.to_s.length) > @max_yval_width
191
+ @max_yval_width = yw
192
+ end
193
+ end
194
+ end
195
+
196
+ def y_range
197
+ unless defined? @y_range
198
+ @y_range = []
199
+ first_y = round_value(min_yval)
200
+ first_y -= step_size if first_y > min_yval
201
+ last_y = round_value(max_yval)
202
+ last_y += step_size if last_y < max_yval
203
+ current_y = first_y
204
+ while current_y <= last_y
205
+ @y_range << current_y
206
+ current_y = round_value(current_y + step_size) ## to avoid fp arithmetic oddness
207
+ end
208
+ end
209
+ @y_range
210
+ end
211
+
212
+ def lines
213
+ raise 'lines must be overridden'
214
+ end
215
+
216
+ def draw
217
+ lines.join("\n")
218
+ end
219
+
220
+ def to_string
221
+ draw
222
+ end
223
+ end
224
+
225
+ class Cartesian < Chart
226
+ def lines
227
+ return [[' ', options[:title], ' ', '|', '+-', ' ']] if data.empty?
228
+
229
+ lines = [' ']
230
+
231
+ bar_width = max_xval_width + 1
232
+
233
+ lines << (' ' * max_yval_width) + ' ' + rounded_data.map { |pair| pair[0].to_s.center(bar_width) }.join('')
234
+
235
+ y_range.each_with_index do |current_y, i|
236
+ yval = current_y.to_s
237
+ bar = if i == 0
238
+ '+'
239
+ else
240
+ '|'
241
+ end
242
+ current_line = [(' ' * (max_yval_width - yval.length)) + "#{current_y}#{bar}"]
243
+
244
+ rounded_data.each do |pair|
245
+ marker = if (i == 0) && options[:hide_zero]
246
+ '-'
247
+ else
248
+ '*'
249
+ end
250
+ filler = if i == 0
251
+ '-'
252
+ else
253
+ ' '
254
+ end
255
+ comparison = if options[:bar]
256
+ current_y <= pair[1]
257
+ else
258
+ current_y == pair[1]
259
+ end
260
+ current_line << if comparison
261
+ marker.center(bar_width, filler)
262
+ else
263
+ filler * bar_width
264
+ end
265
+ end
266
+ lines << current_line.join('')
267
+ current_y += step_size
268
+ end
269
+ lines << ' '
270
+ lines << options[:title].center(lines[1].length) if options[:title]
271
+ lines << ' '
272
+ lines.reverse
273
+ end
274
+ end
275
+ end
276
+ end
data/lib/kovid/cli.rb CHANGED
@@ -75,13 +75,15 @@ module Kovid
75
75
  data_source
76
76
  end
77
77
 
78
- desc 'history COUNTRY or history COUNTRY N',
79
- 'Return history of incidents of COUNTRY (in the last N days)'
80
- def history(*params)
81
- if params.size == 2
82
- puts Kovid.history(params.first, params.last)
78
+ desc 'history COUNTRY or history COUNTRY N or' \
79
+ 'history STATE --usa',
80
+ 'Return history of incidents of COUNTRY|STATE (in the last N days)'
81
+ option :usa, :type => :boolean
82
+ def history(location, days=30)
83
+ if options[:usa]
84
+ puts Kovid.history_us_state(location, days)
83
85
  else
84
- puts Kovid.history(params.first, nil)
86
+ puts Kovid.history(location, days)
85
87
  end
86
88
  data_source
87
89
  end
@@ -145,8 +147,8 @@ module Kovid
145
147
  source = <<~TEXT
146
148
  #{Time.now}
147
149
  Sources:
148
- * JHU CSSE GISand Data
149
- * https://www.worldometers.info/coronavirus/
150
+ * Johns Hopkins University
151
+ * https://www.worldometers.info/coronavirus
150
152
  TEXT
151
153
  puts source
152
154
  end
@@ -23,6 +23,12 @@ module Kovid
23
23
  'Recovered'.paint_green
24
24
  ].freeze
25
25
 
26
+ DATE_CASES_DEATHS = [
27
+ 'Date'.paint_white,
28
+ 'Cases'.paint_white,
29
+ 'Deaths'.paint_red
30
+ ].freeze
31
+
26
32
  CONTINENTAL_AGGREGATE_HEADINGS = [
27
33
  'Cases'.paint_white,
28
34
  'Cases Today'.paint_white,
@@ -93,7 +99,13 @@ module Kovid
93
99
  'Recovered'.paint_green
94
100
  ].freeze
95
101
 
96
- FOOTER_LINE = [
102
+ FOOTER_LINE_THREE_COLUMNS = [
103
+ '------------',
104
+ '------------',
105
+ '------------'
106
+ ].freeze
107
+
108
+ FOOTER_LINE_FOUR_COLUMNS = [
97
109
  '------------',
98
110
  '------------',
99
111
  '------------',
@@ -3,24 +3,15 @@
3
3
  module Kovid
4
4
  module Historians
5
5
  include Constants
6
+ include AsciiCharts
6
7
 
7
- def history(country, last)
8
- # TODO: Write checks for when country is spelt wrong.
8
+ def history(location, days)
9
9
  rows = []
10
10
 
11
- stats = if last
12
- Kovid.format_country_history_numbers(country).last(last.to_i)
13
- else
14
- Kovid.format_country_history_numbers(country)
15
- end
11
+ stats = Kovid.format_country_history_numbers(location).last(days.to_i)
12
+ dates = location['timeline']['cases'].keys.last(days.to_i)
16
13
 
17
- dates = if last
18
- country['timeline']['cases'].keys.last(last.to_i)
19
- else
20
- country['timeline']['cases'].keys
21
- end
22
-
23
- unless last
14
+ if days.to_i >= 30
24
15
  stats = stats.reject { |stat| stat[0].to_i.zero? && stat[1].to_i.zero? }
25
16
  dates = dates.last(stats.count)
26
17
  end
@@ -31,14 +22,25 @@ module Kovid
31
22
  rows << row
32
23
  end
33
24
 
25
+ # Title and Column format if Country or US State
26
+ if location['country']
27
+ title = location['country'].try(:upcase)
28
+ col_format = DATE_CASES_DEATHS_RECOVERED
29
+ footer = FOOTER_LINE_FOUR_COLUMNS
30
+ else
31
+ title = location['state'].try(:upcase)
32
+ col_format = DATE_CASES_DEATHS
33
+ footer = FOOTER_LINE_THREE_COLUMNS
34
+ end
35
+
34
36
  if stats.size > 10
35
- rows << FOOTER_LINE
36
- rows << DATE_CASES_DEATHS_RECOVERED
37
+ rows << footer
38
+ rows << col_format
37
39
  end
38
40
 
39
41
  Terminal::Table.new(
40
- title: country['country'].upcase,
41
- headings: DATE_CASES_DEATHS_RECOVERED,
42
+ title: title,
43
+ headings: col_format,
42
44
  rows: rows
43
45
  )
44
46
  end
@@ -88,7 +90,7 @@ module Kovid
88
90
  dates.each_with_index do |val, index|
89
91
  data << [val, positive_cases_figures[index]]
90
92
  end
91
- y_range = AsciiCharts::Cartesian.new(
93
+ y_range = Kovid::AsciiCharts::Cartesian.new(
92
94
  data, bar: true, hide_zero: true
93
95
  ).y_range
94
96
 
data/lib/kovid/request.rb CHANGED
@@ -8,9 +8,11 @@ require_relative 'uri_builder'
8
8
 
9
9
  module Kovid
10
10
  class Request
11
- COUNTRIES_PATH = UriBuilder.new('/v2/countries').url
12
- STATES_URL = UriBuilder.new('/v2/states').url
13
- JHUCSSE_URL = UriBuilder.new('/v2/jhucsse').url
11
+ COUNTRIES_PATH = UriBuilder.new('/v2/countries').url
12
+ STATES_URL = UriBuilder.new('/v2/states').url
13
+ JHUCSSE_URL = UriBuilder.new('/v2/jhucsse').url
14
+ HISTORICAL_URL = UriBuilder.new('/v2/historical').url
15
+ HISTORICAL_US_URL = UriBuilder.new('/v2/historical/usacounties').url
14
16
 
15
17
  SERVER_DOWN = 'Server overwhelmed. Please try again in a moment.'
16
18
 
@@ -158,19 +160,57 @@ module Kovid
158
160
  puts SERVER_DOWN
159
161
  end
160
162
 
161
- def history(country, last)
163
+ def history(country, days)
162
164
  history_path = UriBuilder.new('/v2/historical').url
165
+
163
166
  response = JSON.parse(
164
167
  Typhoeus.get(
165
168
  history_path + "/#{country}", cache_ttl: 900
166
169
  ).response_body
167
170
  )
168
171
 
169
- Kovid::Tablelize.history(response, last)
172
+ if response.key?('message')
173
+ not_found(country) do |c|
174
+ "Could not find cases for #{c}.\nIf searching United States, add --usa option"
175
+ end
176
+ else
177
+ Kovid::Tablelize.history(response, days)
178
+ end
170
179
  rescue JSON::ParserError
171
180
  puts SERVER_DOWN
172
181
  end
173
182
 
183
+ def history_us_state(state, days)
184
+ history_path = UriBuilder.new('/v2/historical/usacounties').url
185
+ state = Kovid.lookup_us_state(state).downcase()
186
+
187
+ response = JSON.parse(
188
+ Typhoeus.get(
189
+ history_path + "/#{state}", cache_ttl: 900
190
+ ).response_body
191
+ )
192
+
193
+ if response.respond_to?(:key?) and response.key?('message')
194
+ return not_found(state)
195
+ end
196
+
197
+ # API Endpoint returns list of counties for given state, so
198
+ # we aggreage cases for all counties
199
+ # Note: no data for 'Recovered'
200
+ cases = usacounties_aggregator(response, 'cases')
201
+ deaths = usacounties_aggregator(response, 'deaths')
202
+
203
+ # normalize data so we can call Kovid::Tablelize.history on US State data
204
+ response = {
205
+ "state" => state,
206
+ "timeline" => { "cases" => cases, "deaths" => deaths }
207
+ }
208
+
209
+ Kovid::Tablelize.history(response, days)
210
+ rescue JSON::ParserError
211
+ puts SERVER_DOWN
212
+ end
213
+
174
214
  def histogram(country, date)
175
215
  history_path = UriBuilder.new('/v2/historical').url
176
216
  response = JSON.parse(
@@ -188,9 +228,17 @@ module Kovid
188
228
 
189
229
  private
190
230
 
191
- def not_found(country)
192
- rows = [["Wrong spelling/No reported cases on #{country.upcase}."]]
193
- Terminal::Table.new title: "You checked: #{country.upcase}", rows: rows
231
+ def not_found(location)
232
+ rows = []
233
+ default_warning = "Wrong spelling/No reported cases on #{location.upcase}."
234
+
235
+ if block_given?
236
+ rows << [ yield(location) ]
237
+ else
238
+ rows << [ default_warning ]
239
+ end
240
+
241
+ Terminal::Table.new title: "You checked: #{location.upcase}", rows: rows
194
242
  end
195
243
 
196
244
  def fetch_countries(list)
@@ -278,6 +326,16 @@ module Kovid
278
326
  end
279
327
  end.compact
280
328
  end
329
+
330
+ def usacounties_aggregator(data, key=nil)
331
+ data.inject({}) do |base,other|
332
+ base.merge(other['timeline'][key]) do |k,l,r|
333
+ l ||= 0
334
+ l ||= 0
335
+ l + r
336
+ end
337
+ end.compact
338
+ end
281
339
  end
282
340
  end
283
341
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'terminal-table'
4
4
  require 'date'
5
- require 'ascii_charts'
5
+ require_relative 'ascii_charts'
6
6
  require_relative 'painter'
7
7
  require_relative 'constants'
8
8
  require_relative 'aggregators'
data/lib/kovid/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kovid
4
- VERSION = '0.6.8'
4
+ VERSION = '0.6.9'
5
5
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kovid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.8
4
+ version: 0.6.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emmanuel Hayford
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-17 00:00:00.000000000 Z
11
+ date: 2020-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ascii_charts
14
+ name: carmen
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.9.1
19
+ version: 1.1.3
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: 0.9.1
26
+ version: 1.1.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rainbow
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '1.3'
83
- - !ruby/object:Gem::Dependency
84
- name: carmen
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 1.1.3
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 1.1.3
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: simplecov
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -135,6 +121,7 @@ files:
135
121
  - kovid.gemspec
136
122
  - lib/kovid.rb
137
123
  - lib/kovid/aggregators.rb
124
+ - lib/kovid/ascii_charts.rb
138
125
  - lib/kovid/cache.rb
139
126
  - lib/kovid/cli.rb
140
127
  - lib/kovid/constants.rb