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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6bcc9a9d069cb1fc77252328c76b956bd69024bde31ae55bde6ce6d99d995be0
4
- data.tar.gz: e281cc003c4f57706e66a321e3e107b10d334dabe89a108c09c53d61f570e357
3
+ metadata.gz: 3151e15fd8d9c6ad4d4850b2d7200585644b19212bbac4bc6e8c1cf22b01fd51
4
+ data.tar.gz: 276efc536bfc80c1e1df0b9378e5d1645fa284bbdf5b7652ff1798f3a3a76edd
5
5
  SHA512:
6
- metadata.gz: 2c4147b7db9d1d4e4006afb8726ec8054b3308fa805e7ae8b57fa70fae0967e73e572303050a05ef756bccc19b6fd861a217f55b637686a99c85acfc7df2a32b
7
- data.tar.gz: d42511067db1a0a4e1c459f47bd28fd26f07368c54fa43e3e9ada5b7c09eefb06d28bcfb47b98bc5a6a8fdab7a46218d950b72d1c0d1249ba9f3fc2bda5b990f
6
+ metadata.gz: 9f452855f7b707e3bb44735bf75016ebed13665e267c458c17f2ff7f0f0828f94ebb57eafed7f8a88c507d1e4a864ebefc3764ee608e16f26d6a3bfb56c1cfbb
7
+ data.tar.gz: ce3e6d56b4844b95f843954a39acf4e62344b02d6fbb752e396958085cd255240a0fad8a04cc2189f79f3eaf456dcecdd3af41312f5377ea8b04fcf10337428b
@@ -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 << "Goal: #{@text_chart.goal}\n"
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
- first_bar_margin = y_axis_width + @text_chart.size_config(:bar_area_left_margin)
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
- bar_height = bar_start = bar_end = bar_top = 0
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 + first_bar_margin
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 + middle_bar_margin
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 = bar_height - 1
61
- bar_height.times do |t|
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.refs
114
+ references = @text_chart.data
111
115
  width = @size_calc.calculate_reference_width
112
- number_of_references = references.size
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
- number_of_references.times do |i|
117
- ref_size = references[i].digits.size
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 == (width - margin_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
- @chart_canvas[i][ref_start] = references[i].to_s
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
- def draw_reference_line(chart_line, line_start, line_end)
131
- current_position = line_start
132
- until current_position == line_end
133
- if @chart_canvas[chart_line][current_position] != "#"
134
- @chart_canvas[chart_line][current_position] = "'"
135
- end
136
-
137
- current_position += 1
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(:bar_area_left_margin)
21
- right_margin = @text_chart.size_config(:bar_area_right_margin)
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(:bar_spacing)
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
- biggest_item = @text_chart.data.max
40
- biggest_item_width = biggest_item.digits.count
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
- reference_row = @text_chart.size_config(:reference_row_height)
56
- number_of_references = @text_chart.refs.size
57
- number_of_references.times { result += reference_row }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class TextChart
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
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
- # Goal: Show you how cool this is
11
+ # Show you how cool this is
12
12
  #
13
- # 9 |'''''''''''''''''''''''''''''''''''''''''''''''''''''###
14
- # 8 | ###
15
- # 7 | ###
16
- # 6 |'''''''''''''### ###
17
- # 5 |'''''''''''''###'''''''''''''''''''''''''''### ###
18
- # 4 |'''''''''''''###'''''''''''''''''''''''''''###'''''''###'''''''###
19
- # 3 |'''###'''''''###'''''''''''''''''### ### ### ###
20
- # 2 | ### ### ### ### ### ###
21
- # 1 | ### ### ### ### ### ###
22
- # 0 |'''###'''''''###'''''''### ### ### ### ###
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] goal
33
+ # @param [String] subtitle
29
34
  # @param [Array] data
30
- def initialize(title, goal, data)
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
- @goal = goal
33
- @data = data.empty? ? [0] : data
34
- @refs = define_references
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, :goal, :refs, :data, :size_calculator, :designer
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
- @designer.draw_bars
45
- @designer.draw_header.join
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
- bar_area_left_margin: 3,
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
- reference_row_height: 1
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: 0.1.0
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: 2023-12-24 00:00:00.000000000 Z
11
+ date: 2024-01-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: