tty 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|