tty 0.0.7 → 0.0.8

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.
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