cli-ui 1.0.0 → 1.1.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/.gitignore +1 -0
- data/README.md +13 -0
- data/lib/cli/ui/prompt.rb +78 -36
- data/lib/cli/ui/prompt/options_handler.rb +24 -0
- data/lib/cli/ui/version.rb +1 -1
- metadata +3 -3
- data/Gemfile.lock +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 367667f90cce34fe2ac10fffbd13a24a8b7a90e3
|
4
|
+
data.tar.gz: fdc151c1343bc037c8f03c3308ec3646795e9dbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51e249672f6214028aebf3ab31b2d90cde511da996118b50607522318528c57ae0bfe40edc4b447593fb5faf2712b964fdfafdc26e1b092ce96e8ee92366e759
|
7
|
+
data.tar.gz: 58e27c5790e1bb0f35581953467a8c5a38d7ca647f3cca7042e42d347c9708dc44e9007cb326fa563b241daaaaa480662de7dfdaa2ad5a3084ecf68dc4158cf6
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -49,6 +49,19 @@ Prompt user with options and ask them to choose. Can answer using arrow keys, nu
|
|
49
49
|
CLI::UI.ask('What language/framework do you use?', options: %w(rails go ruby python))
|
50
50
|
```
|
51
51
|
|
52
|
+
Can also assign callbacks to each option
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
CLI::UI.ask('What language/framework do you use?') do |handler|
|
56
|
+
handler.option('rails') { |selection| selection }
|
57
|
+
handler.option('go') { |selection| selection }
|
58
|
+
handler.option('ruby') { |selection| selection }
|
59
|
+
handler.option('python') { |selection| selection }
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
* Note that the two examples provided above are identical in functionality
|
64
|
+
|
52
65
|

|
53
66
|
|
54
67
|
---
|
data/lib/cli/ui/prompt.rb
CHANGED
@@ -5,12 +5,13 @@ module CLI
|
|
5
5
|
module UI
|
6
6
|
module Prompt
|
7
7
|
autoload :InteractiveOptions, 'cli/ui/prompt/interactive_options'
|
8
|
-
|
8
|
+
autoload :OptionsHandler, 'cli/ui/prompt/options_handler'
|
9
|
+
private_constant :InteractiveOptions, :OptionsHandler
|
9
10
|
|
10
11
|
class << self
|
11
|
-
# Ask a user a question with either free form answer or a set of answers
|
12
|
+
# Ask a user a question with either free form answer or a set of answers (multiple choice)
|
13
|
+
# Can use arrows, y/n, numbers (1/2), and vim bindings to control multiple choice selection
|
12
14
|
# Do not use this method for yes/no questions. Use +confirm+
|
13
|
-
# Can use arrows, y/n, numbers, and vim bindings to control
|
14
15
|
#
|
15
16
|
# * Handles free form answers (options are nil)
|
16
17
|
# * Handles default answers for free form text
|
@@ -25,14 +26,25 @@ module CLI
|
|
25
26
|
#
|
26
27
|
# ==== Options
|
27
28
|
#
|
28
|
-
# * +:options+ - Options
|
29
|
+
# * +:options+ - Options that the user may select from. Will use +InteractiveOptions+ to do so.
|
29
30
|
# * +:default+ - The default answer to the question (e.g. they just press enter and don't input anything)
|
30
31
|
# * +:is_file+ - Tells the input to use file auto-completion (tab completion)
|
31
32
|
# * +:allow_empty+ - Allows the answer to be empty
|
32
33
|
#
|
33
34
|
# Note:
|
34
|
-
# * +:options+ conflicts with +:default+ and +:is_file+, you cannot set options with either of these keywords
|
35
|
+
# * +:options+ or providing a +Block+ conflicts with +:default+ and +:is_file+, you cannot set options with either of these keywords
|
35
36
|
# * +:default+ conflicts with +:allow_empty:, you cannot set these together
|
37
|
+
# * +:options+ conflicts with providing a +Block+ , you may only set one
|
38
|
+
#
|
39
|
+
# ==== Block (optional)
|
40
|
+
#
|
41
|
+
# * A Proc that provides a +OptionsHandler+ and uses the public +:option+ method to add options and their
|
42
|
+
# respective handlers
|
43
|
+
#
|
44
|
+
# ==== Return Value
|
45
|
+
#
|
46
|
+
# * If a +Block+ was not provided, the selected option or response to the free form question will be returned
|
47
|
+
# * If a +Block+ was provided, the evaluted value of the +Block+ will be returned
|
36
48
|
#
|
37
49
|
# ==== Example Usage:
|
38
50
|
#
|
@@ -48,35 +60,50 @@ module CLI
|
|
48
60
|
# Free form question when the answer can be empty
|
49
61
|
# CLI::UI::Prompt.ask('What is your opinion on this question?', allow_empty: true)
|
50
62
|
#
|
51
|
-
#
|
63
|
+
# Interactive (multiple choice) question
|
52
64
|
# CLI::UI::Prompt.ask('What kind of project is this?', options: %w(rails go ruby python))
|
53
65
|
#
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
66
|
+
# Interactive (multiple choice) question with defined handlers
|
67
|
+
# CLI::UI::Prompt.ask('What kind of project is this?') do |handler|
|
68
|
+
# handler.option('rails') { |selection| selection }
|
69
|
+
# handler.option('go') { |selection| selection }
|
70
|
+
# handler.option('ruby') { |selection| selection }
|
71
|
+
# handler.option('python') { |selection| selection }
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
def ask(question, options: nil, default: nil, is_file: nil, allow_empty: true, &options_proc)
|
75
|
+
if ((options || block_given?) && (default || is_file))
|
76
|
+
raise(ArgumentError, 'conflicting arguments: options provided with default or is_file')
|
58
77
|
end
|
59
78
|
|
60
|
-
if
|
61
|
-
|
62
|
-
elsif options
|
63
|
-
puts_question("#{question} {{yellow:(choose with ↑ ↓ ⏎)}}")
|
79
|
+
if options || block_given?
|
80
|
+
ask_interactive(question, options, &options_proc)
|
64
81
|
else
|
65
|
-
|
82
|
+
ask_free_form(question, default, is_file, allow_empty)
|
66
83
|
end
|
84
|
+
end
|
67
85
|
|
68
|
-
|
69
|
-
|
70
|
-
|
86
|
+
# Asks the user a yes/no question.
|
87
|
+
# Can use arrows, y/n, numbers (1/2), and vim bindings to control
|
88
|
+
#
|
89
|
+
# ==== Example Usage:
|
90
|
+
#
|
91
|
+
# Confirmation question
|
92
|
+
# CLI::UI::Prompt.confirm('Is the sky blue?')
|
93
|
+
#
|
94
|
+
def confirm(question)
|
95
|
+
ask_interactive(question, %w(yes no)) == 'yes'
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
71
99
|
|
72
|
-
|
73
|
-
|
74
|
-
print(ANSI.cursor_save)
|
75
|
-
print(' ' * CLI::UI::Terminal.width)
|
76
|
-
print(ANSI.cursor_restore)
|
77
|
-
puts_question("#{question} (You chose: {{italic:#{resp}}})")
|
100
|
+
def ask_free_form(question, default, is_file, allow_empty)
|
101
|
+
raise(ArgumentError, 'conflicting arguments: default enabled but allow_empty is false') if (default && !allow_empty)
|
78
102
|
|
79
|
-
|
103
|
+
if default
|
104
|
+
puts_question("#{question} (empty = #{default})")
|
105
|
+
else
|
106
|
+
puts_question(question)
|
80
107
|
end
|
81
108
|
|
82
109
|
# Ask a free form question
|
@@ -94,19 +121,34 @@ module CLI
|
|
94
121
|
end
|
95
122
|
end
|
96
123
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
124
|
+
def ask_interactive(question, options = nil)
|
125
|
+
raise(ArgumentError, 'conflicting arguments: options and block given') if options && block_given?
|
126
|
+
|
127
|
+
options ||= if block_given?
|
128
|
+
handler = OptionsHandler.new
|
129
|
+
yield handler
|
130
|
+
handler.options
|
131
|
+
end
|
132
|
+
|
133
|
+
raise(ArgumentError, 'insufficient options') if options.nil? || options.size < 2
|
134
|
+
puts_question("#{question} {{yellow:(choose with ↑ ↓ ⏎)}}")
|
135
|
+
resp = interactive_prompt(options)
|
136
|
+
|
137
|
+
# Clear the line, and reset the question to include the answer
|
138
|
+
print(ANSI.previous_line + ANSI.end_of_line + ' ')
|
139
|
+
print(ANSI.cursor_save)
|
140
|
+
print(' ' * CLI::UI::Terminal.width)
|
141
|
+
print(ANSI.cursor_restore)
|
142
|
+
puts_question("#{question} (You chose: {{italic:#{resp}}})")
|
143
|
+
|
144
|
+
return handler.call(resp) if block_given?
|
145
|
+
resp
|
107
146
|
end
|
108
147
|
|
109
|
-
|
148
|
+
# Useful for stubbing in tests
|
149
|
+
def interactive_prompt(options)
|
150
|
+
InteractiveOptions.call(options)
|
151
|
+
end
|
110
152
|
|
111
153
|
def write_default_over_empty_input(default)
|
112
154
|
CLI::UI.raw do
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module CLI
|
2
|
+
module UI
|
3
|
+
module Prompt
|
4
|
+
# A class that handles the various options of an InteractivePrompt and their callbacks
|
5
|
+
class OptionsHandler
|
6
|
+
def initialize
|
7
|
+
@options = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def options
|
11
|
+
@options.keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def option(option, &handler)
|
15
|
+
@options[option] = handler
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(option)
|
19
|
+
@options[option].call(option)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/cli/ui/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cli-ui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Burke Libbey
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2018-02-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -67,7 +67,6 @@ files:
|
|
67
67
|
- ".rubocop.yml"
|
68
68
|
- ".travis.yml"
|
69
69
|
- Gemfile
|
70
|
-
- Gemfile.lock
|
71
70
|
- LICENSE.txt
|
72
71
|
- README.md
|
73
72
|
- Rakefile
|
@@ -84,6 +83,7 @@ files:
|
|
84
83
|
- lib/cli/ui/progress.rb
|
85
84
|
- lib/cli/ui/prompt.rb
|
86
85
|
- lib/cli/ui/prompt/interactive_options.rb
|
86
|
+
- lib/cli/ui/prompt/options_handler.rb
|
87
87
|
- lib/cli/ui/spinner.rb
|
88
88
|
- lib/cli/ui/spinner/async.rb
|
89
89
|
- lib/cli/ui/spinner/spin_group.rb
|
data/Gemfile.lock
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
cli-ui (0.1.2)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
ansi (1.5.0)
|
10
|
-
ast (2.3.0)
|
11
|
-
builder (3.2.3)
|
12
|
-
byebug (9.0.6)
|
13
|
-
metaclass (0.0.4)
|
14
|
-
method_source (0.8.2)
|
15
|
-
minitest (5.10.2)
|
16
|
-
minitest-reporters (1.1.14)
|
17
|
-
ansi
|
18
|
-
builder
|
19
|
-
minitest (>= 5.0)
|
20
|
-
ruby-progressbar
|
21
|
-
mocha (1.2.1)
|
22
|
-
metaclass (~> 0.0.1)
|
23
|
-
parallel (1.12.0)
|
24
|
-
parser (2.4.0.2)
|
25
|
-
ast (~> 2.3)
|
26
|
-
powerpack (0.1.1)
|
27
|
-
rainbow (3.0.0)
|
28
|
-
rake (10.5.0)
|
29
|
-
rubocop (0.52.0)
|
30
|
-
parallel (~> 1.10)
|
31
|
-
parser (>= 2.4.0.2, < 3.0)
|
32
|
-
powerpack (~> 0.1)
|
33
|
-
rainbow (>= 2.2.2, < 4.0)
|
34
|
-
ruby-progressbar (~> 1.7)
|
35
|
-
unicode-display_width (~> 1.0, >= 1.0.1)
|
36
|
-
ruby-progressbar (1.9.0)
|
37
|
-
unicode-display_width (1.3.0)
|
38
|
-
|
39
|
-
PLATFORMS
|
40
|
-
ruby
|
41
|
-
|
42
|
-
DEPENDENCIES
|
43
|
-
bundler (~> 1.15)
|
44
|
-
byebug
|
45
|
-
cli-ui!
|
46
|
-
method_source
|
47
|
-
minitest (>= 5.0.0)
|
48
|
-
minitest-reporters
|
49
|
-
mocha
|
50
|
-
rake (~> 10.0)
|
51
|
-
rubocop
|
52
|
-
|
53
|
-
BUNDLED WITH
|
54
|
-
1.16.0
|