text_chart 0.1.0 → 1.0.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 +4 -4
- data/lib/text_chart/designer.rb +47 -34
- data/lib/text_chart/size_calculator.rb +40 -10
- data/lib/text_chart/version.rb +1 -1
- data/lib/text_chart.rb +36 -32
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3151e15fd8d9c6ad4d4850b2d7200585644b19212bbac4bc6e8c1cf22b01fd51
|
4
|
+
data.tar.gz: 276efc536bfc80c1e1df0b9378e5d1645fa284bbdf5b7652ff1798f3a3a76edd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f452855f7b707e3bb44735bf75016ebed13665e267c458c17f2ff7f0f0828f94ebb57eafed7f8a88c507d1e4a864ebefc3764ee608e16f26d6a3bfb56c1cfbb
|
7
|
+
data.tar.gz: ce3e6d56b4844b95f843954a39acf4e62344b02d6fbb752e396958085cd255240a0fad8a04cc2189f79f3eaf456dcecdd3af41312f5377ea8b04fcf10337428b
|
data/lib/text_chart/designer.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
class TextChart::Designer
|
4
2
|
# @param [TextChart] text_chart
|
5
3
|
# @param [TextChart::SizeCalculator] size_calc
|
@@ -14,7 +12,7 @@ class TextChart::Designer
|
|
14
12
|
def draw_header
|
15
13
|
header = []
|
16
14
|
header << "#{@text_chart.title}\n"
|
17
|
-
header << "
|
15
|
+
header << "#{@text_chart.subtitle}\n"
|
18
16
|
header << "\n"
|
19
17
|
|
20
18
|
@chart_canvas.prepend(*header)
|
@@ -36,40 +34,46 @@ class TextChart::Designer
|
|
36
34
|
chart_line = 0
|
37
35
|
ref_width = @size_calc.calculate_reference_width
|
38
36
|
y_axis_width = @text_chart.size_config(:y_axis_width)
|
39
|
-
|
40
|
-
middle_bar_margin = @text_chart.size_config(:bar_spacing)
|
37
|
+
bar_margin = @text_chart.size_config(:bar_margin)
|
41
38
|
bar_row = "###"
|
42
39
|
bar_width = @text_chart.size_config(:bar_width)
|
43
|
-
|
44
|
-
|
45
|
-
@text_chart.data.each do |d|
|
46
|
-
# + 1 to guarantee that the bar will always be rendered
|
47
|
-
bar_height = d + 1
|
40
|
+
bar_start = bar_end = bar_top = 0
|
41
|
+
height_of_bars = define_height_of_bars
|
48
42
|
|
43
|
+
height_of_bars.each do |height|
|
49
44
|
bar_start = if bar_start == 0
|
50
|
-
ref_width +
|
45
|
+
ref_width + bar_margin + y_axis_width
|
51
46
|
else
|
52
47
|
# + 1 because bar_end put us on the bar last column
|
53
|
-
bar_end + 1 +
|
48
|
+
bar_end + 1 + bar_margin
|
54
49
|
end
|
55
50
|
|
56
51
|
# - 1 because bar_start already put us on the bar first column
|
57
52
|
bar_end = bar_start + bar_width - 1
|
58
53
|
|
59
54
|
chart_line = zero_line
|
60
|
-
bar_top =
|
61
|
-
|
55
|
+
bar_top = height - 1
|
56
|
+
height.times do |t|
|
62
57
|
@chart_canvas[chart_line][bar_start..bar_end] = bar_row
|
63
58
|
|
64
59
|
chart_line -= 1 unless t == bar_top
|
65
60
|
end
|
66
|
-
|
67
|
-
draw_reference_line(chart_line, ref_width + y_axis_width, bar_start)
|
68
61
|
end
|
69
62
|
|
70
63
|
@chart_canvas
|
71
64
|
end
|
72
65
|
|
66
|
+
# @return [Array<String>]
|
67
|
+
def paint
|
68
|
+
@chart_canvas.map do |row|
|
69
|
+
next if row.gsub!(@text_chart.title, colorize(@text_chart.title, :bold))
|
70
|
+
|
71
|
+
row.gsub!(/-?\d/) { colorize($&, :cyan) }
|
72
|
+
row.gsub!(/#+/) { colorize($&, :blue) }
|
73
|
+
end
|
74
|
+
@chart_canvas
|
75
|
+
end
|
76
|
+
|
73
77
|
private
|
74
78
|
|
75
79
|
def build_empty_chart
|
@@ -107,34 +111,43 @@ class TextChart::Designer
|
|
107
111
|
end
|
108
112
|
|
109
113
|
def draw_references
|
110
|
-
references = @text_chart.
|
114
|
+
references = @text_chart.data
|
111
115
|
width = @size_calc.calculate_reference_width
|
112
|
-
|
113
|
-
ref_size = ref_start = ref_end = nil
|
114
|
-
margin_size = @text_chart.size_config(:reference_and_y_axis_margin)
|
116
|
+
y_axis_size = @size_calc.calculate_y_axis_size
|
117
|
+
ref_size = ref_start = ref_end = ref_str = nil
|
115
118
|
|
116
|
-
|
117
|
-
|
119
|
+
references.each do |r|
|
120
|
+
row = y_axis_size - @size_calc.calculate_bar_height(r)
|
121
|
+
ref_str = r.to_s
|
122
|
+
ref_size = ref_str.size
|
118
123
|
|
119
|
-
if ref_size ==
|
124
|
+
if ref_size == width
|
120
125
|
ref_start = 0
|
121
126
|
ref_end = ref_size - 1
|
122
|
-
@chart_canvas[i][ref_start..ref_end] = references[i].to_s
|
123
127
|
else
|
124
|
-
ref_start = ref_size
|
125
|
-
|
128
|
+
ref_start = width - ref_size
|
129
|
+
ref_end = [ref_start, ref_size].max
|
126
130
|
end
|
131
|
+
@chart_canvas[row][ref_start..ref_end] = ref_str
|
127
132
|
end
|
128
133
|
end
|
129
134
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
135
|
+
# @param string to be colorized [String]
|
136
|
+
# @param desired color/formatting [Symbol]
|
137
|
+
# @return colorized string [String]
|
138
|
+
def colorize(str, format)
|
139
|
+
case format
|
140
|
+
when :bold
|
141
|
+
"\e[1m#{str}\e[22m"
|
142
|
+
when :cyan
|
143
|
+
"\e[36m#{str}\e[0m"
|
144
|
+
when :blue
|
145
|
+
"\e[34m#{str}\e[0m"
|
138
146
|
end
|
139
147
|
end
|
148
|
+
|
149
|
+
# @return height of each sample item [Array<Integer>]
|
150
|
+
def define_height_of_bars
|
151
|
+
@text_chart.data.map { |i| @size_calc.calculate_bar_height(i) }
|
152
|
+
end
|
140
153
|
end
|
@@ -17,14 +17,14 @@ class TextChart::SizeCalculator
|
|
17
17
|
y_axis_width = @text_chart.size_config(:y_axis_width)
|
18
18
|
result += y_axis_width
|
19
19
|
|
20
|
-
left_margin = @text_chart.size_config(:
|
21
|
-
right_margin = @text_chart.size_config(:
|
20
|
+
left_margin = @text_chart.size_config(:bar_margin)
|
21
|
+
right_margin = @text_chart.size_config(:bar_margin)
|
22
22
|
result += left_margin + right_margin
|
23
23
|
|
24
24
|
bar_width = @text_chart.size_config(:bar_width)
|
25
25
|
result += @text_chart.data.size * bar_width
|
26
26
|
|
27
|
-
bar_spacing = @text_chart.size_config(:
|
27
|
+
bar_spacing = @text_chart.size_config(:bar_margin)
|
28
28
|
# -1 to avoid adding spacing after the last bar.
|
29
29
|
result += (@text_chart.data.size - 1) * bar_spacing
|
30
30
|
|
@@ -36,10 +36,8 @@ class TextChart::SizeCalculator
|
|
36
36
|
def calculate_reference_width
|
37
37
|
@reference_width ||=
|
38
38
|
begin
|
39
|
-
|
40
|
-
|
41
|
-
reference_margin = @text_chart.size_config(:reference_and_y_axis_margin)
|
42
|
-
biggest_item_width + reference_margin
|
39
|
+
biggest_number_size = @text_chart.data.map(&:to_s).map(&:size).max
|
40
|
+
biggest_number_size
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
@@ -52,14 +50,23 @@ class TextChart::SizeCalculator
|
|
52
50
|
x_axis_row = @text_chart.size_config(:x_axis_height)
|
53
51
|
result += x_axis_row
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
calculate_bar_height(@text_chart.data.max).times do
|
54
|
+
result += @text_chart.size_config(:bar_row_height)
|
55
|
+
end
|
58
56
|
|
59
57
|
result
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
61
|
+
# @param bar [Integer]
|
62
|
+
# @return the number of rows that we should render [Integer]
|
63
|
+
def calculate_bar_height(bar)
|
64
|
+
return 0 if bar.zero?
|
65
|
+
|
66
|
+
min_bar_height = 1
|
67
|
+
(calculate_increase_percentile(@text_chart.data.min, bar) / bar_height_limiter).round + min_bar_height
|
68
|
+
end
|
69
|
+
|
63
70
|
# @return [Integer]
|
64
71
|
def calculate_x_axis_size
|
65
72
|
@x_axis_size ||= calculate_number_of_columns - calculate_reference_width
|
@@ -73,4 +80,27 @@ class TextChart::SizeCalculator
|
|
73
80
|
calculate_number_of_rows - x_axis_row
|
74
81
|
end
|
75
82
|
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# @param initial value [Numeric]
|
87
|
+
# @param final value [Numeric]
|
88
|
+
# @return increase percentile [Float]
|
89
|
+
def calculate_increase_percentile(initial, final)
|
90
|
+
float_initial = initial.to_f
|
91
|
+
float_final = final.to_f
|
92
|
+
diff = float_final - float_initial
|
93
|
+
(diff / float_initial) * 100.0
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return the denominator to assure the `max_rows` config [Integer]
|
97
|
+
def bar_height_limiter
|
98
|
+
@bar_height_limiter ||=
|
99
|
+
begin
|
100
|
+
limiter = 10.0
|
101
|
+
max_diff = calculate_increase_percentile(@text_chart.data.min, @text_chart.data.max)
|
102
|
+
limiter *= 10.0 until (max_diff / limiter).round <= @text_chart.size_config(:max_bar_height)
|
103
|
+
limiter
|
104
|
+
end
|
105
|
+
end
|
76
106
|
end
|
data/lib/text_chart/version.rb
CHANGED
data/lib/text_chart.rb
CHANGED
@@ -8,41 +8,53 @@ require_relative "text_chart/designer"
|
|
8
8
|
# representing the chart, just like this one:
|
9
9
|
#
|
10
10
|
# text_chart demonstration
|
11
|
-
#
|
11
|
+
# Show you how cool this is
|
12
12
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
13
|
+
# 73| ###
|
14
|
+
# | ###
|
15
|
+
# 67| ### ### ### ###
|
16
|
+
# | ### ### ### ###
|
17
|
+
# 54| ### ### ### ### ### ### ###
|
18
|
+
# | ### ### ### ### ### ### ###
|
19
|
+
# 44| ### ### ### ### ### ### ### ### ### ###
|
20
|
+
# | ### ### ### ### ### ### ### ### ### ###
|
21
|
+
# 33| ### ### ### ### ### ### ### ### ### ### ###
|
22
|
+
# | ### ### ### ### ### ### ### ### ### ### ###
|
23
|
+
# 27| ### ### ### ### ### ### ### ### ### ### ### ### ### ###
|
24
|
+
# 20| ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
|
25
|
+
# 14| ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
|
26
|
+
# 10| ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
|
27
|
+
# 5| ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
|
28
|
+
# ----------------------------------------------------------------------------------
|
24
29
|
class TextChart
|
25
30
|
class Error < StandardError; end
|
26
31
|
|
27
32
|
# @param [String] title
|
28
|
-
# @param [String]
|
33
|
+
# @param [String] subtitle
|
29
34
|
# @param [Array] data
|
30
|
-
|
35
|
+
# @param [Boolean] colors
|
36
|
+
def initialize(title, subtitle, data, colors = false)
|
37
|
+
raise Error, "`data` cannot be empty" if data.empty?
|
38
|
+
|
31
39
|
@title = title
|
32
|
-
@
|
33
|
-
@data = data.empty? ? [0] : data
|
34
|
-
@
|
40
|
+
@subtitle = subtitle
|
41
|
+
@data = data.empty? ? [0] : data.filter(&:positive?)
|
42
|
+
@colors = colors
|
35
43
|
@size_calculator = SizeCalculator.new(self)
|
36
44
|
@designer = Designer.new(self, @size_calculator)
|
37
45
|
end
|
38
46
|
|
39
|
-
attr_reader :title, :
|
47
|
+
attr_reader :title, :subtitle, :data, :size_calculator, :designer
|
40
48
|
|
41
49
|
# @return [String]
|
42
50
|
def to_s
|
43
|
-
@designer.draw_axis
|
44
|
-
|
45
|
-
|
51
|
+
result = @designer.draw_axis &&
|
52
|
+
@designer.draw_bars &&
|
53
|
+
@designer.draw_header
|
54
|
+
|
55
|
+
result = @designer.paint if @colors
|
56
|
+
|
57
|
+
result.join
|
46
58
|
end
|
47
59
|
|
48
60
|
# @param [Symbol] key
|
@@ -55,18 +67,10 @@ class TextChart
|
|
55
67
|
|
56
68
|
SIZE_CONFIG = {
|
57
69
|
y_axis_width: 1,
|
58
|
-
|
59
|
-
bar_area_right_margin: 3,
|
70
|
+
bar_margin: 1,
|
60
71
|
bar_width: 3,
|
61
|
-
bar_spacing: 7,
|
62
|
-
reference_and_y_axis_margin: 1,
|
63
72
|
x_axis_height: 1,
|
64
|
-
|
73
|
+
bar_row_height: 1,
|
74
|
+
max_bar_height: 60
|
65
75
|
}
|
66
|
-
|
67
|
-
def define_references
|
68
|
-
r = [*@data.min..@data.max].reverse
|
69
|
-
r << 0 unless r.include?(0)
|
70
|
-
r
|
71
|
-
end
|
72
76
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: text_chart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gustavo Ribeiro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|