tty 0.2.1 → 0.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +45 -115
- data/lib/tty.rb +3 -31
- data/lib/tty/plugins/plugin.rb +2 -2
- data/lib/tty/terminal.rb +2 -58
- data/lib/tty/terminal/home.rb +27 -9
- data/lib/tty/version.rb +1 -1
- data/spec/tty/plugins/plugin/load_spec.rb +10 -18
- data/spec/tty/system/editor/open_spec.rb +1 -1
- data/spec/tty/terminal/home_spec.rb +18 -26
- data/spec/tty/tty_spec.rb +1 -1
- data/spec/tty/vector/new_spec.rb +1 -1
- metadata +2 -83
- data/lib/tty/shell.rb +0 -211
- data/lib/tty/shell/distance.rb +0 -49
- data/lib/tty/shell/question.rb +0 -335
- data/lib/tty/shell/question/modifier.rb +0 -93
- data/lib/tty/shell/question/validation.rb +0 -92
- data/lib/tty/shell/reader.rb +0 -110
- data/lib/tty/shell/response.rb +0 -249
- data/lib/tty/shell/response_delegation.rb +0 -55
- data/lib/tty/shell/statement.rb +0 -60
- data/lib/tty/shell/suggestion.rb +0 -126
- data/lib/tty/support/utils.rb +0 -16
- data/lib/tty/terminal/echo.rb +0 -38
- data/lib/tty/terminal/raw.rb +0 -38
- data/spec/tty/shell/ask_spec.rb +0 -77
- data/spec/tty/shell/distance/distance_spec.rb +0 -75
- data/spec/tty/shell/distance/initialize_spec.rb +0 -14
- data/spec/tty/shell/error_spec.rb +0 -30
- data/spec/tty/shell/print_table_spec.rb +0 -24
- data/spec/tty/shell/question/argument_spec.rb +0 -30
- data/spec/tty/shell/question/character_spec.rb +0 -24
- data/spec/tty/shell/question/default_spec.rb +0 -25
- data/spec/tty/shell/question/in_spec.rb +0 -23
- data/spec/tty/shell/question/initialize_spec.rb +0 -24
- data/spec/tty/shell/question/modifier/apply_to_spec.rb +0 -34
- data/spec/tty/shell/question/modifier/letter_case_spec.rb +0 -27
- data/spec/tty/shell/question/modifier/whitespace_spec.rb +0 -33
- data/spec/tty/shell/question/modify_spec.rb +0 -44
- data/spec/tty/shell/question/valid_spec.rb +0 -46
- data/spec/tty/shell/question/validate_spec.rb +0 -30
- data/spec/tty/shell/question/validation/coerce_spec.rb +0 -24
- data/spec/tty/shell/question/validation/valid_value_spec.rb +0 -28
- data/spec/tty/shell/reader/getc_spec.rb +0 -42
- data/spec/tty/shell/response/read_bool_spec.rb +0 -40
- data/spec/tty/shell/response/read_char_spec.rb +0 -16
- data/spec/tty/shell/response/read_date_spec.rb +0 -20
- data/spec/tty/shell/response/read_email_spec.rb +0 -42
- data/spec/tty/shell/response/read_multiple_spec.rb +0 -23
- data/spec/tty/shell/response/read_number_spec.rb +0 -28
- data/spec/tty/shell/response/read_range_spec.rb +0 -31
- data/spec/tty/shell/response/read_spec.rb +0 -68
- data/spec/tty/shell/response/read_string_spec.rb +0 -19
- data/spec/tty/shell/say_spec.rb +0 -67
- data/spec/tty/shell/statement/initialize_spec.rb +0 -15
- data/spec/tty/shell/suggest_spec.rb +0 -50
- data/spec/tty/shell/warn_spec.rb +0 -30
- data/spec/tty/terminal/color_spec.rb +0 -16
- data/spec/tty/terminal/echo_spec.rb +0 -21
@@ -1,92 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module TTY
|
4
|
-
class Shell
|
5
|
-
class Question
|
6
|
-
# A class representing question validation.
|
7
|
-
class Validation
|
8
|
-
# @api private
|
9
|
-
attr_reader :validation
|
10
|
-
private :validation
|
11
|
-
|
12
|
-
# Initialize a Validation
|
13
|
-
#
|
14
|
-
# @param [Object] validation
|
15
|
-
#
|
16
|
-
# @return [undefined]
|
17
|
-
#
|
18
|
-
# @api private
|
19
|
-
def initialize(validation = nil)
|
20
|
-
@validation = validation ? coerce(validation) : validation
|
21
|
-
end
|
22
|
-
|
23
|
-
# Convert validation into known type.
|
24
|
-
#
|
25
|
-
# @param [Object] validation
|
26
|
-
#
|
27
|
-
# @raise [TTY::ValidationCoercion] failed to convert validation
|
28
|
-
#
|
29
|
-
# @api private
|
30
|
-
def coerce(validation)
|
31
|
-
case validation
|
32
|
-
when Proc
|
33
|
-
validation
|
34
|
-
when Regexp, String
|
35
|
-
Regexp.new(validation.to_s)
|
36
|
-
else
|
37
|
-
fail TTY::ValidationCoercion, "Wrong type, got #{validation.class}"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Check if validation is required
|
42
|
-
#
|
43
|
-
# @return [Boolean]
|
44
|
-
#
|
45
|
-
# @api public
|
46
|
-
def validate?
|
47
|
-
!!validation
|
48
|
-
end
|
49
|
-
|
50
|
-
# Test if the value matches the validation
|
51
|
-
#
|
52
|
-
# @example
|
53
|
-
# validation.valid_value?(value) # => true or false
|
54
|
-
#
|
55
|
-
# @param [Object] value
|
56
|
-
# the value to validate
|
57
|
-
#
|
58
|
-
# @return [undefined]
|
59
|
-
#
|
60
|
-
# @api public
|
61
|
-
def valid_value?(value)
|
62
|
-
check_validation(value)
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
# Check if provided value passes validation
|
68
|
-
#
|
69
|
-
# @param [String] value
|
70
|
-
#
|
71
|
-
# @raise [TTY::InvalidArgument] unkown type of argument
|
72
|
-
#
|
73
|
-
# @return [undefined]
|
74
|
-
#
|
75
|
-
# @api private
|
76
|
-
def check_validation(value)
|
77
|
-
if validate? && value
|
78
|
-
value = value.to_s
|
79
|
-
if validation.is_a?(Regexp) && validation =~ value
|
80
|
-
elsif validation.is_a?(Proc) && validation.call(value)
|
81
|
-
else
|
82
|
-
fail TTY::InvalidArgument, "Invalid input for #{value}"
|
83
|
-
end
|
84
|
-
true
|
85
|
-
else
|
86
|
-
false
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end # Validation
|
90
|
-
end # Question
|
91
|
-
end # Shell
|
92
|
-
end # TTY
|
data/lib/tty/shell/reader.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module TTY
|
4
|
-
# A class responsible for shell prompt interactions.
|
5
|
-
class Shell
|
6
|
-
# A class responsible for reading character input from STDIN
|
7
|
-
class Reader
|
8
|
-
# @api private
|
9
|
-
attr_reader :shell
|
10
|
-
private :shell
|
11
|
-
|
12
|
-
# Key input constants for decimal codes
|
13
|
-
CARRIAGE_RETURN = 13.freeze
|
14
|
-
NEWLINE = 10.freeze
|
15
|
-
BACKSPACE = 127.freeze
|
16
|
-
DELETE = 8.freeze
|
17
|
-
|
18
|
-
# Initialize a Reader
|
19
|
-
#
|
20
|
-
# @api public
|
21
|
-
def initialize(shell = Shell.new)
|
22
|
-
@shell = shell
|
23
|
-
end
|
24
|
-
|
25
|
-
# Get input in unbuffered mode.
|
26
|
-
#
|
27
|
-
# @example
|
28
|
-
# buffer do
|
29
|
-
# ...
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# @return [String]
|
33
|
-
#
|
34
|
-
# @api public
|
35
|
-
def buffer(&block)
|
36
|
-
bufferring = shell.output.sync
|
37
|
-
# Immediately flush output
|
38
|
-
shell.output.sync = true
|
39
|
-
|
40
|
-
value = block.call if block_given?
|
41
|
-
|
42
|
-
shell.output.sync = bufferring
|
43
|
-
value
|
44
|
-
end
|
45
|
-
|
46
|
-
# Get a value from STDIN one key at a time. Each key press is echoed back
|
47
|
-
# to the shell masked with character(if given). The input finishes when
|
48
|
-
# enter key is pressed.
|
49
|
-
#
|
50
|
-
# @param [String] mask
|
51
|
-
# the character to use as mask
|
52
|
-
#
|
53
|
-
# @return [String]
|
54
|
-
#
|
55
|
-
# @api public
|
56
|
-
def getc(mask = (not_set = true))
|
57
|
-
value = ''
|
58
|
-
buffer do
|
59
|
-
begin
|
60
|
-
while (char = shell.input.getbyte) &&
|
61
|
-
!(char == CARRIAGE_RETURN || char == NEWLINE)
|
62
|
-
value = handle_char value, char, not_set, mask
|
63
|
-
end
|
64
|
-
ensure
|
65
|
-
TTY.terminal.echo_on
|
66
|
-
end
|
67
|
-
end
|
68
|
-
value
|
69
|
-
end
|
70
|
-
|
71
|
-
# Get a value from STDIN using line input.
|
72
|
-
#
|
73
|
-
# @api public
|
74
|
-
def gets
|
75
|
-
shell.input.gets
|
76
|
-
end
|
77
|
-
|
78
|
-
# Reads at maximum +maxlen+ characters.
|
79
|
-
#
|
80
|
-
# @param [Integer] maxlen
|
81
|
-
#
|
82
|
-
# @api public
|
83
|
-
def readpartial(maxlen)
|
84
|
-
shell.input.readpartial(maxlen)
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
# Handle single character by appending to or removing from output
|
90
|
-
#
|
91
|
-
# @api private
|
92
|
-
def handle_char(value, char, not_set, mask)
|
93
|
-
if char == BACKSPACE || char == DELETE
|
94
|
-
value.slice!(-1, 1) unless value.empty?
|
95
|
-
else
|
96
|
-
print_char char, not_set, mask
|
97
|
-
value << char
|
98
|
-
end
|
99
|
-
value
|
100
|
-
end
|
101
|
-
|
102
|
-
# Print out character back to shell STDOUT
|
103
|
-
#
|
104
|
-
# @api private
|
105
|
-
def print_char(char, not_set, mask)
|
106
|
-
shell.output.putc((not_set || !mask) ? char : mask)
|
107
|
-
end
|
108
|
-
end # Reader
|
109
|
-
end # Shell
|
110
|
-
end # TTY
|
data/lib/tty/shell/response.rb
DELETED
@@ -1,249 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'date'
|
4
|
-
|
5
|
-
module TTY
|
6
|
-
# A class responsible for shell prompt interactions
|
7
|
-
class Shell
|
8
|
-
# A class representing a shell response
|
9
|
-
class Response
|
10
|
-
VALID_TYPES = [
|
11
|
-
:boolean,
|
12
|
-
:string,
|
13
|
-
:symbol,
|
14
|
-
:integer,
|
15
|
-
:float,
|
16
|
-
:date,
|
17
|
-
:datetime
|
18
|
-
]
|
19
|
-
|
20
|
-
attr_reader :reader
|
21
|
-
private :reader
|
22
|
-
|
23
|
-
attr_reader :shell
|
24
|
-
private :shell
|
25
|
-
|
26
|
-
attr_reader :question
|
27
|
-
private :question
|
28
|
-
|
29
|
-
# Initialize a Response
|
30
|
-
#
|
31
|
-
# @api public
|
32
|
-
def initialize(question, shell = Shell.new)
|
33
|
-
@question = question
|
34
|
-
@shell = shell
|
35
|
-
@converter = Necromancer.new
|
36
|
-
@reader = Reader.new(shell)
|
37
|
-
end
|
38
|
-
|
39
|
-
# Read input from STDIN either character or line
|
40
|
-
#
|
41
|
-
# @param [Symbol] type
|
42
|
-
#
|
43
|
-
# @return [undefined]
|
44
|
-
#
|
45
|
-
# @api public
|
46
|
-
def read(type = nil)
|
47
|
-
question.evaluate_response read_input
|
48
|
-
end
|
49
|
-
|
50
|
-
# @api private
|
51
|
-
def read_input
|
52
|
-
reader = Reader.new(shell)
|
53
|
-
|
54
|
-
if question.mask? && question.echo?
|
55
|
-
reader.getc(question.mask)
|
56
|
-
else
|
57
|
-
TTY.terminal.echo(question.echo) do
|
58
|
-
TTY.terminal.raw(question.raw) do
|
59
|
-
if question.raw?
|
60
|
-
reader.readpartial(10)
|
61
|
-
elsif question.character?
|
62
|
-
reader.getc(question.mask)
|
63
|
-
else
|
64
|
-
reader.gets
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Read answer and cast to String type
|
72
|
-
#
|
73
|
-
# @param [String] error
|
74
|
-
# error to display on failed conversion to string type
|
75
|
-
#
|
76
|
-
# @api public
|
77
|
-
def read_string(error = nil)
|
78
|
-
question.evaluate_response(String(read_input).strip)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Read answer's first character
|
82
|
-
#
|
83
|
-
# @api public
|
84
|
-
def read_char
|
85
|
-
question.char(true)
|
86
|
-
question.evaluate_response String(read_input).chars.to_a[0]
|
87
|
-
end
|
88
|
-
|
89
|
-
# Read multiple line answer and cast to String type
|
90
|
-
#
|
91
|
-
# @api public
|
92
|
-
def read_text
|
93
|
-
question.evaluate_response String(read_input)
|
94
|
-
end
|
95
|
-
|
96
|
-
# Read ansewr and cast to Symbol type
|
97
|
-
#
|
98
|
-
# @api public
|
99
|
-
def read_symbol(error = nil)
|
100
|
-
question.evaluate_response(read_input.to_sym)
|
101
|
-
end
|
102
|
-
|
103
|
-
# Read answer from predifined choicse
|
104
|
-
#
|
105
|
-
# @api public
|
106
|
-
def read_choice(type = nil)
|
107
|
-
question.argument(:required) unless question.default?
|
108
|
-
question.evaluate_response read_input
|
109
|
-
end
|
110
|
-
|
111
|
-
# Read integer value
|
112
|
-
#
|
113
|
-
# @api public
|
114
|
-
def read_int(error = nil)
|
115
|
-
response = @converter.convert(read_input).to(:integer)
|
116
|
-
question.evaluate_response(response)
|
117
|
-
end
|
118
|
-
|
119
|
-
# Read float value
|
120
|
-
#
|
121
|
-
# @api public
|
122
|
-
def read_float(error = nil)
|
123
|
-
response = @converter.convert(read_input).to(:float)
|
124
|
-
question.evaluate_response(response)
|
125
|
-
end
|
126
|
-
|
127
|
-
# Read regular expression
|
128
|
-
#
|
129
|
-
# @api public
|
130
|
-
def read_regex(error = nil)
|
131
|
-
question.evaluate_response Kernel.send(:Regex, read_input)
|
132
|
-
end
|
133
|
-
|
134
|
-
# Read range expression
|
135
|
-
#
|
136
|
-
# @api public
|
137
|
-
def read_range
|
138
|
-
response = @converter.convert(read_input).to(:range, strict: true)
|
139
|
-
question.evaluate_response(response)
|
140
|
-
end
|
141
|
-
|
142
|
-
# Read date
|
143
|
-
#
|
144
|
-
# @api public
|
145
|
-
def read_date
|
146
|
-
response = @converter.convert(read_input).to(:date)
|
147
|
-
question.evaluate_response(response)
|
148
|
-
end
|
149
|
-
|
150
|
-
# Read datetime
|
151
|
-
#
|
152
|
-
# @api public
|
153
|
-
def read_datetime
|
154
|
-
response = @converter.convert(read_input).to(:datetime)
|
155
|
-
question.evaluate_response(response)
|
156
|
-
end
|
157
|
-
|
158
|
-
# Read boolean
|
159
|
-
#
|
160
|
-
# @api public
|
161
|
-
def read_bool(error = nil)
|
162
|
-
response = @converter.convert(read_input).to(:boolean, strict: true)
|
163
|
-
question.evaluate_response(response)
|
164
|
-
end
|
165
|
-
|
166
|
-
# Read file contents
|
167
|
-
#
|
168
|
-
# @api public
|
169
|
-
def read_file(error = nil)
|
170
|
-
question.evaluate_response File.open(File.join(directory, read_input))
|
171
|
-
end
|
172
|
-
|
173
|
-
# Read string answer and validate against email regex
|
174
|
-
#
|
175
|
-
# @return [String]
|
176
|
-
#
|
177
|
-
# @api public
|
178
|
-
def read_email
|
179
|
-
question.validate(/^[a-z0-9._%+-]+@([a-z0-9-]+\.)+[a-z]{2,6}$/i)
|
180
|
-
question.prompt(question.statement) if question.error
|
181
|
-
with_exception { read_string }
|
182
|
-
end
|
183
|
-
|
184
|
-
# Read answer provided on multiple lines
|
185
|
-
#
|
186
|
-
# @api public
|
187
|
-
def read_multiple
|
188
|
-
response = ''
|
189
|
-
loop do
|
190
|
-
value = question.evaluate_response read_input
|
191
|
-
break if !value || value == ''
|
192
|
-
next if value !~ /\S/
|
193
|
-
response << value
|
194
|
-
end
|
195
|
-
response
|
196
|
-
end
|
197
|
-
|
198
|
-
# Read password
|
199
|
-
#
|
200
|
-
# @api public
|
201
|
-
def read_password
|
202
|
-
question.echo false
|
203
|
-
question.evaluate_response read_input
|
204
|
-
end
|
205
|
-
|
206
|
-
# Read a single keypress
|
207
|
-
#
|
208
|
-
# @api public
|
209
|
-
def read_keypress
|
210
|
-
question.echo false
|
211
|
-
question.raw true
|
212
|
-
question.evaluate_response(read_input).tap do |key|
|
213
|
-
raise Interrupt if key == "\x03" # Ctrl-C
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
private
|
218
|
-
|
219
|
-
# Ignore exception
|
220
|
-
#
|
221
|
-
# @api private
|
222
|
-
def with_exception(&block)
|
223
|
-
yield
|
224
|
-
rescue
|
225
|
-
question.error? ? block.call : raise
|
226
|
-
end
|
227
|
-
|
228
|
-
# @param [Symbol] type
|
229
|
-
# :boolean, :string, :numeric, :array
|
230
|
-
#
|
231
|
-
# @api private
|
232
|
-
def read_type(class_or_name)
|
233
|
-
raise TypeError, "Type #{type} is not valid" if type && !valid_type?(type)
|
234
|
-
case type
|
235
|
-
when :string, ::String
|
236
|
-
read_string
|
237
|
-
when :symbol, ::Symbol
|
238
|
-
read_symbol
|
239
|
-
when :float, ::Float
|
240
|
-
read_float
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def valid_type?(type)
|
245
|
-
self.class::VALID_TYPES.include? type.to_sym
|
246
|
-
end
|
247
|
-
end # Response
|
248
|
-
end # Shell
|
249
|
-
end # TTY
|