tabled 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/README.md +56 -0
- data/demo.rb +130 -0
- data/lib/content_shaper.rb +68 -0
- data/lib/helpers.rb +31 -0
- data/lib/tabled.rb +7 -41
- data/lib/template.rb +5 -7
- data/tabled.gemspec +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9bea1975c1f4f3cf411a90414b7497ac7a580dd0138ff42cf47f1019c42b21e
|
4
|
+
data.tar.gz: 6b623b51a521cc9c1e6459420dce36080cfc0382269e4dddf5cd7849a0d55f73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68fb74f92e12cb02a9b3c565e67fe482d4ee667bfeae7a9864c0ae2a9317ca0834a77edfe6f6757a83a9a14ae87b7f49703e43f314460954a064d2e8c56ce19b
|
7
|
+
data.tar.gz: 59f967d55a04ef8695b3cfbbbcf06333c0c71a93644a260ffc94259152355e169cfb8d23ef6150ee258617837379ff8811c224b3184aabde920fc142035f6fe2
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--format documentation
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/tabled.svg)](https://badge.fury.io/rb/tabled) ![CI is pasing for ruby 2.6 - 3.0](https://github.com/rukomoynikov/tabled/actions/workflows/linters.yml/badge.svg)
|
2
|
+
|
3
|
+
|
4
|
+
# Description
|
5
|
+
This library can be used to render your data to a console. It's quite simple and has many features
|
6
|
+
|
7
|
+
# How to use
|
8
|
+
1. Install the gem `bundle add tabled` or `gem install tabled`
|
9
|
+
2. Add to the application `require 'tabled''`
|
10
|
+
3. Pass to the application array of rows. Each row may have any amount of columns and optional footer text.
|
11
|
+
|
12
|
+
### Simple data structure
|
13
|
+
```ruby
|
14
|
+
data = [
|
15
|
+
["Helena", "20 years", "Female"],
|
16
|
+
["John", "18 years", "Male"],
|
17
|
+
["Alan", "23 years", "Male"],
|
18
|
+
]
|
19
|
+
|
20
|
+
Tabled.new(data).print_to_console
|
21
|
+
```
|
22
|
+
|
23
|
+
Result
|
24
|
+
```shell
|
25
|
+
Helena 20 years Female
|
26
|
+
John 18 years Male
|
27
|
+
Alan 23 years Male
|
28
|
+
```
|
29
|
+
|
30
|
+
### Using footer inside a row
|
31
|
+
```ruby
|
32
|
+
data = [
|
33
|
+
["Helena", "20 years", "Female"],
|
34
|
+
["John", "18 years", "Male", { footer: "Legendary assassin John Wick (Keanu Reeves) retired from his violent career after marrying the love of his life." }],
|
35
|
+
["Alan", "23 years", "Male"],
|
36
|
+
]
|
37
|
+
|
38
|
+
Tabled.new(data).print_to_console
|
39
|
+
```
|
40
|
+
|
41
|
+
Result
|
42
|
+
```shell
|
43
|
+
Helena 20 years Female
|
44
|
+
|
45
|
+
John 18 years Male
|
46
|
+
Legendary assassin John Wick.
|
47
|
+
|
48
|
+
Alan 23 years Male
|
49
|
+
```
|
50
|
+
|
51
|
+
# Contributing
|
52
|
+
1. Fork it ( http://github.com/rodhilton/console_table/fork )
|
53
|
+
2. Create your feature branch (git checkout -b my-new-feature)
|
54
|
+
3. Commit your changes (git commit -am 'Add some feature')
|
55
|
+
4. Push to the branch (git push origin my-new-feature)
|
56
|
+
5. Create new Pull Request
|
data/demo.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require_relative './lib/tabled'
|
2
|
+
|
3
|
+
STAR_WARS_CHARACTERS = [
|
4
|
+
{
|
5
|
+
"name": "Luke Skywalker",
|
6
|
+
"height": "172",
|
7
|
+
"mass": "77",
|
8
|
+
"hair_color": "blond",
|
9
|
+
"skin_color": "fair",
|
10
|
+
"eye_color": "blue",
|
11
|
+
"birth_year": "19BBY",
|
12
|
+
"gender": "male",
|
13
|
+
},
|
14
|
+
{
|
15
|
+
"name": "C-3PO",
|
16
|
+
"height": "167",
|
17
|
+
"mass": "75",
|
18
|
+
"hair_color": "n/a",
|
19
|
+
"skin_color": "gold",
|
20
|
+
"eye_color": "yellow",
|
21
|
+
"birth_year": "112BBY",
|
22
|
+
"gender": "n/a",
|
23
|
+
},
|
24
|
+
{
|
25
|
+
"name": "R2-D2",
|
26
|
+
"height": "96",
|
27
|
+
"mass": "32",
|
28
|
+
"hair_color": "n/a",
|
29
|
+
"skin_color": "white, blue",
|
30
|
+
"eye_color": "red",
|
31
|
+
"birth_year": "33BBY",
|
32
|
+
"gender": "n/a",
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"name": "Darth Vader",
|
36
|
+
"height": "202",
|
37
|
+
"mass": "136",
|
38
|
+
"hair_color": "none",
|
39
|
+
"skin_color": "white",
|
40
|
+
"eye_color": "yellow",
|
41
|
+
"birth_year": "41.9BBY",
|
42
|
+
"gender": "male",
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"name": "Leia Organa",
|
46
|
+
"height": "150",
|
47
|
+
"mass": "49",
|
48
|
+
"hair_color": "brown",
|
49
|
+
"skin_color": "light",
|
50
|
+
"eye_color": "brown",
|
51
|
+
"birth_year": "19BBY",
|
52
|
+
"gender": "female",
|
53
|
+
},
|
54
|
+
{
|
55
|
+
"name": "Owen Lars",
|
56
|
+
"height": "178",
|
57
|
+
"mass": "120",
|
58
|
+
"hair_color": "brown, grey",
|
59
|
+
"skin_color": "light",
|
60
|
+
"eye_color": "blue",
|
61
|
+
"birth_year": "52BBY",
|
62
|
+
"gender": "male",
|
63
|
+
},
|
64
|
+
{
|
65
|
+
"name": "Beru Whitesun lars",
|
66
|
+
"height": "165",
|
67
|
+
"mass": "75",
|
68
|
+
"hair_color": "brown",
|
69
|
+
"skin_color": "light",
|
70
|
+
"eye_color": "blue",
|
71
|
+
"birth_year": "47BBY",
|
72
|
+
"gender": "female",
|
73
|
+
},
|
74
|
+
{
|
75
|
+
"name": "R5-D4",
|
76
|
+
"height": "97",
|
77
|
+
"mass": "32",
|
78
|
+
"hair_color": "n/a",
|
79
|
+
"skin_color": "white, red",
|
80
|
+
"eye_color": "red",
|
81
|
+
"birth_year": "unknown",
|
82
|
+
"gender": "n/a",
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"name": "Biggs Darklighter",
|
86
|
+
"height": "183",
|
87
|
+
"mass": "84",
|
88
|
+
"hair_color": "black",
|
89
|
+
"skin_color": "light",
|
90
|
+
"eye_color": "brown",
|
91
|
+
"birth_year": "24BBY",
|
92
|
+
"gender": "male",
|
93
|
+
},
|
94
|
+
{
|
95
|
+
"name": "Obi-Wan Kenobi",
|
96
|
+
"height": "182",
|
97
|
+
"mass": "77",
|
98
|
+
"hair_color": "auburn, white",
|
99
|
+
"skin_color": "fair",
|
100
|
+
"eye_color": "blue-gray",
|
101
|
+
"birth_year": "57BBY",
|
102
|
+
"gender": "male",
|
103
|
+
}
|
104
|
+
]
|
105
|
+
|
106
|
+
print "Printing without any params: \n"
|
107
|
+
|
108
|
+
data = STAR_WARS_CHARACTERS.map { |character|
|
109
|
+
[character[:name], character[:height], character[:gender]]
|
110
|
+
}
|
111
|
+
|
112
|
+
Tabled.new(data).print_to_console
|
113
|
+
|
114
|
+
print "\n\n############################\n\n"
|
115
|
+
print "Printing without frame: \n"
|
116
|
+
|
117
|
+
data = STAR_WARS_CHARACTERS.map { |character|
|
118
|
+
[character[:name], character[:height], character[:gender]]
|
119
|
+
}
|
120
|
+
|
121
|
+
Tabled.new(data, framed: false).print_to_console
|
122
|
+
|
123
|
+
print "\n\n############################\n\n"
|
124
|
+
print "Printing without frame: and row separator\n"
|
125
|
+
|
126
|
+
data = STAR_WARS_CHARACTERS.map { |character|
|
127
|
+
[character[:name], character[:height], character[:gender]]
|
128
|
+
}
|
129
|
+
|
130
|
+
Tabled.new(data, framed: false, row_separator: nil).print_to_console
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Tabled
|
2
|
+
class ContentShaper
|
3
|
+
attr_accessor :data, :options, :columns_width
|
4
|
+
|
5
|
+
def initialize(data, columns_width, options)
|
6
|
+
@data = data
|
7
|
+
@columns_width = columns_width
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def shape
|
12
|
+
content =
|
13
|
+
data
|
14
|
+
.inject([]) { |enumerator, row|
|
15
|
+
enumerator << Tabled::Template::Row.render(row, columns_width, options[:framed])
|
16
|
+
enumerator << Tabled::Template::RowFooter.render(row, columns_width, options[:framed])
|
17
|
+
|
18
|
+
# Row separator
|
19
|
+
unless options[:row_separator].nil?
|
20
|
+
enumerator << options[:row_separator].to_s * row_length
|
21
|
+
end
|
22
|
+
|
23
|
+
enumerator
|
24
|
+
}
|
25
|
+
.compact
|
26
|
+
|
27
|
+
content = add_left_and_right_borders(content)
|
28
|
+
content = add_top_bottom_borders(content)
|
29
|
+
|
30
|
+
content
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def row_length
|
36
|
+
@row_length ||= columns_width.sum
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_left_and_right_borders(content)
|
40
|
+
content.inject([]) { |enumerator, row|
|
41
|
+
# For a row separator all symbols are the same
|
42
|
+
row_is_separator = row.split('').uniq.size == 1
|
43
|
+
if row_is_separator && !options[:row_separator].nil?
|
44
|
+
enumerator << (options[:row_separator] * 2) + row + options[:row_separator]
|
45
|
+
elsif !options[:framed]
|
46
|
+
enumerator << row
|
47
|
+
else
|
48
|
+
enumerator << ('| ' if options[:framed]) + row + ('|' if options[:framed])
|
49
|
+
end
|
50
|
+
|
51
|
+
enumerator
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_top_bottom_borders(content)
|
56
|
+
# Top and bottom borders
|
57
|
+
if options[:framed]
|
58
|
+
[
|
59
|
+
'-' * (row_length + 3),
|
60
|
+
options[:row_separator] ? content[0..-2] : content,
|
61
|
+
'-' * (row_length + 3)
|
62
|
+
].flatten
|
63
|
+
else
|
64
|
+
content
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/helpers.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
class Tabled
|
2
|
+
class Helpers
|
3
|
+
# Calculates columns size
|
4
|
+
def self.calculate_columns_width(data)
|
5
|
+
columns_width = []
|
6
|
+
|
7
|
+
data.each do |row|
|
8
|
+
row_without_params = row[0..-2]
|
9
|
+
row_without_params.each_with_index { |column, index|
|
10
|
+
is_column_last = row_without_params.count == index + 1
|
11
|
+
if is_column_last
|
12
|
+
possible_new_value = [row.last.fetch(:footer, '').to_s.size, column.to_s.size].sort.last
|
13
|
+
columns_width[index] = possible_new_value if possible_new_value > (columns_width[index] || 0)
|
14
|
+
else
|
15
|
+
columns_width[index] = column.to_s.size if column.to_s.size > (columns_width[index] || 0)
|
16
|
+
end
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
columns_width.map { |column_width| column_width + 1 }
|
21
|
+
end
|
22
|
+
|
23
|
+
# Add hash as a last element of the row
|
24
|
+
def self.convert_to_required_structure(data)
|
25
|
+
data.map { |row|
|
26
|
+
row << {} unless row.last.is_a?(Hash)
|
27
|
+
row
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/tabled.rb
CHANGED
@@ -1,55 +1,21 @@
|
|
1
1
|
require 'byebug'
|
2
|
-
|
2
|
+
require_relative './template'
|
3
|
+
require_relative './helpers'
|
4
|
+
require_relative './content_shaper'
|
3
5
|
|
4
6
|
class Tabled
|
5
|
-
DEFAULT_OPTIONS = {
|
7
|
+
DEFAULT_OPTIONS = { framed: true, row_separator: '-' }
|
6
8
|
attr_accessor :data, :columns_width, :content, :options
|
7
9
|
|
8
10
|
def initialize(data, **options)
|
9
11
|
@options = DEFAULT_OPTIONS.merge(options)
|
10
|
-
@data = data
|
11
|
-
@columns_width =
|
12
|
-
|
13
|
-
convert_to_required_structure
|
14
|
-
calculate_columns_width
|
15
|
-
prepare_content
|
12
|
+
@data = Tabled::Helpers.convert_to_required_structure(data)
|
13
|
+
@columns_width = Tabled::Helpers.calculate_columns_width(data)
|
14
|
+
@content = Tabled::ContentShaper.new(data, @columns_width, @options).shape()
|
16
15
|
end
|
17
16
|
|
18
17
|
|
19
18
|
def print_to_console
|
20
19
|
print content.join("\n")
|
21
20
|
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def convert_to_required_structure
|
26
|
-
self.data = data.map { |row|
|
27
|
-
row << {} unless row.last.is_a?(Hash)
|
28
|
-
row
|
29
|
-
}
|
30
|
-
end
|
31
|
-
|
32
|
-
def calculate_columns_width
|
33
|
-
data.each do |row|
|
34
|
-
row_without_params = row[0..-2]
|
35
|
-
row_without_params.each_with_index { |column, index|
|
36
|
-
is_column_last = row_without_params.count == index + 1
|
37
|
-
if is_column_last
|
38
|
-
possible_new_value = [row.last.fetch(:footer, '').to_s.size, column.to_s.size].sort.last
|
39
|
-
self.columns_width[index] = possible_new_value if possible_new_value > (self.columns_width[index] || 0)
|
40
|
-
else
|
41
|
-
self.columns_width[index] = column.to_s.size if column.to_s.size > (self.columns_width[index] || 0)
|
42
|
-
end
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
self.columns_width = columns_width.map { |column_width| column_width + 1 }
|
47
|
-
end
|
48
|
-
|
49
|
-
def prepare_content
|
50
|
-
self.content = data.inject([]) { |enumerator, row|
|
51
|
-
enumerator << Tabled::Template::Row.render(row, columns_width, options)
|
52
|
-
enumerator << Tabled::Template::RowFooter.render(row)
|
53
|
-
}.compact
|
54
|
-
end
|
55
21
|
end
|
data/lib/template.rb
CHANGED
@@ -1,23 +1,21 @@
|
|
1
1
|
class Tabled
|
2
2
|
class Template
|
3
3
|
class Row
|
4
|
-
def self.render(row, columns_width,
|
4
|
+
def self.render(row, columns_width, is_framed)
|
5
5
|
row[0..-2].map.with_index { |column, index|
|
6
6
|
spaces = ' ' * (columns_width[index] - column.to_s.size)
|
7
7
|
column.to_s + spaces
|
8
8
|
}.join('')
|
9
9
|
end
|
10
10
|
end
|
11
|
-
end
|
12
|
-
end
|
13
11
|
|
14
|
-
class Tabled
|
15
|
-
class Template
|
16
12
|
class RowFooter
|
17
|
-
def self.render(row)
|
13
|
+
def self.render(row, columns_width, is_framed)
|
18
14
|
return nil unless row.last.fetch(:footer, false)
|
19
15
|
|
20
|
-
row.last.fetch(:footer)
|
16
|
+
footer = row.last.fetch(:footer)
|
17
|
+
required_spaces = columns_width.sum() - footer.size
|
18
|
+
footer + (' ' * required_spaces)
|
21
19
|
end
|
22
20
|
end
|
23
21
|
end
|
data/tabled.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'tabled'
|
3
|
-
s.version = '0.0.
|
3
|
+
s.version = '0.0.2'
|
4
4
|
s.summary = "Library for rendering pretty tables in console"
|
5
5
|
s.description = "This library can be used to render your data to a console. It's quite simple and has many features"
|
6
6
|
s.authors = ["Max Rukomoynikov"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tabled
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Rukomoynikov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-05-
|
11
|
+
date: 2022-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -61,8 +61,13 @@ extra_rdoc_files: []
|
|
61
61
|
files:
|
62
62
|
- ".github/workflows/linters.yml"
|
63
63
|
- ".gitignore"
|
64
|
+
- ".rspec"
|
64
65
|
- Gemfile
|
65
66
|
- Gemfile.lock
|
67
|
+
- README.md
|
68
|
+
- demo.rb
|
69
|
+
- lib/content_shaper.rb
|
70
|
+
- lib/helpers.rb
|
66
71
|
- lib/tabled.rb
|
67
72
|
- lib/template.rb
|
68
73
|
- tabled.gemspec
|