tty 0.0.6 → 0.0.7
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/README.md +78 -12
- data/benchmarks/shell.rb +26 -0
- data/benchmarks/table.rb +35 -0
- data/lib/tty.rb +23 -1
- data/lib/tty/coercer.rb +13 -0
- data/lib/tty/coercer/boolean.rb +39 -0
- data/lib/tty/coercer/float.rb +23 -0
- data/lib/tty/coercer/integer.rb +23 -0
- data/lib/tty/coercer/range.rb +33 -0
- data/lib/tty/shell.rb +6 -2
- data/lib/tty/shell/question.rb +158 -138
- data/lib/tty/shell/reader.rb +92 -0
- data/lib/tty/shell/response.rb +219 -0
- data/lib/tty/shell/response_delegation.rb +53 -0
- data/lib/tty/table.rb +90 -16
- data/lib/tty/table/border.rb +34 -8
- data/lib/tty/table/border/ascii.rb +16 -25
- data/lib/tty/table/border/null.rb +0 -6
- data/lib/tty/table/border/unicode.rb +16 -25
- data/lib/tty/table/column_set.rb +1 -1
- data/lib/tty/table/error.rb +10 -0
- data/lib/tty/table/operation/wrapped.rb +0 -6
- data/lib/tty/table/orientation.rb +57 -0
- data/lib/tty/table/orientation/horizontal.rb +19 -0
- data/lib/tty/table/orientation/vertical.rb +19 -0
- data/lib/tty/table/renderer.rb +7 -0
- data/lib/tty/table/renderer/ascii.rb +1 -1
- data/lib/tty/table/renderer/basic.rb +2 -2
- data/lib/tty/table/renderer/unicode.rb +1 -1
- data/lib/tty/table/validatable.rb +20 -0
- data/lib/tty/terminal.rb +15 -14
- data/lib/tty/terminal/color.rb +1 -1
- data/lib/tty/terminal/echo.rb +41 -0
- data/lib/tty/terminal/home.rb +31 -0
- data/lib/tty/text.rb +85 -0
- data/lib/tty/text/truncation.rb +83 -0
- data/lib/tty/text/wrapping.rb +96 -0
- data/lib/tty/version.rb +1 -1
- data/spec/tty/coercer/boolean/coerce_spec.rb +113 -0
- data/spec/tty/coercer/float/coerce_spec.rb +32 -0
- data/spec/tty/coercer/integer/coerce_spec.rb +39 -0
- data/spec/tty/coercer/range/coerce_spec.rb +73 -0
- data/spec/tty/shell/ask_spec.rb +14 -1
- data/spec/tty/shell/question/argument_spec.rb +30 -0
- data/spec/tty/shell/question/character_spec.rb +16 -0
- data/spec/tty/shell/question/default_spec.rb +25 -0
- data/spec/tty/shell/question/in_spec.rb +23 -0
- data/spec/tty/shell/question/initialize_spec.rb +11 -211
- data/spec/tty/shell/question/modifier/whitespace_spec.rb +1 -1
- data/spec/tty/shell/question/modify_spec.rb +44 -0
- data/spec/tty/shell/question/valid_spec.rb +46 -0
- data/spec/tty/shell/question/validate_spec.rb +30 -0
- data/spec/tty/shell/reader/getc_spec.rb +40 -0
- data/spec/tty/shell/response/read_bool_spec.rb +41 -0
- data/spec/tty/shell/response/read_char_spec.rb +17 -0
- data/spec/tty/shell/response/read_date_spec.rb +20 -0
- data/spec/tty/shell/response/read_email_spec.rb +43 -0
- data/spec/tty/shell/response/read_multiple_spec.rb +24 -0
- data/spec/tty/shell/response/read_number_spec.rb +29 -0
- data/spec/tty/shell/response/read_range_spec.rb +29 -0
- data/spec/tty/shell/response/read_spec.rb +68 -0
- data/spec/tty/shell/response/read_string_spec.rb +19 -0
- data/spec/tty/table/access_spec.rb +6 -0
- data/spec/tty/table/border/new_spec.rb +3 -3
- data/spec/tty/table/initialize_spec.rb +17 -1
- data/spec/tty/table/options_spec.rb +7 -1
- data/spec/tty/table/orientation_spec.rb +98 -0
- data/spec/tty/table/renders_with_spec.rb +76 -0
- data/spec/tty/table/rotate_spec.rb +72 -0
- data/spec/tty/table/to_s_spec.rb +13 -1
- data/spec/tty/table/validatable/validate_options_spec.rb +34 -0
- data/spec/tty/terminal/color/remove_spec.rb +34 -1
- data/spec/tty/terminal/echo_spec.rb +22 -0
- data/spec/tty/text/truncate_spec.rb +13 -0
- data/spec/tty/text/truncation/initialize_spec.rb +29 -0
- data/spec/tty/text/truncation/truncate_spec.rb +73 -0
- data/spec/tty/text/wrap_spec.rb +14 -0
- data/spec/tty/text/wrapping/initialize_spec.rb +25 -0
- data/spec/tty/text/wrapping/wrap_spec.rb +80 -0
- data/tty.gemspec +1 -0
- metadata +101 -8
data/lib/tty/terminal/color.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Terminal
|
5
|
+
|
6
|
+
# A class responsible for toggling echo.
|
7
|
+
class Echo
|
8
|
+
|
9
|
+
# Turn echo on
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
def on
|
13
|
+
%x{stty echo} if TTY::System.unix?
|
14
|
+
end
|
15
|
+
|
16
|
+
# Turn echo off
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
def off
|
20
|
+
%x{stty -echo} if TTY::System.unix?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Wrap code block inside echo
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def echo(is_on=true, &block)
|
27
|
+
value = nil
|
28
|
+
begin
|
29
|
+
self.off unless is_on
|
30
|
+
value = block.call if block_given?
|
31
|
+
self.on
|
32
|
+
return value
|
33
|
+
rescue NoMethodError, Interrupt => e
|
34
|
+
self.on
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end # Echo
|
40
|
+
end # Terminal
|
41
|
+
end # TTY
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Terminal
|
5
|
+
|
6
|
+
# A class responsible for locating user home
|
7
|
+
class Home
|
8
|
+
|
9
|
+
# Find user home
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
def home
|
13
|
+
if (env_home = ENV['HOME'])
|
14
|
+
env_home
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
require 'etc'
|
18
|
+
File.expand_path("~#{Etc.getlogin}")
|
19
|
+
rescue
|
20
|
+
if TTY::System.windows?
|
21
|
+
"C:/"
|
22
|
+
else
|
23
|
+
"/"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end #Home
|
30
|
+
end # Terminal
|
31
|
+
end # TTY
|
data/lib/tty/text.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
|
5
|
+
# A class responsible for text manipulations
|
6
|
+
class Text
|
7
|
+
|
8
|
+
SPACE = " ".freeze
|
9
|
+
|
10
|
+
NEWLINE = "\n".freeze
|
11
|
+
|
12
|
+
DEFAULT_WIDTH = 80.freeze
|
13
|
+
|
14
|
+
# Specifies the split mode for words
|
15
|
+
def split_mode
|
16
|
+
end
|
17
|
+
|
18
|
+
# Wrap a text into lines no longer than provided length
|
19
|
+
#
|
20
|
+
# @param [String] text
|
21
|
+
# the text to be wrapped
|
22
|
+
#
|
23
|
+
# @overload wrap(text, value)
|
24
|
+
# wraps text at given value
|
25
|
+
#
|
26
|
+
# @param [Integer] value
|
27
|
+
#
|
28
|
+
# @overload wrap(text, value, options)
|
29
|
+
# @param [Integer] value
|
30
|
+
# @param [Hash] options
|
31
|
+
# @option options [Symbol] :indent the indentation
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# wrap("Some longish text", 8)
|
35
|
+
# # => "Some\nlongish\ntext"
|
36
|
+
#
|
37
|
+
# wrap("Some longish text", :length => 8)
|
38
|
+
# # => "Some\nlongish\ntext"
|
39
|
+
#
|
40
|
+
# wrap("Some longish text", 8, :indent => 4)
|
41
|
+
# # => > Some
|
42
|
+
# > longish
|
43
|
+
# > text
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def self.wrap(text, *args)
|
47
|
+
Wrapping.new(text, *args).wrap
|
48
|
+
end
|
49
|
+
|
50
|
+
# Truncate a text at a given length (defaults to 30)
|
51
|
+
#
|
52
|
+
# @param [String] text
|
53
|
+
# the text to be truncated
|
54
|
+
#
|
55
|
+
# @overload truncate(text, value)
|
56
|
+
# truncates text at given value
|
57
|
+
#
|
58
|
+
# @param [Integer] value
|
59
|
+
#
|
60
|
+
# @overload truncate(text, value, options)
|
61
|
+
# @param [Integer] value
|
62
|
+
# @param [Hash] options
|
63
|
+
# @option options [Symbol] :separator the separation character
|
64
|
+
# @option options [Symbol] :trailing the trailing characters
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# truncate("The sovereignest thing on earth is parmacetti for an inward bruise.")
|
68
|
+
# # => "The sovereignest thing on ear…"
|
69
|
+
#
|
70
|
+
# truncate("The sovereignest thing on earth is parmacetti for an inward bruise.", length: 20)
|
71
|
+
# # => "The sovereignest th…"
|
72
|
+
#
|
73
|
+
# truncate("The sovereignest thing on earth is parmacetti for an inward bruise.", length: 20, separator: ' ' )
|
74
|
+
# # => "The sovereignest…"
|
75
|
+
#
|
76
|
+
# truncate("The sovereignest thing on earth is parmacetti for an inward bruise.", length: 40, trailing: '... (see more)' )
|
77
|
+
# # => "The sovereignest thing on... (see more)"
|
78
|
+
#
|
79
|
+
# @api public
|
80
|
+
def self.truncate(text, *args)
|
81
|
+
Truncation.new(text, *args).truncate
|
82
|
+
end
|
83
|
+
|
84
|
+
end # Text
|
85
|
+
end # TTY
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Text
|
5
|
+
|
6
|
+
# A class responsible for text truncation operations
|
7
|
+
class Truncation
|
8
|
+
include Unicode
|
9
|
+
|
10
|
+
DEFAULT_TRAILING = '…'.freeze
|
11
|
+
|
12
|
+
DEFAULT_TRUNCATION_LENGTH = 30.freeze
|
13
|
+
|
14
|
+
attr_reader :text
|
15
|
+
|
16
|
+
attr_reader :length
|
17
|
+
|
18
|
+
attr_reader :separator
|
19
|
+
|
20
|
+
attr_reader :trailing
|
21
|
+
|
22
|
+
# Initialize a Truncation
|
23
|
+
#
|
24
|
+
# @param [String] text
|
25
|
+
# the text to be truncated
|
26
|
+
#
|
27
|
+
# @overload new(text, value)
|
28
|
+
# truncates text at given value
|
29
|
+
#
|
30
|
+
# @param [Integer] value
|
31
|
+
#
|
32
|
+
# @overload new(text, value, options)
|
33
|
+
# @param [Integer] value
|
34
|
+
#
|
35
|
+
# @param [Hash] options
|
36
|
+
# @option options [Symbol] :length the desired length
|
37
|
+
# @option options [Symbol] :separator the character for splitting words
|
38
|
+
# @option options [Symbol] :trailing the character for ending sentence
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
def initialize(text, *args)
|
42
|
+
options = Utils.extract_options!(args)
|
43
|
+
@text = text
|
44
|
+
@length = options.fetch(:length) { DEFAULT_TRUNCATION_LENGTH }
|
45
|
+
@length = args[0] unless args.empty?
|
46
|
+
@separator = options.fetch(:separator) { nil }
|
47
|
+
@trailing = options.fetch(:trailing) { DEFAULT_TRAILING }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Truncate a text
|
51
|
+
#
|
52
|
+
# @see TTY::Text.truncate
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
def truncate
|
56
|
+
return text unless length && length > 0
|
57
|
+
|
58
|
+
as_unicode do
|
59
|
+
chars = text.chars.to_a
|
60
|
+
return chars.join if chars.length < length
|
61
|
+
stop = chars[0, length_without_trailing].rindex(separator)
|
62
|
+
|
63
|
+
chars[0, stop || length_without_trailing].join + trailing
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Leave space for the trailing characters
|
70
|
+
#
|
71
|
+
# @return [Integer]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def length_without_trailing
|
75
|
+
as_unicode do
|
76
|
+
trailing_size = trailing.chars.to_a.size
|
77
|
+
length - trailing_size
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end # Truncation
|
82
|
+
end # Text
|
83
|
+
end # TTY
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Text
|
5
|
+
|
6
|
+
# A class responsible for text wrapping operations
|
7
|
+
class Wrapping
|
8
|
+
include Unicode
|
9
|
+
|
10
|
+
attr_reader :text
|
11
|
+
|
12
|
+
attr_reader :length
|
13
|
+
|
14
|
+
attr_reader :indent
|
15
|
+
|
16
|
+
# Initialize a Wrapping
|
17
|
+
#
|
18
|
+
# @param [String] text
|
19
|
+
# the text to be wrapped
|
20
|
+
#
|
21
|
+
# @overload new(text, value)
|
22
|
+
# wraps text at given value
|
23
|
+
#
|
24
|
+
# @param [Integer] value
|
25
|
+
#
|
26
|
+
# @overload new(text, value, options)
|
27
|
+
# @param [Integer] value
|
28
|
+
# @param [Hash] options
|
29
|
+
# @option options [Symbol] :indent the indentation
|
30
|
+
# @option options [Symbol] :length the desired length
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def initialize(text, *args)
|
34
|
+
options = Utils.extract_options!(args)
|
35
|
+
@text = text
|
36
|
+
@length = options.fetch(:length) { DEFAULT_WIDTH }
|
37
|
+
@indent = options.fetch(:indent) { 0 }
|
38
|
+
@length = args[0] unless args.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
# Wrap a text into lines no longer than length
|
42
|
+
#
|
43
|
+
# @see TTY::Text#wrap
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
def wrap
|
47
|
+
return text unless length && length > 0
|
48
|
+
|
49
|
+
as_unicode do
|
50
|
+
text.split(NEWLINE).map do |line|
|
51
|
+
modified_line = wrap_line line
|
52
|
+
indent_line modified_line
|
53
|
+
end * NEWLINE
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Calculate string length without color escapes
|
60
|
+
#
|
61
|
+
# @param [String] string
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
def actual_length(string)
|
65
|
+
length + (string.length - TTY.terminal.color.remove(string).length)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Wrap line at given length
|
69
|
+
#
|
70
|
+
# @param [String] line
|
71
|
+
#
|
72
|
+
# @return [String]
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
def wrap_line(line)
|
76
|
+
wrap_at = actual_length line
|
77
|
+
line.strip.gsub(/\n/,' ').squeeze(' ').
|
78
|
+
gsub(/(.{1,#{wrap_at}})(?:\s+|$\n?)|(.{1,#{wrap_at}})/, "\\1\\2\n").strip
|
79
|
+
end
|
80
|
+
|
81
|
+
# Indent string by given value
|
82
|
+
#
|
83
|
+
# @param [String] text
|
84
|
+
#
|
85
|
+
# @return [String]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
def indent_line(text)
|
89
|
+
text.split(NEWLINE).each do |line|
|
90
|
+
line.insert(0, SPACE * indent)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end # Wrapping
|
95
|
+
end # Text
|
96
|
+
end # TTY
|
data/lib/tty/version.rb
CHANGED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TTY::Coercer::Boolean, '#coerce' do
|
4
|
+
subject { described_class.coerce(value) }
|
5
|
+
|
6
|
+
context "with empty" do
|
7
|
+
let(:value) { '' }
|
8
|
+
|
9
|
+
it { expect { subject }.to raise_error(TTY::TypeError) }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with true" do
|
13
|
+
let(:value) { true }
|
14
|
+
|
15
|
+
it { expect(subject).to be_true }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "with 'true'" do
|
19
|
+
let(:value) { 'true' }
|
20
|
+
|
21
|
+
it { expect(subject).to be_true }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with TRUE" do
|
25
|
+
let(:value) { TRUE }
|
26
|
+
|
27
|
+
it { expect(subject).to be_true }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with 'TRUE'" do
|
31
|
+
let(:value) { 'TRUE' }
|
32
|
+
|
33
|
+
it { expect(subject).to be_true }
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with 't'" do
|
37
|
+
let(:value) { 't' }
|
38
|
+
|
39
|
+
it { expect(subject).to be_true }
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with 'T'" do
|
43
|
+
let(:value) { 'T' }
|
44
|
+
|
45
|
+
it { expect(subject).to be_true }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with 1" do
|
49
|
+
let(:value) { 1 }
|
50
|
+
|
51
|
+
it { expect(subject).to be_true }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with '1'" do
|
55
|
+
let(:value) { '1' }
|
56
|
+
|
57
|
+
it { expect(subject).to be_true }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with false" do
|
61
|
+
let(:value) { false }
|
62
|
+
|
63
|
+
it { expect(subject).to be_false }
|
64
|
+
end
|
65
|
+
|
66
|
+
context "with 'false'" do
|
67
|
+
let(:value) { 'false' }
|
68
|
+
|
69
|
+
it { expect(subject).to be_false }
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with FALSE" do
|
73
|
+
let(:value) { FALSE }
|
74
|
+
|
75
|
+
it { expect(subject).to be_false }
|
76
|
+
end
|
77
|
+
|
78
|
+
context "with 'FALSE'" do
|
79
|
+
let(:value) { 'FALSE' }
|
80
|
+
|
81
|
+
it { expect(subject).to be_false }
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with 'f'" do
|
85
|
+
let(:value) { 'f' }
|
86
|
+
|
87
|
+
it { expect(subject).to be_false }
|
88
|
+
end
|
89
|
+
|
90
|
+
context "with 'F'" do
|
91
|
+
let(:value) { 'F' }
|
92
|
+
|
93
|
+
it { expect(subject).to be_false }
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with 0" do
|
97
|
+
let(:value) { 0 }
|
98
|
+
|
99
|
+
it { expect(subject).to be_false }
|
100
|
+
end
|
101
|
+
|
102
|
+
context "with '0'" do
|
103
|
+
let(:value) { '0' }
|
104
|
+
|
105
|
+
it { expect(subject).to be_false }
|
106
|
+
end
|
107
|
+
|
108
|
+
context "with FOO" do
|
109
|
+
let(:value) { 'FOO' }
|
110
|
+
|
111
|
+
it { expect { subject }.to raise_error(TTY::TypeError) }
|
112
|
+
end
|
113
|
+
end
|