markdown-tables 1.0.0 → 1.0.1
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/markdown-tables.rb +85 -94
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb85037027b4ed9b6c064ef04ed5ad507ae20859
|
4
|
+
data.tar.gz: f1d9d7230c5b4882d050e94d401264b35610c57f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3aaa0e871716d174ee1530a5b4a1809bd3b88377f5a6393080e1b7f156594652ec96d69ad478c0e57e5361829a6965b06dc1a157233978f9ad0cbe2ac0f8c1b
|
7
|
+
data.tar.gz: c772f17d33eac4696d1e5213d8d81d9bb607a3439757a52b664d6e427d35da6af17c4b19ac56b0c22007249c06f7d3c5bdcd2cf4ac3a3919a255c967924ff077
|
data/lib/markdown-tables.rb
CHANGED
@@ -6,92 +6,75 @@ class MarkdownTables
|
|
6
6
|
# Pass align: 'l' for left alignment or 'r' for right alignment. Anything
|
7
7
|
# else will result in cells being centered. Pass an array of align values
|
8
8
|
# to specify alignment per column.
|
9
|
-
# If is_rows is true, then each sub-array represents a row.
|
9
|
+
# If is_rows is true, then each sub-array of data represents a row.
|
10
10
|
# Conversely, if is_rows is false, each sub-array of data represents a column.
|
11
11
|
# Empty cells can be given with nil or an empty string.
|
12
12
|
def self.make_table(labels, data, align: '', is_rows: false)
|
13
|
+
validate(labels, data, align, is_rows)
|
14
|
+
|
15
|
+
# Deep copy the arguments so we don't mutate the originals.
|
13
16
|
labels = Marshal.load(Marshal.dump(labels))
|
14
17
|
data = Marshal.load(Marshal.dump(data))
|
15
|
-
validate(labels, data, align, is_rows)
|
16
|
-
sanitize!(labels, data)
|
17
18
|
|
19
|
+
# Remove any breaking Markdown characters.
|
20
|
+
labels.map! {|label| sanitize(label)}
|
21
|
+
data.map! {|datum| datum.map {|cell| sanitize(cell)}}
|
22
|
+
|
23
|
+
# Convert align to something that other methods won't need to validate.
|
24
|
+
align.class == String && align = [align] * labels.length
|
25
|
+
align.map! {|a| a =~ /[lr]/i ? a.downcase : 'c'}
|
26
|
+
|
27
|
+
# Generate the column labels and alignment line.
|
18
28
|
header_line = labels.join('|')
|
19
|
-
alignment_line =
|
20
|
-
|
21
|
-
if
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
row = []
|
28
|
-
data.each {|col| row.push(col[i])}
|
29
|
-
rows.push(row.join('|'))
|
30
|
-
end
|
31
|
-
end
|
29
|
+
alignment_line = parse_alignment(align, labels.length)
|
30
|
+
|
31
|
+
# Pad the data arrays so that it can be transposed if necessary.
|
32
|
+
max_len = data.map(&:length).max
|
33
|
+
data.map! {|datum| fill(datum, max_len)}
|
34
|
+
|
35
|
+
# Generate the table rows.
|
36
|
+
rows = (is_rows ? data : data.transpose).map {|row| row.join('|')}
|
32
37
|
|
33
38
|
return [header_line, alignment_line, rows.join("\n")].join("\n")
|
34
39
|
end
|
35
40
|
|
36
41
|
# Convert a Markdown table into human-readable form.
|
37
42
|
def self.plain_text(md_table)
|
43
|
+
md_table !~ // && raise('Invalid input')
|
44
|
+
|
45
|
+
# Split the table into lines to get the labels, rows, and alignments.
|
38
46
|
lines = md_table.split("\n")
|
39
47
|
alignments = lines[1].split('|')
|
48
|
+
# labels or rows might have some empty values but alignments
|
49
|
+
# is guaranteed to be of the right width.
|
40
50
|
table_width = alignments.length
|
41
|
-
|
42
|
-
#
|
43
|
-
labels = lines[0].split('|')
|
44
|
-
|
45
|
-
rows = lines[2..-1].map {|line| line.split('|')}
|
46
|
-
rows.each_index do |i|
|
47
|
-
rows[i].length < table_width && rows[i] += [' '] * (table_width - rows[i].length)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Replace non-breaking HTML characters with their plaintext counterparts.
|
51
|
-
rows.each do |row|
|
52
|
-
row.each do |cell|
|
53
|
-
cell.gsub!(/( )|(|)/, ' ' => ' ', '|' => '|')
|
54
|
-
end
|
55
|
-
end
|
51
|
+
# '|||'.split('|') == [], so we need to manually add trailing empty cells.
|
52
|
+
# Leading empty cells are taken care of automatically.
|
53
|
+
labels = fill(lines[0].split('|'), table_width)
|
54
|
+
rows = lines[2..-1].map {|line| fill(line.split('|'), table_width)}
|
56
55
|
|
57
56
|
# Get the width for each column.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
labels[i].prepend(' ' * start)
|
72
|
-
labels[i] += ' ' * (widths[i] - start - label_length)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Align the cells.
|
76
|
-
rows.each do |row|
|
77
|
-
row.length.times do |i|
|
78
|
-
cell_length = row[i].length
|
79
|
-
start = align_cell(cell_length, widths[i], alignments[i])
|
80
|
-
row[i].prepend(' ' * start)
|
81
|
-
row[i] += ' ' * (widths[i] - start - cell_length)
|
82
|
-
end
|
83
|
-
end
|
57
|
+
cols = rows.transpose
|
58
|
+
widths = cols.each_index.map {|i| column_width(cols[i].push(labels[i]))}
|
59
|
+
|
60
|
+
# Align the labels and cells.
|
61
|
+
labels = labels.each_index.map { |i|
|
62
|
+
aligned_cell(unsanitize(labels[i]), widths[i], alignments[i])
|
63
|
+
}
|
64
|
+
rows.map! { |row|
|
65
|
+
row.each_index.map { |i|
|
66
|
+
aligned_cell(unsanitize(row[i]), widths[i], alignments[i])
|
67
|
+
}
|
68
|
+
}
|
84
69
|
|
85
70
|
border = "\n|" + widths.map {|w| '=' * w}.join('|') + "|\n"
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
table += border
|
71
|
+
return (
|
72
|
+
border + [
|
73
|
+
'|' + labels.join('|') + '|',
|
74
|
+
rows.map {|row| '|' + row.join('|') + '|'}.join(border.tr('=', '-'))
|
75
|
+
].join(border) + border
|
76
|
+
).strip
|
93
77
|
|
94
|
-
return table.chomp
|
95
78
|
end
|
96
79
|
|
97
80
|
# Sanity checks for make_table.
|
@@ -119,43 +102,51 @@ class MarkdownTables
|
|
119
102
|
end
|
120
103
|
end
|
121
104
|
|
122
|
-
# Convert
|
123
|
-
# non-breaking
|
124
|
-
private_class_method def self.sanitize
|
105
|
+
# Convert some input to a string and replace any '|' characters with
|
106
|
+
# a non-breaking equivalent,
|
107
|
+
private_class_method def self.sanitize(input)
|
125
108
|
bar = '|' # Non-breaking HTML vertical bar.
|
126
|
-
|
127
|
-
|
109
|
+
return input.to_s.gsub('|', bar)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Replace non-breaking HTML characters with their plaintext counterparts.
|
113
|
+
private_class_method def self.unsanitize(input)
|
114
|
+
return input.gsub(/( )|(|)/, ' ' => ' ', '|' => '|')
|
128
115
|
end
|
129
116
|
|
130
117
|
# Generate the alignment line from a string or array.
|
131
|
-
# align must be a string or array
|
118
|
+
# align must be a string or array of strings.
|
132
119
|
# n: number of labels in the table to be created.
|
133
|
-
private_class_method def self.
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|a| a.downcase == 'l' ? ':-' : a.downcase == 'r' ? '-:' : ':-:'
|
140
|
-
}
|
141
|
-
if alignments.length < n
|
142
|
-
alignments += [':-:'] * (n - alignments.length)
|
143
|
-
end
|
144
|
-
alignment_line = alignments.join('|')
|
145
|
-
end
|
146
|
-
return alignment_line
|
120
|
+
private_class_method def self.parse_alignment(align, n)
|
121
|
+
align_map = {'l' => ':-', 'c' => ':-:', 'r' => '-:'}
|
122
|
+
alignments = align.map {|a| align_map[a]}
|
123
|
+
# If not enough values were given, center the remaining columns.
|
124
|
+
alignments.length < n && alignments += [':-:'] * (n - alignments.length)
|
125
|
+
return alignments.join('|')
|
147
126
|
end
|
148
127
|
|
149
|
-
#
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
return 1
|
128
|
+
# Align some text in a cell.
|
129
|
+
private_class_method def self.aligned_cell(text, width, align)
|
130
|
+
if align =~ /:-+:/ # Center alignment.
|
131
|
+
start = (width / 2) - (text.length / 2)
|
132
|
+
elsif align =~ /-+:/ # Right alignment.
|
133
|
+
start = width - text.length - 1
|
134
|
+
else # Left alignment.
|
135
|
+
start = 1
|
158
136
|
end
|
137
|
+
return ' ' * start + text + ' ' * (width - start - text.length)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Get the width for a column.
|
141
|
+
private_class_method def self.column_width(col)
|
142
|
+
# Pad each cell on either side and maintain a minimum 3 width of characters.
|
143
|
+
return [(!col.empty? ? col.map(&:length).max : 0) + 2, 3].max
|
144
|
+
end
|
145
|
+
|
146
|
+
# Add any missing empty values to a row.
|
147
|
+
private_class_method def self.fill(row, n)
|
148
|
+
row.length > n && raise('Sanity checks failed for fill')
|
149
|
+
return row.length < n ? row + ([''] * (n - row.length)) : row
|
159
150
|
end
|
160
151
|
|
161
152
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: markdown-tables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris de Graaf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: chrisadegraaf@gmail.com
|