tty 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/.travis.yml +0 -1
  2. data/README.md +141 -23
  3. data/benchmarks/table.rb +5 -0
  4. data/lib/tty/logger.rb +71 -0
  5. data/lib/tty/support/equatable.rb +6 -2
  6. data/lib/tty/system/which.rb +41 -0
  7. data/lib/tty/system.rb +8 -0
  8. data/lib/tty/table/border/ascii.rb +15 -16
  9. data/lib/tty/table/border/null.rb +9 -4
  10. data/lib/tty/table/border/unicode.rb +15 -16
  11. data/lib/tty/table/border.rb +69 -9
  12. data/lib/tty/table/border_dsl.rb +247 -0
  13. data/lib/tty/table/border_options.rb +52 -0
  14. data/lib/tty/table/field.rb +101 -0
  15. data/lib/tty/table/header.rb +115 -0
  16. data/lib/tty/table/operation/alignment_set.rb +14 -10
  17. data/lib/tty/table/operation/truncation.rb +19 -13
  18. data/lib/tty/table/operation/wrapped.rb +20 -9
  19. data/lib/tty/table/operations.rb +69 -0
  20. data/lib/tty/table/renderer/basic.rb +35 -26
  21. data/lib/tty/table/renderer.rb +13 -1
  22. data/lib/tty/table/row.rb +174 -0
  23. data/lib/tty/table.rb +96 -21
  24. data/lib/tty/text/truncation.rb +1 -1
  25. data/lib/tty/vector.rb +8 -7
  26. data/lib/tty/version.rb +1 -1
  27. data/lib/tty.rb +21 -0
  28. data/spec/tty/logger/new_spec.rb +36 -0
  29. data/spec/tty/logger/valid_level_spec.rb +33 -0
  30. data/spec/tty/system/platform_spec.rb +8 -0
  31. data/spec/tty/system/which_spec.rb +41 -0
  32. data/spec/tty/table/access_spec.rb +12 -1
  33. data/spec/tty/table/add_row_spec.rb +28 -0
  34. data/spec/tty/table/border/new_spec.rb +9 -4
  35. data/spec/tty/table/border/null/rendering_spec.rb +39 -1
  36. data/spec/tty/table/border/options/from_spec.rb +39 -0
  37. data/spec/tty/table/border/options/new_spec.rb +15 -0
  38. data/spec/tty/table/border/style_spec.rb +70 -0
  39. data/spec/tty/table/border_spec.rb +107 -0
  40. data/spec/tty/table/each_with_index_spec.rb +30 -0
  41. data/spec/tty/table/field/equality_spec.rb +51 -0
  42. data/spec/tty/table/field/new_spec.rb +29 -0
  43. data/spec/tty/table/field/width_spec.rb +21 -0
  44. data/spec/tty/table/header/call_spec.rb +30 -0
  45. data/spec/tty/table/header/new_spec.rb +25 -0
  46. data/spec/tty/table/header/set_spec.rb +15 -0
  47. data/spec/tty/table/header/to_ary_spec.rb +14 -0
  48. data/spec/tty/table/header_spec.rb +14 -0
  49. data/spec/tty/table/operation/alignment_set/align_rows_spec.rb +8 -1
  50. data/spec/tty/table/operation/truncation/call_spec.rb +27 -0
  51. data/spec/tty/table/operation/wrapped/call_spec.rb +27 -0
  52. data/spec/tty/table/operations/new_spec.rb +32 -0
  53. data/spec/tty/table/options_spec.rb +17 -9
  54. data/spec/tty/table/renderer/basic/alignment_spec.rb +76 -29
  55. data/spec/tty/table/renderer/basic/separator_spec.rb +99 -0
  56. data/spec/tty/table/renderer_spec.rb +7 -1
  57. data/spec/tty/table/renders_with_spec.rb +35 -28
  58. data/spec/tty/table/rotate_spec.rb +1 -0
  59. data/spec/tty/table/row/access_spec.rb +25 -0
  60. data/spec/tty/table/row/call_spec.rb +41 -0
  61. data/spec/tty/table/row/data_spec.rb +26 -0
  62. data/spec/tty/table/row/equality_spec.rb +73 -0
  63. data/spec/tty/table/row/new_spec.rb +41 -0
  64. data/spec/tty/table/row/to_ary_spec.rb +14 -0
  65. data/spec/tty/text/truncation/truncate_spec.rb +6 -0
  66. metadata +72 -10
