tty 0.0.9 → 0.0.10
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.
- data/.rspec +2 -1
- data/.travis.yml +3 -6
- data/README.md +232 -134
- data/lib/tty/plugins/plugin.rb +56 -0
- data/lib/tty/plugins.rb +75 -0
- data/lib/tty/shell/suggestion.rb +102 -0
- data/lib/tty/shell.rb +41 -14
- data/lib/tty/system/editor.rb +111 -0
- data/lib/tty/system/which.rb +13 -1
- data/lib/tty/system.rb +44 -28
- data/lib/tty/table/border/null.rb +0 -9
- data/lib/tty/table/border/row_line.rb +21 -0
- data/lib/tty/table/border.rb +63 -32
- data/lib/tty/table/border_dsl.rb +1 -1
- data/lib/tty/table/column_set.rb +16 -17
- data/lib/tty/table/field.rb +27 -7
- data/lib/tty/table/header.rb +18 -9
- data/lib/tty/table/operation/alignment_set.rb +20 -25
- data/lib/tty/table/operation/escape.rb +30 -0
- data/lib/tty/table/operation/filter.rb +36 -0
- data/lib/tty/table/operation/truncation.rb +22 -11
- data/lib/tty/table/operation/wrapped.rb +21 -10
- data/lib/tty/table/operations.rb +10 -8
- data/lib/tty/table/orientation/horizontal.rb +1 -1
- data/lib/tty/table/renderer/ascii.rb +3 -3
- data/lib/tty/table/renderer/basic.rb +135 -65
- data/lib/tty/table/renderer/color.rb +1 -4
- data/lib/tty/table/renderer/unicode.rb +3 -3
- data/lib/tty/table/renderer.rb +48 -61
- data/lib/tty/table/row.rb +30 -3
- data/lib/tty/table/transformation.rb +38 -0
- data/lib/tty/table/validatable.rb +7 -5
- data/lib/tty/table.rb +78 -99
- data/lib/tty/terminal/color.rb +2 -2
- data/lib/tty/terminal/echo.rb +1 -1
- data/lib/tty/terminal/pager/basic.rb +52 -0
- data/lib/tty/terminal/pager/system.rb +39 -0
- data/lib/tty/terminal/pager.rb +95 -0
- data/lib/tty/terminal.rb +30 -1
- data/lib/tty/version.rb +1 -1
- data/lib/tty.rb +41 -1
- data/spec/spec_helper.rb +20 -0
- data/spec/tty/plugins/find_spec.rb +28 -0
- data/spec/tty/plugins/load_spec.rb +20 -0
- data/spec/tty/plugins/plugin/load_spec.rb +30 -0
- data/spec/tty/plugins/plugin/new_spec.rb +18 -0
- data/spec/tty/shell/suggest_spec.rb +50 -0
- data/spec/tty/support/conversion_spec.rb +3 -3
- data/spec/tty/support/delegatable_spec.rb +1 -1
- data/spec/tty/support/equatable_spec.rb +6 -9
- data/spec/tty/system/editor/available_spec.rb +40 -0
- data/spec/tty/system/editor/build_spec.rb +40 -0
- data/spec/tty/system/editor/command_spec.rb +16 -0
- data/spec/tty/system/editor/executables_spec.rb +13 -0
- data/spec/tty/system/editor/invoke_spec.rb +38 -0
- data/spec/tty/system/editor/open_spec.rb +27 -0
- data/spec/tty/system/platform_spec.rb +4 -6
- data/spec/tty/system/which/which_spec.rb +48 -0
- data/spec/tty/system/which_spec.rb +8 -34
- data/spec/tty/table/border/ascii/rendering_spec.rb +19 -5
- data/spec/tty/table/border/new_spec.rb +1 -1
- data/spec/tty/table/border/null/rendering_spec.rb +24 -8
- data/spec/tty/table/border/unicode/rendering_spec.rb +19 -5
- data/spec/tty/table/column_set/extract_widths_spec.rb +4 -15
- data/spec/tty/table/column_set/total_width_spec.rb +15 -0
- data/spec/tty/table/data_spec.rb +14 -0
- data/spec/tty/table/each_spec.rb +17 -4
- data/spec/tty/table/each_with_index_spec.rb +34 -6
- data/spec/tty/table/field/length_spec.rb +21 -0
- data/spec/tty/table/field/lines_spec.rb +21 -0
- data/spec/tty/table/filter_spec.rb +23 -0
- data/spec/tty/table/header/call_spec.rb +1 -1
- data/spec/tty/table/header/height_spec.rb +27 -0
- data/spec/tty/table/initialize_spec.rb +6 -6
- data/spec/tty/table/operation/alignment_set/call_spec.rb +39 -0
- data/spec/tty/table/operation/escape/call_spec.rb +16 -0
- data/spec/tty/table/operation/filter/call_spec.rb +17 -0
- data/spec/tty/table/operation/truncation/call_spec.rb +15 -10
- data/spec/tty/table/operation/truncation/truncate_spec.rb +1 -1
- data/spec/tty/table/operation/wrapped/call_spec.rb +15 -10
- data/spec/tty/table/operation/wrapped/wrap_spec.rb +1 -1
- data/spec/tty/table/operations/new_spec.rb +4 -4
- data/spec/tty/table/options_spec.rb +0 -28
- data/spec/tty/table/orientation_spec.rb +5 -6
- data/spec/tty/table/properties_spec.rb +1 -4
- data/spec/tty/table/render_spec.rb +57 -0
- data/spec/tty/table/{renders_with_spec.rb → render_with_spec.rb} +29 -10
- data/spec/tty/table/renderer/ascii/render_spec.rb +68 -0
- data/spec/tty/table/renderer/ascii/separator_spec.rb +28 -0
- data/spec/tty/table/renderer/basic/alignment_spec.rb +18 -16
- data/spec/tty/table/renderer/basic/extract_column_widths_spec.rb +17 -12
- data/spec/tty/table/renderer/basic/filter_spec.rb +53 -0
- data/spec/tty/table/renderer/basic/multiline_content_spec.rb +135 -0
- data/spec/tty/table/renderer/basic/new_spec.rb +13 -2
- data/spec/tty/table/renderer/basic/options_spec.rb +48 -0
- data/spec/tty/table/renderer/basic/render_spec.rb +19 -121
- data/spec/tty/table/renderer/basic/separator_spec.rb +14 -48
- data/spec/tty/table/renderer/basic/truncation_spec.rb +35 -0
- data/spec/tty/table/renderer/basic/wrapping_spec.rb +40 -0
- data/spec/tty/table/{border_spec.rb → renderer/border_spec.rb} +17 -20
- data/spec/tty/table/renderer/select_spec.rb +22 -0
- data/spec/tty/table/{border → renderer}/style_spec.rb +13 -14
- data/spec/tty/table/renderer/unicode/render_spec.rb +68 -0
- data/spec/tty/table/renderer/unicode/separator_spec.rb +26 -0
- data/spec/tty/table/rotate_spec.rb +2 -3
- data/spec/tty/table/row/call_spec.rb +1 -1
- data/spec/tty/table/row/each_spec.rb +31 -0
- data/spec/tty/table/row/height_spec.rb +27 -0
- data/spec/tty/table/to_s_spec.rb +3 -3
- data/spec/tty/table/transformation/extract_tuples_spec.rb +35 -0
- data/spec/tty/table/validatable/validate_options_spec.rb +1 -2
- data/spec/tty/terminal/home_spec.rb +3 -3
- data/spec/tty/terminal/page_spec.rb +13 -0
- data/spec/tty/terminal/pager/available_spec.rb +40 -0
- data/spec/tty/terminal/pager/basic/page_spec.rb +54 -0
- data/spec/tty/terminal/pager/command_spec.rb +16 -0
- data/spec/tty/terminal/pager/executables_spec.rb +13 -0
- data/spec/tty/terminal/pager/page_spec.rb +47 -0
- data/spec/tty/terminal/pager/system/page_spec.rb +29 -0
- data/spec/tty/text/distance/distance_spec.rb +12 -0
- data/tty.gemspec +7 -3
- metadata +160 -27
- data/spec/tty/table/operation/alignment_set/align_rows_spec.rb +0 -53
- data/spec/tty/table/renderer/pick_renderer_spec.rb +0 -25
- data/spec/tty/table/renderer_spec.rb +0 -49
data/lib/tty/plugins.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
|
5
|
+
# A class responsible for managing plugins installation
|
6
|
+
class Plugins
|
7
|
+
|
8
|
+
PLUGIN_PREFIX = 'tty'
|
9
|
+
|
10
|
+
attr_accessor :plugins
|
11
|
+
private :plugins
|
12
|
+
|
13
|
+
# Initialize the Plugins
|
14
|
+
#
|
15
|
+
# @api public
|
16
|
+
def initialize
|
17
|
+
@plugins = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Load all plugins that are not enabled
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def load
|
24
|
+
plugins.each do |plugin|
|
25
|
+
plugin.load! unless plugin.enabled?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Register plugin with name in internal array
|
30
|
+
#
|
31
|
+
# @param [String] name
|
32
|
+
#
|
33
|
+
# @param [TTY::Plugin] plugin
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
def register(name, plugin=false)
|
37
|
+
if plugin && !loaded?(name)
|
38
|
+
plugins << plugin
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Find all installed TTY plugins and store them
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
def find
|
46
|
+
Gem.refresh
|
47
|
+
Gem::Specification.each do |gem|
|
48
|
+
next unless gem.name =~ /^#{PLUGIN_PREFIX}/
|
49
|
+
plugin_name = gem.name[/^#{PLUGIN_PREFIX}-(.*)/, 1]
|
50
|
+
register(plugin_name, Plugin.new(plugin_name, gem))
|
51
|
+
end
|
52
|
+
plugins
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return a list of all plugin names as strings
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
def names
|
59
|
+
plugins.inject(Hash.new) do |hash, plugin|
|
60
|
+
hash[plugin.name] = plugin
|
61
|
+
hash
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Check if plugin is already loaded
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
def loaded?(name)
|
71
|
+
plugins.any? { |plugin| plugin.gem_name == name }
|
72
|
+
end
|
73
|
+
|
74
|
+
end # PluginManager
|
75
|
+
end # TTY
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
# A class responsible for shell prompt interactions.
|
5
|
+
class Shell
|
6
|
+
|
7
|
+
# A class representing a suggestion
|
8
|
+
class Suggestion
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
attr_reader :shell
|
12
|
+
private :shell
|
13
|
+
|
14
|
+
# Number of spaces
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
attr_reader :indent
|
18
|
+
|
19
|
+
# Text for a single suggestion
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
attr_reader :single_text
|
23
|
+
|
24
|
+
# Text for multiple suggestions
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
attr_reader :plural_text
|
28
|
+
|
29
|
+
DEFAULT_INDENT = 8
|
30
|
+
|
31
|
+
SINGLE_TEXT = 'Did you mean this?'
|
32
|
+
|
33
|
+
PLURAL_TEXT = 'Did you mean one of these?'
|
34
|
+
|
35
|
+
# Initialize a Suggestion
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def initialize(options={})
|
39
|
+
@indent = options.fetch(:indent) { DEFAULT_INDENT }
|
40
|
+
@single_text = options.fetch(:single_text) { SINGLE_TEXT }
|
41
|
+
@plural_text = options.fetch(:plural_text) { PLURAL_TEXT }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Suggest matches out of possibile strings
|
45
|
+
#
|
46
|
+
# @param [String] message
|
47
|
+
#
|
48
|
+
# @param [Array[String]] possibilities
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
def suggest(message, possibilities)
|
52
|
+
distances = measure_distances(message, possibilities)
|
53
|
+
minimum_distance = distances.keys.min
|
54
|
+
max_distance = distances.keys.max
|
55
|
+
|
56
|
+
if minimum_distance < max_distance
|
57
|
+
suggestions = distances[minimum_distance].sort
|
58
|
+
evaluate(suggestions)
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Measure distances between messag and possibilities
|
65
|
+
#
|
66
|
+
# @param [String] message
|
67
|
+
#
|
68
|
+
# @param [Array[String]] possibilities
|
69
|
+
#
|
70
|
+
# @return [Hash]
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
def measure_distances(message, possibilities)
|
74
|
+
distances = Hash.new { |hash, key| hash[key] = [] }
|
75
|
+
|
76
|
+
possibilities.each do |possibility|
|
77
|
+
distances[Text.distance(message, possibility)] << possibility
|
78
|
+
end
|
79
|
+
distances
|
80
|
+
end
|
81
|
+
|
82
|
+
# Build up a suggestion string
|
83
|
+
#
|
84
|
+
# @param [Array[String]] suggestions
|
85
|
+
#
|
86
|
+
# @return [String]
|
87
|
+
#
|
88
|
+
# @api private
|
89
|
+
def evaluate(suggestions)
|
90
|
+
suggestion = ""
|
91
|
+
if suggestions.one?
|
92
|
+
suggestion << single_text + "\n"
|
93
|
+
suggestion << (" " * indent + suggestions.first)
|
94
|
+
else
|
95
|
+
suggestion << plural_text + "\n"
|
96
|
+
suggestion << suggestions.map { |suggestion| " " * indent + suggestion }.join("\n")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end # Suggestion
|
101
|
+
end # Shell
|
102
|
+
end # TTY
|
data/lib/tty/shell.rb
CHANGED
@@ -135,30 +135,57 @@ module TTY
|
|
135
135
|
args.each { |message| say message, options.merge(:color => :red) }
|
136
136
|
end
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
138
|
+
# Takes the string provided by the user and compare it with other possible
|
139
|
+
# matches to suggest an unambigous string
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# shell.suggest('sta', ['status', 'stage', 'commit', 'branch'])
|
143
|
+
# # => "status, stage"
|
144
|
+
#
|
145
|
+
# @param [String] message
|
146
|
+
#
|
147
|
+
# @param [Array] possibilities
|
148
|
+
#
|
149
|
+
# @param [Hash] options
|
150
|
+
# @option options [String] :indent
|
151
|
+
# The number of spaces for indentation
|
152
|
+
# @option options [String] :single_text
|
153
|
+
# The text for a single suggestion
|
154
|
+
# @option options [String] :plural_text
|
155
|
+
# The text for multiple suggestions
|
156
|
+
#
|
157
|
+
# @return [String]
|
158
|
+
#
|
159
|
+
# @api public
|
160
|
+
def suggest(message, possibilities, options={})
|
161
|
+
suggestion = Suggestion.new(options)
|
162
|
+
say(suggestion.suggest(message, possibilities))
|
149
163
|
end
|
150
164
|
|
151
165
|
# Print a table to shell.
|
152
166
|
#
|
167
|
+
# @example of a table with rows rendered with ascii border
|
168
|
+
# rows = [[1], [2], [3]]
|
169
|
+
# TTY.shell.print_table rows, renderer: :ascii
|
170
|
+
#
|
153
171
|
# @return [undefined]
|
154
172
|
#
|
155
173
|
# @api public
|
156
174
|
def print_table(*args, &block)
|
157
|
-
|
158
|
-
|
175
|
+
options = Utils.extract_options!(args)
|
176
|
+
renderer = options.fetch(:renderer) { :basic }
|
177
|
+
table = TTY::Table.new(*args, &block)
|
178
|
+
say table.render(renderer, options)
|
159
179
|
end
|
160
180
|
|
161
|
-
|
181
|
+
# Check if outputing to shell
|
182
|
+
#
|
183
|
+
# @return [Boolean]
|
184
|
+
#
|
185
|
+
# @api public
|
186
|
+
def tty?
|
187
|
+
stdout.tty?
|
188
|
+
end
|
162
189
|
|
163
190
|
def stdin
|
164
191
|
$stdin
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'shellwords'
|
4
|
+
|
5
|
+
module TTY
|
6
|
+
class System
|
7
|
+
|
8
|
+
# A class responsible for launching an editor
|
9
|
+
class Editor
|
10
|
+
|
11
|
+
attr_reader :file
|
12
|
+
|
13
|
+
# Initialize an Editor
|
14
|
+
#
|
15
|
+
# @param [String] file
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def initialize(file)
|
19
|
+
@file = file
|
20
|
+
end
|
21
|
+
|
22
|
+
# List possible executable for editor command
|
23
|
+
#
|
24
|
+
# @return [Array[String]]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def self.executables
|
28
|
+
[ ENV['VISUAL'], ENV['EDITOR'], 'vi', 'emacs' ]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Find available command
|
32
|
+
#
|
33
|
+
# @param [Array[String]] commands
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def self.available(*commands)
|
39
|
+
commands = commands.empty? ? self.executables : commands
|
40
|
+
commands.compact.uniq.find { |cmd| System.exists?(cmd) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Finds command using a configured command(s) or detected shell commands.
|
44
|
+
#
|
45
|
+
# @param [Array[String]] commands
|
46
|
+
#
|
47
|
+
# @return [String]
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def self.command(*commands)
|
51
|
+
@command = if (@command && commands.empty?)
|
52
|
+
@command
|
53
|
+
else
|
54
|
+
available(*commands)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Open file in system editor
|
59
|
+
#
|
60
|
+
# @param [String] file
|
61
|
+
# the name of the file
|
62
|
+
#
|
63
|
+
# @raise [TTY::CommandInvocationError]
|
64
|
+
#
|
65
|
+
# @return [Object]
|
66
|
+
#
|
67
|
+
# @api public
|
68
|
+
def self.open(file)
|
69
|
+
unless self.command
|
70
|
+
raise CommandInvocationError, "Please export $VISUAL or $EDITOR"
|
71
|
+
exit 1
|
72
|
+
end
|
73
|
+
|
74
|
+
new(file).invoke
|
75
|
+
end
|
76
|
+
|
77
|
+
# Build invocation command for editor
|
78
|
+
#
|
79
|
+
# @return [String]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
def build
|
83
|
+
escaped_file = if System.unix?
|
84
|
+
# Escape file string so it can be safely used in a Bourne shell
|
85
|
+
Shellwords.shellescape(file)
|
86
|
+
elsif System.windows?
|
87
|
+
file.gsub(/\//, '\\')
|
88
|
+
else
|
89
|
+
file
|
90
|
+
end
|
91
|
+
"#{Editor.command} #{escaped_file}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Inovke editor command in a shell
|
95
|
+
#
|
96
|
+
# @raise [TTY::CommandInvocationError]
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
def invoke
|
100
|
+
command_invocation = build
|
101
|
+
status = system(*Shellwords.split(command_invocation))
|
102
|
+
|
103
|
+
unless status
|
104
|
+
raise CommandInvocationError, "`#{command_invocation}` failed with status: #{$? ? $?.exitstatus : nil}"
|
105
|
+
exit status
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end # Editor
|
110
|
+
end # System
|
111
|
+
end # TTY
|
data/lib/tty/system/which.rb
CHANGED
@@ -6,6 +6,18 @@ module TTY
|
|
6
6
|
# A class responsible for finding an executable in the PATH
|
7
7
|
class Which
|
8
8
|
|
9
|
+
attr_reader :command
|
10
|
+
|
11
|
+
# Initialize a Which
|
12
|
+
#
|
13
|
+
# @param [String] command
|
14
|
+
# the command to find
|
15
|
+
#
|
16
|
+
# @api public
|
17
|
+
def initialize(command)
|
18
|
+
@command = command
|
19
|
+
end
|
20
|
+
|
9
21
|
# Find an executable in the PATH
|
10
22
|
#
|
11
23
|
# @param [String] command
|
@@ -18,7 +30,7 @@ module TTY
|
|
18
30
|
# the full path to executable if found, `nil` otherwise
|
19
31
|
#
|
20
32
|
# @api public
|
21
|
-
def which
|
33
|
+
def which
|
22
34
|
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
23
35
|
default_system_path.each do |path|
|
24
36
|
exts.each do |ext|
|
data/lib/tty/system.rb
CHANGED
@@ -5,34 +5,50 @@ require 'rbconfig'
|
|
5
5
|
module TTY
|
6
6
|
class System
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
8
|
+
# Check if windows platform.
|
9
|
+
#
|
10
|
+
# @return [Boolean]
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def self.windows?
|
14
|
+
RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/
|
15
|
+
end
|
16
|
+
|
17
|
+
# Check if unix platform
|
18
|
+
#
|
19
|
+
# @return [Boolean]
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
def self.unix?
|
23
|
+
RbConfig::CONFIG['host_os'] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
|
24
|
+
end
|
25
|
+
|
26
|
+
# Find an executable in the PATH
|
27
|
+
#
|
28
|
+
# @see TTY::System::Which
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def self.which(command)
|
32
|
+
Which.new(command).which
|
33
|
+
end
|
34
|
+
|
35
|
+
# Check if command is available
|
36
|
+
#
|
37
|
+
# @param [String] name
|
38
|
+
# the command name
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
def self.exists?(name)
|
42
|
+
!!self.which(name)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Proxy to editor object
|
46
|
+
#
|
47
|
+
# @return [TTY::System::Editor]
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def self.editor
|
51
|
+
TTY::System::Editor
|
36
52
|
end
|
37
53
|
|
38
54
|
end # System
|
@@ -26,15 +26,6 @@ module TTY
|
|
26
26
|
border ? super : nil
|
27
27
|
end
|
28
28
|
|
29
|
-
# A line spanning all columns delemited by space character.
|
30
|
-
#
|
31
|
-
# @return [String]
|
32
|
-
#
|
33
|
-
# @api private
|
34
|
-
def row_line
|
35
|
-
(border && !border.characters.empty?) ? super : row.join(SPACE_CHAR)
|
36
|
-
end
|
37
|
-
|
38
29
|
# A stub bottom line
|
39
30
|
#
|
40
31
|
# @api private
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Table
|
5
|
+
class Border
|
6
|
+
|
7
|
+
# A class for a table row line chars manipulation
|
8
|
+
class RowLine < Struct.new(:left, :center, :right)
|
9
|
+
|
10
|
+
# Colorize characters with a given style
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def colorize(style)
|
14
|
+
colorized_chars = Border.set_color(style, right, center, left)
|
15
|
+
self.right, self.center, self.left = colorized_chars
|
16
|
+
end
|
17
|
+
|
18
|
+
end # RowLine
|
19
|
+
end # Border
|
20
|
+
end # Table
|
21
|
+
end # TTY
|
data/lib/tty/table/border.rb
CHANGED
@@ -15,18 +15,12 @@ module TTY
|
|
15
15
|
# Represent a separtor on each row
|
16
16
|
EACH_ROW = :each_row
|
17
17
|
|
18
|
-
# The row
|
18
|
+
# The row field widths
|
19
19
|
#
|
20
20
|
# @api private
|
21
21
|
attr_reader :widths
|
22
22
|
private :widths
|
23
23
|
|
24
|
-
# The table row
|
25
|
-
#
|
26
|
-
# @api private
|
27
|
-
attr_reader :row
|
28
|
-
private :row
|
29
|
-
|
30
24
|
# The table custom border characters
|
31
25
|
attr_reader :border
|
32
26
|
|
@@ -39,19 +33,19 @@ module TTY
|
|
39
33
|
|
40
34
|
# Instantiate a new object
|
41
35
|
#
|
42
|
-
# @param [Array]
|
36
|
+
# @param [Array] column_widths
|
37
|
+
# the table column widths
|
43
38
|
#
|
44
39
|
# @param [BorderOptions] options
|
45
40
|
#
|
46
41
|
# @return [Object]
|
47
42
|
#
|
48
43
|
# @api private
|
49
|
-
def initialize(
|
44
|
+
def initialize(column_widths, options = nil)
|
50
45
|
if self.class == Border
|
51
46
|
raise NotImplementedError, "#{self} is an abstract class"
|
52
47
|
else
|
53
|
-
@
|
54
|
-
@widths = row.map { |cell| cell.chars.to_a.size }
|
48
|
+
@widths = column_widths
|
55
49
|
@border = TTY::Table::BorderOptions.from options
|
56
50
|
end
|
57
51
|
end
|
@@ -65,7 +59,7 @@ module TTY
|
|
65
59
|
#
|
66
60
|
# @api public
|
67
61
|
def self.def_border(characters=(not_set=true), &block)
|
68
|
-
return self.characters = characters
|
62
|
+
return self.characters = characters unless not_set
|
69
63
|
|
70
64
|
dsl = TTY::Table::BorderDSL.new(&block)
|
71
65
|
self.characters = dsl.characters
|
@@ -116,6 +110,15 @@ module TTY
|
|
116
110
|
(result = render(:top)).empty? ? nil : result
|
117
111
|
end
|
118
112
|
|
113
|
+
# A line spannig all columns marking bottom of a table.
|
114
|
+
#
|
115
|
+
# @return [String]
|
116
|
+
#
|
117
|
+
# @api private
|
118
|
+
def bottom_line
|
119
|
+
(result = render(:bottom)).empty? ? nil : result
|
120
|
+
end
|
121
|
+
|
119
122
|
# A line spanning all columns delemeting rows in a table.
|
120
123
|
#
|
121
124
|
# @return [String]
|
@@ -125,35 +128,61 @@ module TTY
|
|
125
128
|
(result = render(:mid)).empty? ? nil : result
|
126
129
|
end
|
127
130
|
|
128
|
-
# A line spanning all columns delemeting
|
131
|
+
# A line spanning all columns delemeting fields in a row.
|
132
|
+
#
|
133
|
+
# @param [TTY::Table::Row] row
|
134
|
+
# the table row
|
129
135
|
#
|
130
136
|
# @return [String]
|
131
137
|
#
|
132
|
-
# @api
|
133
|
-
def row_line
|
134
|
-
|
135
|
-
|
136
|
-
center_char = self['center']
|
138
|
+
# @api public
|
139
|
+
def row_line(row)
|
140
|
+
line = RowLine.new(self['left'], self['center'], self['right'])
|
141
|
+
line.colorize(border.style) if color?
|
137
142
|
|
138
|
-
|
139
|
-
|
140
|
-
|
143
|
+
result = row_heights(row, line)
|
144
|
+
result.empty? ? EMPTY_CHAR : result
|
145
|
+
end
|
141
146
|
|
142
|
-
|
143
|
-
|
147
|
+
protected
|
148
|
+
|
149
|
+
# Separate multiline string into individual rows with border.
|
150
|
+
#
|
151
|
+
# @param [TTY::Table::Row] row
|
152
|
+
# the table row
|
153
|
+
#
|
154
|
+
# @param [TTY::Table::Border::RowLine] line
|
155
|
+
#
|
156
|
+
# @api private
|
157
|
+
def row_heights(row, line)
|
158
|
+
if row.size > 0
|
159
|
+
row.height.times.map do |line_index|
|
160
|
+
row_height_line(row, line_index, line)
|
161
|
+
end.join("\n")
|
162
|
+
else
|
163
|
+
line.left + line.right
|
164
|
+
end
|
144
165
|
end
|
145
166
|
|
146
|
-
#
|
167
|
+
# Generate border for a given multiline row
|
168
|
+
#
|
169
|
+
# @param [TTY::Table::Row] row
|
170
|
+
# the table row
|
171
|
+
#
|
172
|
+
# @param [Integer] line
|
173
|
+
# the index for current line inside multiline
|
174
|
+
#
|
175
|
+
# @param [TTY::Table::Border::RowLine] line
|
147
176
|
#
|
148
177
|
# @return [String]
|
149
178
|
#
|
150
179
|
# @api private
|
151
|
-
def
|
152
|
-
|
180
|
+
def row_height_line(row, line_index, line)
|
181
|
+
line.left + row.fields.each_with_index.map do |field, index|
|
182
|
+
(field.lines[line_index] || EMPTY_CHAR).ljust(widths[index])
|
183
|
+
end.join(line.center) + line.right
|
153
184
|
end
|
154
185
|
|
155
|
-
protected
|
156
|
-
|
157
186
|
# Generate particular border type
|
158
187
|
#
|
159
188
|
# @param [String] type
|
@@ -164,11 +193,13 @@ module TTY
|
|
164
193
|
type = type.to_s
|
165
194
|
border_char = self[type]
|
166
195
|
line = render_line(border_char,
|
167
|
-
|
168
|
-
|
169
|
-
|
196
|
+
self["#{type}_left"] || border_char,
|
197
|
+
self["#{type}_right"] || border_char,
|
198
|
+
self["#{type}_mid"])
|
170
199
|
|
171
|
-
|
200
|
+
if color? && !line.empty?
|
201
|
+
line = Border.set_color(border.style, line)
|
202
|
+
end
|
172
203
|
line
|
173
204
|
end
|
174
205
|
|
data/lib/tty/table/border_dsl.rb
CHANGED
@@ -22,7 +22,7 @@ module TTY
|
|
22
22
|
def initialize(characters=nil, &block)
|
23
23
|
@options = TTY::Table::BorderOptions.new
|
24
24
|
@options.characters = characters if characters
|
25
|
-
yield_or_eval
|
25
|
+
yield_or_eval(&block) if block_given?
|
26
26
|
end
|
27
27
|
|
28
28
|
# Apply style color to the border
|