text_chart 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6bcc9a9d069cb1fc77252328c76b956bd69024bde31ae55bde6ce6d99d995be0
4
+ data.tar.gz: e281cc003c4f57706e66a321e3e107b10d334dabe89a108c09c53d61f570e357
5
+ SHA512:
6
+ metadata.gz: 2c4147b7db9d1d4e4006afb8726ec8054b3308fa805e7ae8b57fa70fae0967e73e572303050a05ef756bccc19b6fd861a217f55b637686a99c85acfc7df2a32b
7
+ data.tar.gz: d42511067db1a0a4e1c459f47bd28fd26f07368c54fa43e3e9ada5b7c09eefb06d28bcfb47b98bc5a6a8fdab7a46218d950b72d1c0d1249ba9f3fc2bda5b990f
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TextChart::Designer
4
+ # @param [TextChart] text_chart
5
+ # @param [TextChart::SizeCalculator] size_calc
6
+ # @param [Array<String>] chart_canvas
7
+ def initialize(text_chart, size_calc)
8
+ @text_chart = text_chart
9
+ @size_calc = size_calc
10
+ @chart_canvas = build_empty_chart
11
+ end
12
+
13
+ # @return [Array<String>]
14
+ def draw_header
15
+ header = []
16
+ header << "#{@text_chart.title}\n"
17
+ header << "Goal: #{@text_chart.goal}\n"
18
+ header << "\n"
19
+
20
+ @chart_canvas.prepend(*header)
21
+ end
22
+
23
+ # @return [Array<String>]
24
+ def draw_axis
25
+ draw_x_axis
26
+ draw_y_axis
27
+ draw_references
28
+
29
+ @chart_canvas
30
+ end
31
+
32
+ # @return [Array<String>]
33
+ def draw_bars
34
+ last_line_index = @chart_canvas.size - 1
35
+ zero_line = last_line_index - @text_chart.size_config(:x_axis_height)
36
+ chart_line = 0
37
+ ref_width = @size_calc.calculate_reference_width
38
+ 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)
41
+ bar_row = "###"
42
+ 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
48
+
49
+ bar_start = if bar_start == 0
50
+ ref_width + first_bar_margin
51
+ else
52
+ # + 1 because bar_end put us on the bar last column
53
+ bar_end + 1 + middle_bar_margin
54
+ end
55
+
56
+ # - 1 because bar_start already put us on the bar first column
57
+ bar_end = bar_start + bar_width - 1
58
+
59
+ chart_line = zero_line
60
+ bar_top = bar_height - 1
61
+ bar_height.times do |t|
62
+ @chart_canvas[chart_line][bar_start..bar_end] = bar_row
63
+
64
+ chart_line -= 1 unless t == bar_top
65
+ end
66
+
67
+ draw_reference_line(chart_line, ref_width + y_axis_width, bar_start)
68
+ end
69
+
70
+ @chart_canvas
71
+ end
72
+
73
+ private
74
+
75
+ def build_empty_chart
76
+ chart = []
77
+
78
+ number_of_columns = @size_calc.calculate_number_of_columns
79
+ number_of_rows = @size_calc.calculate_number_of_rows
80
+
81
+ empty_row = ""
82
+ number_of_columns.times { empty_row += " " }
83
+ empty_row += "\n"
84
+
85
+ number_of_rows.times { chart << empty_row.dup }
86
+
87
+ chart
88
+ end
89
+
90
+ def draw_x_axis
91
+ position = @size_calc.calculate_reference_width
92
+ size = @size_calc.calculate_x_axis_size
93
+ size.times do
94
+ @chart_canvas.last[position] = "-"
95
+ position += 1
96
+ end
97
+ end
98
+
99
+ def draw_y_axis
100
+ position = 0
101
+ margin = @size_calc.calculate_reference_width
102
+ size = @size_calc.calculate_y_axis_size
103
+ size.times do
104
+ @chart_canvas[position][margin] = "|"
105
+ position += 1
106
+ end
107
+ end
108
+
109
+ def draw_references
110
+ references = @text_chart.refs
111
+ 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)
115
+
116
+ number_of_references.times do |i|
117
+ ref_size = references[i].digits.size
118
+
119
+ if ref_size == (width - margin_size)
120
+ ref_start = 0
121
+ ref_end = ref_size - 1
122
+ @chart_canvas[i][ref_start..ref_end] = references[i].to_s
123
+ else
124
+ ref_start = ref_size
125
+ @chart_canvas[i][ref_start] = references[i].to_s
126
+ end
127
+ end
128
+ end
129
+
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
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TextChart::SizeCalculator
4
+ # @param [TextChart] text_chart
5
+ def initialize(text_chart)
6
+ @text_chart = text_chart
7
+ end
8
+
9
+ # @return [Integer]
10
+ def calculate_number_of_columns
11
+ @number_of_columns ||=
12
+ begin
13
+ result = 0
14
+
15
+ result += calculate_reference_width
16
+
17
+ y_axis_width = @text_chart.size_config(:y_axis_width)
18
+ result += y_axis_width
19
+
20
+ left_margin = @text_chart.size_config(:bar_area_left_margin)
21
+ right_margin = @text_chart.size_config(:bar_area_right_margin)
22
+ result += left_margin + right_margin
23
+
24
+ bar_width = @text_chart.size_config(:bar_width)
25
+ result += @text_chart.data.size * bar_width
26
+
27
+ bar_spacing = @text_chart.size_config(:bar_spacing)
28
+ # -1 to avoid adding spacing after the last bar.
29
+ result += (@text_chart.data.size - 1) * bar_spacing
30
+
31
+ result
32
+ end
33
+ end
34
+
35
+ # @return [Integer]
36
+ def calculate_reference_width
37
+ @reference_width ||=
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
43
+ end
44
+ end
45
+
46
+ # @return [Integer]
47
+ def calculate_number_of_rows
48
+ @number_of_rows ||=
49
+ begin
50
+ result = 0
51
+
52
+ x_axis_row = @text_chart.size_config(:x_axis_height)
53
+ result += x_axis_row
54
+
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 }
58
+
59
+ result
60
+ end
61
+ end
62
+
63
+ # @return [Integer]
64
+ def calculate_x_axis_size
65
+ @x_axis_size ||= calculate_number_of_columns - calculate_reference_width
66
+ end
67
+
68
+ # @return [Integer]
69
+ def calculate_y_axis_size
70
+ @y_axis_size ||=
71
+ begin
72
+ x_axis_row = @text_chart.size_config(:x_axis_height)
73
+ calculate_number_of_rows - x_axis_row
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TextChart
4
+ VERSION = "0.1.0"
5
+ end
data/lib/text_chart.rb ADDED
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "text_chart/version"
4
+ require_relative "text_chart/size_calculator"
5
+ require_relative "text_chart/designer"
6
+
7
+ # This is the main class of the text_chart. After calling the `#to_s` method you'll receive a string
8
+ # representing the chart, just like this one:
9
+ #
10
+ # text_chart demonstration
11
+ # Goal: Show you how cool this is
12
+ #
13
+ # 9 |'''''''''''''''''''''''''''''''''''''''''''''''''''''###
14
+ # 8 | ###
15
+ # 7 | ###
16
+ # 6 |'''''''''''''### ###
17
+ # 5 |'''''''''''''###'''''''''''''''''''''''''''### ###
18
+ # 4 |'''''''''''''###'''''''''''''''''''''''''''###'''''''###'''''''###
19
+ # 3 |'''###'''''''###'''''''''''''''''### ### ### ###
20
+ # 2 | ### ### ### ### ### ###
21
+ # 1 | ### ### ### ### ### ###
22
+ # 0 |'''###'''''''###'''''''### ### ### ### ###
23
+ # ----------------------------------------------------------------------
24
+ class TextChart
25
+ class Error < StandardError; end
26
+
27
+ # @param [String] title
28
+ # @param [String] goal
29
+ # @param [Array] data
30
+ def initialize(title, goal, data)
31
+ @title = title
32
+ @goal = goal
33
+ @data = data.empty? ? [0] : data
34
+ @refs = define_references
35
+ @size_calculator = SizeCalculator.new(self)
36
+ @designer = Designer.new(self, @size_calculator)
37
+ end
38
+
39
+ attr_reader :title, :goal, :refs, :data, :size_calculator, :designer
40
+
41
+ # @return [String]
42
+ def to_s
43
+ @designer.draw_axis
44
+ @designer.draw_bars
45
+ @designer.draw_header.join
46
+ end
47
+
48
+ # @param [Symbol] key
49
+ # @return [Integer]
50
+ def size_config(key)
51
+ SIZE_CONFIG[key]
52
+ end
53
+
54
+ private
55
+
56
+ SIZE_CONFIG = {
57
+ y_axis_width: 1,
58
+ bar_area_left_margin: 3,
59
+ bar_area_right_margin: 3,
60
+ bar_width: 3,
61
+ bar_spacing: 7,
62
+ reference_and_y_axis_margin: 1,
63
+ x_axis_height: 1,
64
+ reference_row_height: 1
65
+ }
66
+
67
+ def define_references
68
+ r = [*@data.min..@data.max].reverse
69
+ r << 0 unless r.include?(0)
70
+ r
71
+ end
72
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: text_chart
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gustavo Ribeiro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-12-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - grdev@tutanota.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/text_chart.rb
21
+ - lib/text_chart/designer.rb
22
+ - lib/text_chart/size_calculator.rb
23
+ - lib/text_chart/version.rb
24
+ homepage: https://github.com/gustavothecoder/text_chart
25
+ licenses:
26
+ - MIT
27
+ metadata:
28
+ homepage_uri: https://github.com/gustavothecoder/text_chart
29
+ source_code_uri: https://github.com/gustavothecoder/text_chart
30
+ changelog_uri: https://github.com/gustavothecoder/text_chart/blob/main/CHANGELOG.md
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubygems_version: 3.2.33
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Generate text-based charts.
50
+ test_files: []