data/.travis.yml CHANGED
@@ -16,5 +16,4 @@ matrix:
16
16
  allow_failures:
17
17
  - rvm: ruby-head
18
18
  - rvm: jruby-head
19
- - rvm: jruby-19mode
20
19
  - rvm: rbx-19mode
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # TTY
2
- [![Build Status](https://secure.travis-ci.org/peter-murach/tty.png?branch=master)][travis] [![Code Climate](https://codeclimate.com/badge.png)][codeclimate]
2
+ [![Gem Version](https://badge.fury.io/rb/tty.png)][gem]
3
+ [![Build Status](https://secure.travis-ci.org/peter-murach/tty.png?branch=master)][travis]
4
+ [![Code Climate](https://codeclimate.com/github/peter-murach/tty.png)][codeclimate]
3
5
 
6
+ [gem]: http://badge.fury.io/rb/tty
4
7
  [travis]: http://travis-ci.org/peter-murach/tty
5
8
  [codeclimate]: https://codeclimate.com/github/peter-murach/tty
6
9
 
@@ -10,14 +13,16 @@ Toolbox for developing CLI clients in Ruby. This library provides a fluid interf
10
13
 
11
14
  Jump-start development of your command line app:
12
15
 
13
- * Fully customizable table rendering with an easy-to-use API. (status: In Progress)
14
- * Terminal output colorization. (status: DONE)
15
- * Terminal & System detection utilities. (status: In Progress)
16
- * Text alignment/padding/indentation. (status: In Progress)
17
- * Shell user interface. (status: In Progress)
18
- * File diffs. (status: TODO)
19
- * Progress bar. (status: TODO)
20
- * Configuration file management. (status: TODO)
16
+ * Table rendering with an easy-to-use API [status: In Progress]
17
+ * Terminal output colorization. [status: ✔ ]
18
+ * Terminal & System detection utilities. [status: In Progress]
19
+ * Text manipulation(wrapping/truncation) [status: In Progress]
20
+ * Shell user interface. [status: In Progress]
21
+ * File diffs. [status: TODO]
22
+ * Progress bar. [status: TODO]
23
+ * Configuration file management. [status: TODO]
24
+ * Logging [status: In Progress]
25
+ * Plugin ecosystem [status: TODO]
21
26
  * Fully tested with major ruby interpreters.
22
27
  * No dependencies to allow for easy gem vendoring.
23
28
 
@@ -45,7 +50,6 @@ To instantiate table pass 2-dimensional array:
45
50
  table = TTY::Table[['a1', 'a2'], ['b1', 'b2']]
46
51
  table = TTY::Table.new [['a1', 'a2'], ['b1', 'b2']]
47
52
  table = TTY::Table.new rows: [['a1', 'a2'], ['b1', 'b2']]
48
-
49
53
  table = TTY::Table.new ['h1', 'h2'], [['a1', 'a2'], ['b1', 'b2']]
50
54
  table = TTY::Table.new header: ['h1', 'h2'], rows: [['a1', 'a2'], ['b1', 'b2']]
51
55
  ```
@@ -63,6 +67,8 @@ Apart from `rows` and `header`, you can provide other customization options such
63
67
  column_aligns # array of cell alignments out of :left, :center and :right
64
68
  renderer # enforce display type out of :basic, :color, :unicode, :ascii
65
69
  orientation # either :horizontal or :vertical
70
+ border # hash of border properties out of :characters, :style, :separator keys
71
+ width # constrain the table total width, otherwise dynamically calculated based on content and terminal size
66
72
  ```
67
73
 
68
74
  Table behaves like an Array so `<<`, `each` and familiar methods can be used
@@ -73,12 +79,15 @@ Table behaves like an Array so `<<`, `each` and familiar methods can be used
73
79
  table << ['a1', 'a2'] << ['b1', 'b2'] # chain rows assignment
74
80
 
75
81
  table.each { |row| ... } # iterate over rows
82
+ table.each_with_index # iterate over each element with row and column index
76
83
  table[i, j] # return element at row(i) and column(j)
77
84
  table.row(i) { ... } # return array for row(i)
78
85
  table.column(j) { ... } # return array for column(j)
86
+ table.column(name) # return array for column(name), name of header
79
87
  table.row_size # return row size
80
88
  table.column_size # return column size
81
89
  table.size # return an array of [row_size, column_size]
90
+ table.border # specify border properties
82
91
  ```
83
92
 
84
93
  or pass your rows in a block
@@ -99,7 +108,9 @@ And then to print do
99
108
  b1 b2 b3
100
109
  ```
101
110
 
102
- To print border around data table you need to specify `renderer` type out of `basic`, `ascii`, `unicode`. For instance to output unicode border:
111
+ #### Border
112
+
113
+ To print border around data table you need to specify `renderer` type out of `basic`, `ascii`, `unicode`. By default `basic` is used. For instance, to output unicode border:
103
114
 
104
115
  ```
105
116
  table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2'], renderer: 'unicode'
@@ -113,26 +124,132 @@ To print border around data table you need to specify `renderer` type out of `ba
113
124
  └───────┴───────┘
114
125
  ```
115
126
 
116
- You can also create your own custom border by subclassing `TTY::Table::Border`
127
+ You can also create your own custom border by subclassing `TTY::Table::Border` and implementing the `def_border` method using internal DSL methods like so:
117
128
 
118
129
  ```ruby
119
130
  class MyBorder < TTY::Table::Border
120
131
  def_border do
121
- {
122
- 'bottom' => ' ',
123
- 'bottom_mid' => '*',
124
- 'bottom_left' => '*',
125
- 'bottom_right' => '*',
126
- 'left' => '$',
127
- 'right' => '$'
128
- }
132
+ left '$'
133
+ center '$'
134
+ right '$'
135
+ bottom ' '
136
+ bottom_mid '*'
137
+ bottom_left '*'
138
+ bottom_right '*'
129
139
  end
130
140
  end
131
141
  ```
132
- Next pass the border to your table
142
+
143
+ Next pass the border class to your instantiated table
133
144
 
134
145
  ```ruby
146
+ table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2']
135
147
  table.renders_with MyBorder
148
+ table.to_s
149
+
150
+ $header1$header2$
151
+ $a1 $a2 $
152
+ * * *
153
+ ```
154
+
155
+ Finally, if you want to introduce slight modifications to the predefined border types, you can use table `border` helper like so
156
+
157
+ ```ruby
158
+ table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2']
159
+ table.border do
160
+ mid '='
161
+ mid_mid ' '
162
+ end
163
+
164
+ table.to_s
165
+
166
+ header1 header2
167
+ ======= =======
168
+ a1 a2
169
+ b1 b2
170
+ ```
171
+
172
+ In addition to specifying border characters you can force table to render separator line on each row like:
173
+
174
+ ```ruby
175
+ table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2']]
176
+ table.border.separator = :each_row
177
+ table.to_s
178
+
179
+ +-------+-------+
180
+ |header1|header2|
181
+ +-------+-------+
182
+ |a1 |a2 |
183
+ +-------+-------+
184
+ |b1 |b2 |
185
+ +-------+-------+
186
+ ```
187
+
188
+ Also to change the display color of your border do:
189
+
190
+ ```ruby
191
+ table.border.style = :red
192
+ ```
193
+
194
+ #### Alignment
195
+
196
+ All columns are left aligned by default. You can enforce per column alignment by passing `column_aligns` option like so
197
+
198
+ ```ruby
199
+ rows = [['a1', 'a2'], ['b1', 'b2']
200
+ table = TTY::Table.new rows: rows, column_aligns: [:center, :right]
201
+ ```
202
+
203
+ To align a single column do
204
+
205
+ ```ruby
206
+ table.align_column(1, :right)
207
+ ```
208
+
209
+ If you require a more granular alignment you can align individual fields in a row by passing `align` option
210
+
211
+ ```ruby
212
+ table = TTY::Table.new do |t|
213
+ t << ['a1', 'a2', 'a3']
214
+ t << ['b1', {:value => 'b2', :align => :right}, 'b3']
215
+ t << ['c1', 'c2', {:value => 'c3', :align => :center}]
216
+ end
217
+ ```
218
+
219
+ #### Style
220
+
221
+ To format individual fields/cells do
222
+
223
+ ```ruby
224
+ table = TTY::Table.new rows: rows, width: 40
225
+ ```
226
+
227
+ #### Filter
228
+
229
+ You can define filters that will modify individual table fields value before they are rendered. A filter can be a callable such as proc. Here's an example that formats
230
+
231
+ ```ruby
232
+ table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2']
233
+ table.filter = Proc.new do |val, row_index, col_index|
234
+ if col_index == 1 and !(row_index == 0)
235
+ val.capitalize
236
+ end
237
+ end
238
+ table.to_s
239
+
240
+ +-------+-------+
241
+ |header1|header2|
242
+ +-------+-------+
243
+ |a1 |A2 |
244
+ +-------+-------+
245
+ |b1 |B2 |
246
+ +-------+-------+
247
+
248
+ ```
249
+
250
+ To add background color to even fields do
251
+
252
+ ```ruby
136
253
  ```
137
254
 
138
255
  ### Terminal
@@ -241,8 +358,9 @@ on the other hand, if we are interested in range answer then
241
358
  ### System
242
359
 
243
360
  ```ruby
244
- TTY::System.unix? # => true
245
- TTY::System.windows? # => false
361
+ TTY::System.unix? # => true
362
+ TTY::System.windows? # => false
363
+ TTY::System.which(cmd) # full path to executable if found, nil otherwise
246
364
  ```
247
365
 
248
366
  ## Contributing
data/benchmarks/table.rb CHANGED
@@ -13,6 +13,7 @@ rows = (1..100).map { |n| ["row#{n}", "red"] }
13
13
  table = TTY::Table.new(header, rows)
14
14
  table_ascii = TTY::Table.new(header, rows, :renderer => :ascii)
15
15
  table_unicode = TTY::Table.new(header, rows, :renderer => :unicode)
16
+ table_color = TTY::Table.new(header, rows, :renderer => :ascii, :border => { :style => :red })
16
17
 
17
18
  Benchmark.ips do |r|
18
19
 
@@ -32,4 +33,8 @@ Benchmark.ips do |r|
32
33
  table_unicode.to_s
33
34
  end
34
35
 
36
+ r.report("TTY Color #to_s") do
37
+ table_color.to_s
38
+ end
39
+
35
40
  end
data/lib/tty/logger.rb ADDED
@@ -0,0 +1,71 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+
5
+ # A class providing logging system
6
+ class Logger
7
+ include TTY::Equatable
8
+
9
+ ALL = 0
10
+ INFO = 1
11
+ DEBUG = 2
12
+ WARN = 3
13
+ ERROR = 4
14
+ FATAL = 5
15
+ OFF = 6
16
+
17
+ MAX_LEVELS = 7
18
+
19
+ attr_reader :namespace
20
+
21
+ attr_reader :level
22
+
23
+ attr_reader :output
24
+
25
+ attr_reader :timestamp_format
26
+
27
+ # Initialize a Logger
28
+ #
29
+ # @param [String] name
30
+ #
31
+ # @param [Hash] options
32
+ #
33
+ # @option options [String] :output
34
+ #
35
+ # @api public
36
+ def initialize(options={})
37
+ @namespace = options.fetch(:namespace) { raise ArgumentError, "Logger must have namespace", caller }
38
+ @output = options.fetch(:output) { $stderr }
39
+ @level = options.fetch(:level) { ALL }
40
+ @timestamp_format = options.fetch(:timestamp_format) { '%Y-%m-%d %T' }
41
+ end
42
+
43
+ def level=(level)
44
+ validate_level(level)
45
+ @level = level
46
+ end
47
+
48
+ # @api public
49
+ def timestamp
50
+ Time.now.strftime(timestamp_format)
51
+ end
52
+
53
+ def validate_level(level)
54
+ unless valid_level?(level)
55
+ raise ArgumentError, "Log level must be 0..#{MAX_LEVELS}", caller
56
+ end
57
+ end
58
+
59
+ def self.valid_level?(level)
60
+ !level.nil? && level.kind_of?(Numeric) && level >= ALL && level <= OFF
61
+ end
62
+
63
+ # Print formatted log to output
64
+ #
65
+ # @api public
66
+ def log(message)
67
+ output.print timestamp + ' - ' + message
68
+ end
69
+
70
+ end # Logger
71
+ end # TTY
@@ -85,8 +85,9 @@ module TTY
85
85
  # @api private
86
86
  def define_compare
87
87
  define_method(:compare?) do |comparator, other|
88
- attrs = comparison_attrs || []
89
- !attrs.find { |attr| send(attr).send(comparator, other.send(attr)) }
88
+ klass = self.class
89
+ attrs = klass.comparison_attrs || []
90
+ attrs.all? { |attr| send(attr).send(comparator, other.send(attr)) }
90
91
  end
91
92
  end
92
93
 
@@ -142,6 +143,9 @@ module TTY
142
143
  #
143
144
  # @api public
144
145
  def ==(other)
146
+ print '== '
147
+ p self
148
+ p other
145
149
  return false unless self.class <=> other.class
146
150
  compare?(__method__, other)
147
151
  end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class System
5
+
6
+ # A class responsible for finding an executable in the PATH
7
+ class Which
8
+
9
+ # Find an executable in the PATH
10
+ #
11
+ # @param [String] command
12
+ # the command to search in the PATH
13
+ #
14
+ # @example
15
+ # which("ruby") # => /usr/local/bin/ruby
16
+ #
17
+ # @return [String]
18
+ # the full path to executable if found, `nil` otherwise
19
+ #
20
+ # @api public
21
+ def which(command)
22
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
23
+ default_system_path.each do |path|
24
+ exts.each do |ext|
25
+ exec = File.join("#{path}", "#{command}#{ext}")
26
+ return exec if File.executable? exec
27
+ end
28
+ end
29
+ return nil
30
+ end
31
+
32
+ # Find default system paths
33
+ #
34
+ # @api private
35
+ def default_system_path
36
+ ENV['PATH'].split(File::PATH_SEPARATOR)
37
+ end
38
+
39
+ end # Which
40
+ end # System
41
+ end # TTY
data/lib/tty/system.rb CHANGED
@@ -25,6 +25,14 @@ module TTY
25
25
  RbConfig::CONFIG['host_os'] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
26
26
  end
27
27
 
28
+ # Find an executable in the PATH
29
+ #
30
+ # @see TTY::System::Which
31
+ #
32
+ # @api public
33
+ def which(command)
34
+ Which.new(command)
35
+ end
28
36
  end
29
37
 
30
38
  end # System
@@ -8,22 +8,21 @@ module TTY
8
8
  class ASCII < Border
9
9
 
10
10
  def_border do
11
- {
12
- 'top' => '-',
13
- 'top_mid' => '+',
14
- 'top_left' => '+',
15
- 'top_right' => '+',
16
- 'bottom' => '-',
17
- 'bottom_mid' => '+',
18
- 'bottom_left' => '+',
19
- 'bottom_right' => '+',
20
- 'mid' => '-',
21
- 'mid_mid' => '+',
22
- 'mid_left' => '+',
23
- 'mid_right' => '+',
24
- 'left' => '|',
25
- 'right' => '|'
26
- }
11
+ top '-'
12
+ top_mid '+'
13
+ top_left '+'
14
+ top_right '+'
15
+ bottom '-'
16
+ bottom_mid '+'
17
+ bottom_left '+'
18
+ bottom_right '+'
19
+ mid '-'
20
+ mid_mid '+'
21
+ mid_left '+'
22
+ mid_right '+'
23
+ left '|'
24
+ center '|'
25
+ right '|'
27
26
  end
28
27
 
29
28
  end # ASCII
@@ -7,18 +7,23 @@ module TTY
7
7
  # A class that represents no border.
8
8
  class Null < Border
9
9
 
10
+ def_border do
11
+ center SPACE_CHAR
12
+ end
13
+
10
14
  # A stub top line
11
15
  #
12
16
  # @api private
13
17
  def top_line
14
- nil
18
+ border ? super : nil
15
19
  end
16
20
 
17
21
  # A stub separator line
18
22
  #
19
23
  # @api private
20
24
  def separator
21
- nil
25
+ return [] if border.separator == EACH_ROW
26
+ border ? super : nil
22
27
  end
23
28
 
24
29
  # A line spanning all columns delemited by space character.
@@ -27,14 +32,14 @@ module TTY
27
32
  #
28
33
  # @api private
29
34
  def row_line
30
- row.join(' ')
35
+ (border && !border.characters.empty?) ? super : row.join(SPACE_CHAR)
31
36
  end
32
37
 
33
38
  # A stub bottom line
34
39
  #
35
40
  # @api private
36
41
  def bottom_line
37
- nil
42
+ border ? super : nil
38
43
  end
39
44
 
40
45
  end # Null
@@ -8,22 +8,21 @@ module TTY
8
8
  class Unicode < Border
9
9
 
10
10
  def_border do
11
- {
12
- 'top' => '─',
13
- 'top_mid' => '┬',
14
- 'top_left' => '┌',
15
- 'top_right' => '┐',
16
- 'bottom' => '─',
17
- 'bottom_mid' => '┴',
18
- 'bottom_left' => '',
19
- 'bottom_right' => '┘',
20
- 'mid' => '─',
21
- 'mid_mid' => '┼',
22
- 'mid_left' => '├',
23
- 'mid_right' => '┤',
24
- 'left' => '│',
25
- 'right' => '│'
26
- }
11
+ top '─'
12
+ top_mid ''
13
+ top_left ''
14
+ top_right ''
15
+ bottom ''
16
+ bottom_mid ''
17
+ bottom_left ''
18
+ bottom_right ''
19
+ mid ''
20
+ mid_mid ''
21
+ mid_left ''
22
+ mid_right ''
23
+ left ''
24
+ center '│'
25
+ right '│'
27
26
  end
28
27
 
29
28
  end # Unicode
@@ -6,6 +6,14 @@ module TTY
6
6
  # Abstract base class that is responsible for building the table border.
7
7
  class Border
8
8
  include Unicode
9
+ include TTY::Equatable
10
+
11
+ EMPTY_CHAR = ''.freeze
12
+
13
+ SPACE_CHAR = ' '.freeze
14
+
15
+ # Represent a separtor on each row
16
+ EACH_ROW = :each_row
9
17
 
10
18
  # The row cell widths
11
19
  #
@@ -19,6 +27,9 @@ module TTY
19
27
  attr_reader :row
20
28
  private :row
21
29
 
30
+ # The table custom border characters
31
+ attr_reader :border
32
+
22
33
  class << self
23
34
  # Store characters for border
24
35
  #
@@ -28,23 +39,36 @@ module TTY
28
39
 
29
40
  # Instantiate a new object
30
41
  #
42
+ # @param [Array] row
43
+ #
44
+ # @param [BorderOptions] options
45
+ #
31
46
  # @return [Object]
32
47
  #
33
48
  # @api private
34
- def initialize(row=nil)
49
+ def initialize(row, options=nil)
35
50
  if self.class == Border
36
51
  raise NotImplementedError, "#{self} is an abstract class"
37
52
  else
38
53
  @row = row
39
54
  @widths = row.map { |cell| cell.chars.to_a.size }
55
+ @border = TTY::Table::BorderOptions.from options
40
56
  end
41
57
  end
42
58
 
43
59
  # Define border characters
44
60
  #
61
+ # @param [Hash] characters
62
+ # the border characters
63
+ #
64
+ # @return [Hash]
65
+ #
45
66
  # @api public
46
- def self.def_border(&block)
47
- @characters = block
67
+ def self.def_border(characters=(not_set=true), &block)
68
+ return self.characters = characters if !not_set
69
+
70
+ dsl = TTY::Table::BorderDSL.new(&block)
71
+ self.characters = dsl.characters
48
72
  end
49
73
 
50
74
  # Retrive individula character by type
@@ -56,7 +80,31 @@ module TTY
56
80
  #
57
81
  # @api private
58
82
  def [](type)
59
- self.class.characters.call[type] || ''
83
+ characters = self.class.characters
84
+ chars = border.nil? ? characters : characters.merge(border.characters)
85
+ chars[type] || EMPTY_CHAR
86
+ end
87
+
88
+ # Check if border color is set
89
+ #
90
+ # @return [Boolean]
91
+ #
92
+ # @api public
93
+ def color?
94
+ border && border.style
95
+ end
96
+
97
+ # Set color on characters
98
+ #
99
+ # @param [Symbol] color
100
+ #
101
+ # @param [Array[String]] array of strings
102
+ #
103
+ # @return [Array[String]]
104
+ #
105
+ # @api public
106
+ def self.set_color(color, *strings)
107
+ strings.map { |string| TTY.terminal.color.set(string, color) }
60
108
  end
61
109
 
62
110
  # A line spanning all columns marking top of a table.
@@ -83,7 +131,15 @@ module TTY
83
131
  #
84
132
  # @api private
85
133
  def row_line
86
- result = self['left'] + row.join(self['right']) + self['right']
134
+ right_char = self['right']
135
+ left_char = self['left']
136
+ center_char = self['center']
137
+
138
+ if color?
139
+ right_char, center_char, left_char = Border.set_color(border.style, right_char, center_char, left_char)
140
+ end
141
+
142
+ result = left_char + row.join(center_char) + right_char
87
143
  result.empty? ? nil : result
88
144
  end
89
145
 
@@ -106,10 +162,14 @@ module TTY
106
162
  # @api private
107
163
  def render(type)
108
164
  type = type.to_s
109
- render_line self[type],
110
- self["#{type}_left"] || self[type],
111
- self["#{type}_right"] || self[type],
112
- self["#{type}_mid"]
165
+ border_char = self[type]
166
+ line = render_line(border_char,
167
+ self["#{type}_left"] || border_char,
168
+ self["#{type}_right"] || border_char,
169
+ self["#{type}_mid"])
170
+
171
+ line = Border.set_color(border.style, line) if color?
172
+ line
113
173
  end
114
174
 
115
175
  # Generate a border string