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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 257914b1c561094bd1e2a466a251b8e44055d806
4
- data.tar.gz: 4a0e814e44663e4740090ecb556056e4f224e0fd
3
+ metadata.gz: 367667f90cce34fe2ac10fffbd13a24a8b7a90e3
4
+ data.tar.gz: fdc151c1343bc037c8f03c3308ec3646795e9dbd
5
5
  SHA512:
6
- metadata.gz: 8a887458aa8446824c92682f32eeb995a7d002a6a1b787b68694873c7e52706de368233415f13d85b399f72e36a7c4d7cb493950d4b2773c0b6dd159b2e500fb
7
- data.tar.gz: bd0dc80707861825a752de6c325f6faf8c2f404c174446d2fa760a4224a2b7e3894c493aa0f5859a5ac947b9ba871c9c8cf2e832c59b239b6bd124fda8bf5c32
6
+ metadata.gz: 51e249672f6214028aebf3ab31b2d90cde511da996118b50607522318528c57ae0bfe40edc4b447593fb5faf2712b964fdfafdc26e1b092ce96e8ee92366e759
7
+ data.tar.gz: 58e27c5790e1bb0f35581953467a8c5a38d7ca647f3cca7042e42d347c9708dc44e9007cb326fa563b241daaaaa480662de7dfdaa2ad5a3084ecf68dc4158cf6
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ Gemfile.lock
1
2
  *.gem
2
3
  build
3
4
  .vagrant
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
  ![Interactive Prompt](https://user-images.githubusercontent.com/3074765/33797984-0ebb5e64-dcdf-11e7-9e7e-7204f279cece.gif)
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
- private_constant :InteractiveOptions
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 to ask the user. Will use +InteractiveOptions+ to do so
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
- # Question with answers
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
- def ask(question, options: nil, default: nil, is_file: nil, allow_empty: true)
56
- if (default && !allow_empty) || (options && (default || is_file))
57
- raise(ArgumentError, 'conflicting arguments')
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 default
61
- puts_question("#{question} (empty = #{default})")
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
- puts_question(question)
82
+ ask_free_form(question, default, is_file, allow_empty)
66
83
  end
84
+ end
67
85
 
68
- # Present the user with options
69
- if options
70
- resp = InteractiveOptions.call(options)
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
- # Clear the line, and reset the question to include the answer
73
- print(ANSI.previous_line + ANSI.end_of_line + ' ')
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
- return resp
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
- # Asks the user a yes/no question.
98
- # Can use arrows, y/n, numbers (1/2), and vim bindings to control
99
- #
100
- # ==== Example Usage:
101
- #
102
- # Confirmation question
103
- # CLI::UI::Prompt.confirm('Is the sky blue?')
104
- #
105
- def confirm(question)
106
- ask(question, options: %w(yes no)) == 'yes'
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
- private
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
@@ -1,5 +1,5 @@
1
1
  module CLI
2
2
  module UI
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
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.0.0
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: 2017-12-15 00:00:00.000000000 Z
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