inquirer 0.1.2 → 0.2.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 +8 -0
- data/README.md +60 -2
- data/example/checkbox.png +0 -0
- data/example/checkbox.rb +5 -0
- data/example/confirm.png +0 -0
- data/example/confirm.rb +5 -0
- data/example/input.png +0 -0
- data/example/input.rb +6 -0
- data/example/list.png +0 -0
- data/example/list.rb +5 -0
- data/lib/inquirer.rb +8 -0
- data/lib/inquirer/prompts/checkbox.rb +53 -15
- data/lib/inquirer/prompts/confirm.rb +114 -0
- data/lib/inquirer/prompts/input.rb +130 -0
- data/lib/inquirer/prompts/list.rb +50 -16
- data/lib/inquirer/utils/iohelper.rb +26 -17
- data/lib/inquirer/version.rb +1 -1
- data/test/classes/checkbox_spec.rb +19 -9
- data/test/classes/confirm_spec.rb +50 -0
- data/test/classes/input_spec.rb +24 -0
- data/test/classes/list_spec.rb +19 -9
- data/test/minitest_helper.rb +5 -3
- metadata +16 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97119771a6f5d25b26a8c9e46d21833da7916364
|
4
|
+
data.tar.gz: 85d97425f2efb04f5a1cbd9b7029d0c1f41b1fe2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8322479e68acb817daa91c465302a45e35ea2798386ba367f948ebd93dbd22ef7be33bf6410ff21e0fc82d5cd33d7b0e8ef07f57a54b49aed71859b6886ec3c0
|
7
|
+
data.tar.gz: 60ae3b63e8ebd9738b755d485294605c751979102026d0cd0e976c25a7989b2c41ee6c26ea0a1598891b0f2e743e3248286486c43a1be6875826fa502d16a276
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 0.2.0
|
2
|
+
|
3
|
+
* feature: add user input prompt with support for default values
|
4
|
+
* feature: add confirmation prompt with support for default values
|
5
|
+
* feature: render response for all prompts if desired
|
6
|
+
* improvement: hide the cursor in the list and checkbox prompts
|
7
|
+
* bugfix: fix the clear method not clearing every line on the way up
|
8
|
+
|
1
9
|
## 0.1.1
|
2
10
|
|
3
11
|
* feature: add (and verify) rubinius 2.1 + 2.2 support
|
data/README.md
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
|
5
5
|
Interactive user prompts on CLI for ruby.
|
6
6
|
|
7
|
-
##
|
7
|
+
## Prompt types
|
8
|
+
|
9
|
+
### List
|
8
10
|
|
9
11
|
```ruby
|
10
12
|
idx = Ask.list "Look behind you...", [
|
@@ -17,6 +19,8 @@ idx = Ask.list "Look behind you...", [
|
|
17
19
|
|
18
20
|

|
19
21
|
|
22
|
+
### Checkbox
|
23
|
+
|
20
24
|
```ruby
|
21
25
|
idx = Ask.checkbox "Monkey see, monkey...", [
|
22
26
|
"don't",
|
@@ -28,6 +32,54 @@ idx = Ask.checkbox "Monkey see, monkey...", [
|
|
28
32
|
|
29
33
|

|
30
34
|
|
35
|
+
### Input
|
36
|
+
|
37
|
+
Takes optional `default` property (`string`).
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
firstname = Ask.input "What's your name"
|
41
|
+
phone = Ask.input "What's your phone number", default: "123"
|
42
|
+
# name and phone are the responses for each question
|
43
|
+
```
|
44
|
+
|
45
|
+

|
46
|
+
|
47
|
+
### Confirm
|
48
|
+
|
49
|
+
Takes optional `default` property (`true` or `false`). The default `default` value is true.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
value = Ask.confirm "Are you sure?"
|
53
|
+
# value is a boolean
|
54
|
+
|
55
|
+
Ask.confirm "Are you sure?", default: false
|
56
|
+
# Default is false
|
57
|
+
```
|
58
|
+
|
59
|
+

|
60
|
+
|
61
|
+
## Options
|
62
|
+
|
63
|
+
### Method parameters
|
64
|
+
|
65
|
+
- question: `string` The text to your are going to ask
|
66
|
+
- elements: `array` Array of options to show. Only for `checkbox` and `list` types.
|
67
|
+
|
68
|
+
### Rendering options
|
69
|
+
|
70
|
+
You can pass this options as the lastest parameter
|
71
|
+
|
72
|
+
- clear: `bool` [Default true] Clear the original question after pressing enter
|
73
|
+
- response: `bool` [Default true] Whether to show the selected response
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
# If you dont want any output use
|
77
|
+
Ask.input "What's your name", response: false
|
78
|
+
|
79
|
+
# If you don't want the response and you want to keep the question prompt
|
80
|
+
Ask.input "What's your name", clear: false, response: false
|
81
|
+
```
|
82
|
+
|
31
83
|
## Installation
|
32
84
|
|
33
85
|
gem install inquirer
|
@@ -42,6 +94,12 @@ idx = Ask.checkbox "Monkey see, monkey...", [
|
|
42
94
|
| Rubinius 2.2.1 | ✔ | ✔ | ✘ |
|
43
95
|
| JRuby 1.7.x | ✘ | ✘ | ✘ |
|
44
96
|
|
97
|
+
## Contributors
|
98
|
+
|
99
|
+
**Thank you for contributing!**
|
100
|
+
|
101
|
+
*  [blackjid](https://github.com/blackjid)
|
102
|
+
|
45
103
|
## Credit
|
46
104
|
|
47
105
|
This is basically the wonderful [Inquirer.js](https://github.com/SBoudrias/Inquirer.js), just done for ruby. I was unable to find a good gem to handle user interaction in ruby as well as this module does in JS.
|
@@ -49,4 +107,4 @@ This is basically the wonderful [Inquirer.js](https://github.com/SBoudrias/Inqui
|
|
49
107
|
## License
|
50
108
|
|
51
109
|
Apache v2
|
52
|
-
Author: Dominik Richter
|
110
|
+
Author: Dominik Richter
|
data/example/checkbox.png
CHANGED
Binary file
|
data/example/checkbox.rb
CHANGED
data/example/confirm.png
ADDED
Binary file
|
data/example/confirm.rb
ADDED
data/example/input.png
ADDED
Binary file
|
data/example/input.rb
ADDED
data/example/list.png
CHANGED
Binary file
|
data/example/list.rb
CHANGED
data/lib/inquirer.rb
CHANGED
@@ -2,6 +2,8 @@ require 'inquirer/version'
|
|
2
2
|
require 'inquirer/utils/iohelper'
|
3
3
|
require 'inquirer/prompts/list'
|
4
4
|
require 'inquirer/prompts/checkbox'
|
5
|
+
require 'inquirer/prompts/input'
|
6
|
+
require 'inquirer/prompts/confirm'
|
5
7
|
|
6
8
|
module Ask
|
7
9
|
extend self
|
@@ -12,4 +14,10 @@ module Ask
|
|
12
14
|
def checkbox *args
|
13
15
|
Checkbox.ask *args
|
14
16
|
end
|
17
|
+
def input *args
|
18
|
+
Input.ask *args
|
19
|
+
end
|
20
|
+
def confirm *args
|
21
|
+
Confirm.ask *args
|
22
|
+
end
|
15
23
|
end
|
@@ -14,6 +14,13 @@ module CheckboxRenderer
|
|
14
14
|
( footer.nil? ? "" : @footer % footer )
|
15
15
|
end
|
16
16
|
|
17
|
+
def renderResponse heading = nil, response = nil
|
18
|
+
# render the heading
|
19
|
+
( heading.nil? ? "" : @heading % heading ) +
|
20
|
+
# render the footer
|
21
|
+
( response.nil? ? "" : @response % response )
|
22
|
+
end
|
23
|
+
|
17
24
|
private
|
18
25
|
|
19
26
|
def render_item x
|
@@ -40,14 +47,25 @@ class CheckboxDefault
|
|
40
47
|
end
|
41
48
|
end
|
42
49
|
|
50
|
+
# Default formatting for response
|
51
|
+
class CheckboxResponseDefault
|
52
|
+
include CheckboxRenderer
|
53
|
+
C = Term::ANSIColor
|
54
|
+
def initialize( style = nil )
|
55
|
+
@heading = "%s: "
|
56
|
+
@response = C.cyan("%s") + "\n"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
43
60
|
class Checkbox
|
44
|
-
def initialize question = nil, elements = [], renderer = nil
|
61
|
+
def initialize question = nil, elements = [], renderer = nil, responseRenderer = nil
|
45
62
|
@elements = elements
|
46
63
|
@question = question
|
47
64
|
@pos = 0
|
48
65
|
@active = elements.map{|i| false}
|
49
66
|
@prompt = ""
|
50
67
|
@renderer = renderer || CheckboxDefault.new( Inquirer::Style::Default )
|
68
|
+
@responseRenderer = responseRenderer = CheckboxResponseDefault.new()
|
51
69
|
end
|
52
70
|
|
53
71
|
def update_prompt
|
@@ -63,35 +81,55 @@ class Checkbox
|
|
63
81
|
@prompt = @renderer.render(@question, e)
|
64
82
|
end
|
65
83
|
|
84
|
+
def update_response
|
85
|
+
e = @elements
|
86
|
+
.map.with_index(0)
|
87
|
+
.select {|f, pos| @active[pos] }
|
88
|
+
.map {|f, pos| f }
|
89
|
+
@prompt = @responseRenderer.renderResponse(@question, e.join(", "))
|
90
|
+
end
|
91
|
+
|
66
92
|
# Run the list selection, wait for the user to select an item and return
|
67
93
|
# the selected index
|
68
94
|
# Params:
|
69
95
|
# +clear+:: +Bool+ whether to clear the selection prompt once this is done
|
70
96
|
# defaults to true; set it to false if you want the prompt to remain after
|
71
97
|
# the user is done with selecting
|
72
|
-
|
98
|
+
# +response+:: +Bool+ whether show the rendered response when this is done
|
99
|
+
# defaults to true; set it to false if you want the prompt to remain after
|
100
|
+
# the user is done with selecting
|
101
|
+
def run clear, response
|
73
102
|
# finish if there's nothing to do
|
74
103
|
return @active if Array(@elements).empty?
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
104
|
+
|
105
|
+
# hides the cursor while prompting
|
106
|
+
IOHelper.without_cursor do
|
107
|
+
# render the
|
108
|
+
IOHelper.render( update_prompt )
|
109
|
+
# loop through user input
|
110
|
+
IOHelper.read_key_while do |key|
|
111
|
+
@pos = (@pos - 1) % @elements.length if key == "up"
|
112
|
+
@pos = (@pos + 1) % @elements.length if key == "down"
|
113
|
+
@active[@pos] = !@active[@pos] if key == "space"
|
114
|
+
IOHelper.rerender( update_prompt )
|
115
|
+
# we are done if the user hits return
|
116
|
+
key != "return"
|
117
|
+
end
|
85
118
|
end
|
119
|
+
|
86
120
|
# clear the final prompt and the line
|
87
121
|
IOHelper.clear if clear
|
122
|
+
|
123
|
+
# show the answer
|
124
|
+
IOHelper.render( update_response ) if response
|
125
|
+
|
88
126
|
# return the index of the selected item
|
89
127
|
@active
|
90
128
|
end
|
91
129
|
|
92
|
-
def self.ask question = nil, elements = [], opts = {
|
93
|
-
l = Checkbox.new question, elements, opts[:renderer]
|
94
|
-
l.run opts
|
130
|
+
def self.ask question = nil, elements = [], opts = {}
|
131
|
+
l = Checkbox.new question, elements, opts[:renderer], opts[:rendererResponse]
|
132
|
+
l.run opts.fetch(:clear, true), opts.fetch(:response, true)
|
95
133
|
end
|
96
134
|
|
97
135
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
# Base rendering for confirm
|
4
|
+
module ConfirmRenderer
|
5
|
+
def render heading = nil, default = nil, footer = nil
|
6
|
+
options = ['y','n']
|
7
|
+
options[0].capitalize! if default == true
|
8
|
+
options[1].capitalize! if default == false
|
9
|
+
|
10
|
+
# render the heading
|
11
|
+
( heading.nil? ? "" : @heading % heading ) +
|
12
|
+
# render the defaults
|
13
|
+
@default % options +
|
14
|
+
# render the footer
|
15
|
+
( footer.nil? ? "" : @footer % footer )
|
16
|
+
end
|
17
|
+
|
18
|
+
def renderResponse heading = nil, response = nil
|
19
|
+
# render the heading
|
20
|
+
( heading.nil? ? "" : @heading % heading ) +
|
21
|
+
# render the footer
|
22
|
+
( response.nil? ? "" : @response % response )
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Default formatting for confirm rendering
|
27
|
+
class ConfirmDefault
|
28
|
+
include ConfirmRenderer
|
29
|
+
C = Term::ANSIColor
|
30
|
+
def initialize( style )
|
31
|
+
@heading = "%s: "
|
32
|
+
@default = "(%s/%s)"
|
33
|
+
@footer = "%s"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Default formatting for response
|
38
|
+
class ConfirmResponseDefault
|
39
|
+
include ConfirmRenderer
|
40
|
+
C = Term::ANSIColor
|
41
|
+
def initialize( style = nil )
|
42
|
+
@heading = "%s: "
|
43
|
+
@response = C.cyan("%s") + "\n"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Confirm
|
48
|
+
def initialize question = nil, default = nil, renderer = nil, responseRenderer = nil
|
49
|
+
@question = question
|
50
|
+
@value = ""
|
51
|
+
@default = default
|
52
|
+
@prompt = ""
|
53
|
+
@renderer = renderer || ConfirmDefault.new( Inquirer::Style::Default )
|
54
|
+
@responseRenderer = responseRenderer = ConfirmResponseDefault.new()
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_prompt
|
58
|
+
# call the renderer
|
59
|
+
@prompt = @renderer.render(@question, @default)
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_response
|
63
|
+
@prompt = @responseRenderer.renderResponse(@question, (@value)? 'Yes' : 'No')
|
64
|
+
end
|
65
|
+
|
66
|
+
# Run the list selection, wait for the user to select an item and return
|
67
|
+
# the selected index
|
68
|
+
# Params:
|
69
|
+
# +clear+:: +Bool+ whether to clear the selection prompt once this is done
|
70
|
+
# defaults to true; set it to false if you want the prompt to remain after
|
71
|
+
# the user is done with selecting
|
72
|
+
# +response+:: +Bool+ whether show the rendered response when this is done
|
73
|
+
# defaults to true; set it to false if you want the prompt to remain after
|
74
|
+
# the user is done with selecting
|
75
|
+
def run clear, response
|
76
|
+
# render the
|
77
|
+
IOHelper.render( update_prompt )
|
78
|
+
# loop through user confirm
|
79
|
+
# IOHelper.read_char
|
80
|
+
IOHelper.read_key_while true do |key|
|
81
|
+
raw = IOHelper.char_to_raw(key)
|
82
|
+
|
83
|
+
case raw
|
84
|
+
when "y","Y"
|
85
|
+
@value = true
|
86
|
+
false
|
87
|
+
when "n","N"
|
88
|
+
@value = false
|
89
|
+
false
|
90
|
+
when "return"
|
91
|
+
@value = @default
|
92
|
+
false
|
93
|
+
else
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
# clear the final prompt and the line
|
100
|
+
IOHelper.clear if clear
|
101
|
+
|
102
|
+
# show the answer
|
103
|
+
IOHelper.render( update_response ) if response
|
104
|
+
|
105
|
+
# return the value
|
106
|
+
@value
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.ask question = nil, opts = {}
|
110
|
+
l = Confirm.new question, opts.fetch(:default, true), opts[:renderer], opts[:rendererResponse]
|
111
|
+
l.run opts.fetch(:clear, true), opts.fetch(:response, true)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
# Base rendering for input
|
4
|
+
module InputRenderer
|
5
|
+
def render heading = nil, value = nil, default = nil, footer = nil
|
6
|
+
# render the heading
|
7
|
+
( heading.nil? ? "" : @heading % heading ) +
|
8
|
+
# render the defaults
|
9
|
+
( default.nil? ? "" : @default % default ) +
|
10
|
+
# render the list
|
11
|
+
( value.nil? ? "" : @value % value ) +
|
12
|
+
# render the footer
|
13
|
+
( footer.nil? ? "" : @footer % footer )
|
14
|
+
end
|
15
|
+
|
16
|
+
def renderResponse heading = nil, response = nil
|
17
|
+
# render the heading
|
18
|
+
( heading.nil? ? "" : @heading % heading ) +
|
19
|
+
# render the footer
|
20
|
+
( response.nil? ? "" : @response % response )
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Default formatting for list rendering
|
25
|
+
class InputDefault
|
26
|
+
include InputRenderer
|
27
|
+
C = Term::ANSIColor
|
28
|
+
def initialize( style )
|
29
|
+
@heading = "%s: "
|
30
|
+
@default = "(%s) "
|
31
|
+
@value = "%s"
|
32
|
+
@footer = "%s"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Default formatting for response
|
37
|
+
class InputResponseDefault
|
38
|
+
include InputRenderer
|
39
|
+
C = Term::ANSIColor
|
40
|
+
def initialize( style = nil )
|
41
|
+
@heading = "%s: "
|
42
|
+
@response = C.cyan("%s") + "\n"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Input
|
47
|
+
def initialize question = nil, default = nil, renderer = nil, responseRenderer = nil
|
48
|
+
@question = question
|
49
|
+
@value = ""
|
50
|
+
@default = default
|
51
|
+
@prompt = ""
|
52
|
+
@pos = 0
|
53
|
+
@renderer = renderer || InputDefault.new( Inquirer::Style::Default )
|
54
|
+
@responseRenderer = responseRenderer = InputResponseDefault.new()
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_prompt
|
58
|
+
# call the renderer
|
59
|
+
@prompt = @renderer.render(@question, @value, @default)
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_response
|
63
|
+
@prompt = @responseRenderer.renderResponse(@question, @value)
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_cursor
|
67
|
+
print IOHelper.char_left * @pos
|
68
|
+
end
|
69
|
+
|
70
|
+
# Run the list selection, wait for the user to select an item and return
|
71
|
+
# the selected index
|
72
|
+
# Params:
|
73
|
+
# +clear+:: +Bool+ whether to clear the selection prompt once this is done
|
74
|
+
# defaults to true; set it to false if you want the prompt to remain after
|
75
|
+
# the user is done with selecting
|
76
|
+
# +response+:: +Bool+ whether show the rendered response when this is done
|
77
|
+
# defaults to true; set it to false if you want the prompt to remain after
|
78
|
+
# the user is done with selecting
|
79
|
+
def run clear, response
|
80
|
+
# render the
|
81
|
+
IOHelper.render( update_prompt )
|
82
|
+
# loop through user input
|
83
|
+
# IOHelper.read_char
|
84
|
+
IOHelper.read_key_while true do |key|
|
85
|
+
raw = IOHelper.char_to_raw(key)
|
86
|
+
|
87
|
+
case raw
|
88
|
+
when "backspace"
|
89
|
+
@value = @value.chop
|
90
|
+
IOHelper.rerender( update_prompt )
|
91
|
+
update_cursor
|
92
|
+
when "left"
|
93
|
+
if @pos < @value.length
|
94
|
+
@pos = @pos + 1
|
95
|
+
print IOHelper.char_left
|
96
|
+
end
|
97
|
+
when "right"
|
98
|
+
if @pos > 0
|
99
|
+
@pos = @pos - 1
|
100
|
+
print IOHelper.char_right
|
101
|
+
end
|
102
|
+
when "return"
|
103
|
+
if not @default.nil? and @value == ""
|
104
|
+
@value = @default
|
105
|
+
end
|
106
|
+
else
|
107
|
+
unless ["up", "down"].include?(raw)
|
108
|
+
@value = @value.insert(@value.length - @pos, key)
|
109
|
+
IOHelper.rerender( update_prompt )
|
110
|
+
update_cursor
|
111
|
+
end
|
112
|
+
end
|
113
|
+
raw != "return"
|
114
|
+
end
|
115
|
+
# clear the final prompt and the line
|
116
|
+
IOHelper.clear if clear
|
117
|
+
|
118
|
+
# show the answer
|
119
|
+
IOHelper.render( update_response ) if response
|
120
|
+
|
121
|
+
# return the value
|
122
|
+
@value
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.ask question = nil, opts = {}
|
126
|
+
l = Input.new question, opts[:default], opts[:renderer], opts[:rendererResponse]
|
127
|
+
l.run opts.fetch(:clear, true), opts.fetch(:response, true)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
@@ -13,6 +13,13 @@ module ListRenderer
|
|
13
13
|
( footer.nil? ? "" : @footer % footer )
|
14
14
|
end
|
15
15
|
|
16
|
+
def renderResponse heading = nil, response = nil
|
17
|
+
# render the heading
|
18
|
+
( heading.nil? ? "" : @heading % heading ) +
|
19
|
+
# render the footer
|
20
|
+
( response.nil? ? "" : @response % response )
|
21
|
+
end
|
22
|
+
|
16
23
|
private
|
17
24
|
|
18
25
|
def render_item x
|
@@ -34,13 +41,24 @@ class ListDefault
|
|
34
41
|
end
|
35
42
|
end
|
36
43
|
|
44
|
+
# Default formatting for response
|
45
|
+
class ListResponseDefault
|
46
|
+
include ListRenderer
|
47
|
+
C = Term::ANSIColor
|
48
|
+
def initialize( style = nil )
|
49
|
+
@heading = "%s: "
|
50
|
+
@response = C.cyan("%s") + "\n"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
37
54
|
class List
|
38
|
-
def initialize question = nil, elements = [], renderer = nil
|
55
|
+
def initialize question = nil, elements = [], renderer = nil, responseRenderer = nil
|
39
56
|
@elements = elements
|
40
57
|
@question = question
|
41
58
|
@pos = 0
|
42
59
|
@prompt = ""
|
43
|
-
@renderer = renderer
|
60
|
+
@renderer = renderer = ListDefault.new( Inquirer::Style::Default )
|
61
|
+
@responseRenderer = responseRenderer = ListResponseDefault.new()
|
44
62
|
end
|
45
63
|
|
46
64
|
def update_prompt
|
@@ -56,34 +74,50 @@ class List
|
|
56
74
|
@prompt = @renderer.render(@question, e)
|
57
75
|
end
|
58
76
|
|
77
|
+
def update_response
|
78
|
+
@prompt = @responseRenderer.renderResponse(@question, @elements[@pos])
|
79
|
+
end
|
80
|
+
|
59
81
|
# Run the list selection, wait for the user to select an item and return
|
60
82
|
# the selected index
|
61
83
|
# Params:
|
62
84
|
# +clear+:: +Bool+ whether to clear the selection prompt once this is done
|
63
85
|
# defaults to true; set it to false if you want the prompt to remain after
|
64
86
|
# the user is done with selecting
|
65
|
-
|
87
|
+
# +response+:: +Bool+ whether show the rendered response when this is done
|
88
|
+
# defaults to true; set it to false if you want the prompt to remain after
|
89
|
+
# the user is done with selecting
|
90
|
+
def run clear, response
|
66
91
|
# finish if there's nothing to do
|
67
92
|
return nil if Array(@elements).empty?
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
IOHelper.
|
75
|
-
|
76
|
-
|
93
|
+
|
94
|
+
# hides the cursor while prompting
|
95
|
+
IOHelper.without_cursor do
|
96
|
+
# render the
|
97
|
+
IOHelper.render( update_prompt )
|
98
|
+
# loop through user input
|
99
|
+
IOHelper.read_key_while do |key|
|
100
|
+
@pos = (@pos - 1) % @elements.length if key == "up"
|
101
|
+
@pos = (@pos + 1) % @elements.length if key == "down"
|
102
|
+
IOHelper.rerender( update_prompt )
|
103
|
+
# we are done if the user hits return
|
104
|
+
key != "return"
|
105
|
+
end
|
77
106
|
end
|
107
|
+
|
78
108
|
# clear the final prompt and the line
|
79
109
|
IOHelper.clear if clear
|
110
|
+
|
111
|
+
# show the answer
|
112
|
+
IOHelper.render( update_response ) if response
|
113
|
+
|
80
114
|
# return the index of the selected item
|
81
115
|
@pos
|
82
116
|
end
|
83
117
|
|
84
|
-
def self.ask question = nil, elements = [], opts = {
|
85
|
-
l = List.new question, elements, opts[:renderer]
|
86
|
-
l.run opts
|
118
|
+
def self.ask question = nil, elements = [], opts = {}
|
119
|
+
l = List.new question, elements, opts[:renderer], opts[:rendererResponse]
|
120
|
+
l.run opts.fetch(:clear, true), opts.fetch(:response, true)
|
87
121
|
end
|
88
122
|
|
89
|
-
end
|
123
|
+
end
|
@@ -56,21 +56,21 @@ module IOHelper
|
|
56
56
|
# Params:
|
57
57
|
# +with_exit_codes+:: +Bool+ whether to throw Interrupts when the user presses
|
58
58
|
# ctrl-c and ctrl-d. (true by default)
|
59
|
-
def read_key with_exit_codes = true
|
60
|
-
|
61
|
-
raise Interrupt if with_exit_codes and (
|
62
|
-
|
59
|
+
def read_key with_exit_codes = true, return_char = false
|
60
|
+
char = read_char
|
61
|
+
raise Interrupt if with_exit_codes and ( char == "\003" or char == "\004" )
|
62
|
+
if return_char then char else char_to_raw char end
|
63
63
|
end
|
64
64
|
|
65
65
|
# Get each key the user presses and hand it one by one to the block. Do this
|
66
66
|
# as long as the block returns truthy
|
67
67
|
# Params:
|
68
68
|
# +&block+:: +Proc+ a block that receives a user key and returns truthy or falsy
|
69
|
-
def read_key_while &block
|
69
|
+
def read_key_while return_char = false, &block
|
70
70
|
STDIN.noecho do
|
71
71
|
# as long as the block doen't return falsy,
|
72
72
|
# read the user input key and sned it to the block
|
73
|
-
while block.( IOHelper.read_key )
|
73
|
+
while block.( IOHelper.read_key true, return_char )
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -100,21 +100,30 @@ module IOHelper
|
|
100
100
|
# determine how many lines to move up
|
101
101
|
n = @rendered.scan(/\n/).length
|
102
102
|
# jump back to the first position and clear the line
|
103
|
-
print carriage_return + ( line_up * n
|
103
|
+
print carriage_return + ( line_up + clear_line ) * n + clear_line
|
104
|
+
end
|
105
|
+
|
106
|
+
# hides the cursor and ensure the curso be visible at the end
|
107
|
+
def without_cursor
|
108
|
+
# tell the terminal to hide the cursor
|
109
|
+
print `tput civis`
|
110
|
+
begin
|
111
|
+
# run the block
|
112
|
+
yield
|
113
|
+
ensure
|
114
|
+
# tell the terminal to show the cursor
|
115
|
+
print `tput cnorm`
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def char_to_raw char
|
120
|
+
KEYS.fetch char, char
|
104
121
|
end
|
105
122
|
|
106
123
|
def carriage_return; "\r" end
|
107
124
|
def line_up; "\e[A" end
|
108
125
|
def clear_line; "\e[0K" end
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
def read_key_raw
|
113
|
-
c = read_char
|
114
|
-
# try to get the key name from the character
|
115
|
-
k = KEYS[c]
|
116
|
-
# return either the character or key name
|
117
|
-
( k.nil? ) ? c : k
|
118
|
-
end
|
126
|
+
def char_left; "\e[D" end
|
127
|
+
def char_right; "\e[C" end
|
119
128
|
|
120
129
|
end
|
data/lib/inquirer/version.rb
CHANGED
@@ -8,51 +8,61 @@ describe Checkbox do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "finishes rendering with a clear" do
|
11
|
-
Checkbox.ask "select", ["one","two","three"]
|
11
|
+
Checkbox.ask "select", ["one","two","three"], response: false
|
12
12
|
IOHelper.output.must_equal ""
|
13
13
|
end
|
14
14
|
|
15
15
|
it "doesn't render the dialog with 0 items" do
|
16
|
-
Checkbox.ask "select", [], clear: false
|
16
|
+
Checkbox.ask "select", [], clear: false, response: false
|
17
17
|
IOHelper.output.must_equal ""
|
18
18
|
end
|
19
19
|
|
20
20
|
it "renders the dialog with 3 items" do
|
21
|
-
Checkbox.ask "select", ["one","two","three"], clear: false
|
21
|
+
Checkbox.ask "select", ["one","two","three"], clear: false, response: false
|
22
22
|
IOHelper.output.must_equal "select:\n\e[36m‣\e[0m⬡ one\n ⬡ two\n ⬡ three\n"
|
23
23
|
end
|
24
24
|
|
25
25
|
it "it finishes selection on pressing enter" do
|
26
26
|
IOHelper.keys = "enter"
|
27
|
-
Checkbox.ask( "select", ["one","two","three"], clear: false
|
27
|
+
Checkbox.ask( "select", ["one","two","three"], clear: false, response: false
|
28
28
|
).must_equal [false,false,false]
|
29
29
|
end
|
30
30
|
|
31
31
|
it "selects and renders other items correctly (press down, press up, space, cycle)" do
|
32
32
|
IOHelper.keys = ["down","space","enter"]
|
33
|
-
Checkbox.ask( "select", ["one","two","three"], clear: false
|
33
|
+
Checkbox.ask( "select", ["one","two","three"], clear: false, response: false
|
34
34
|
).must_equal [false,true,false]
|
35
35
|
IOHelper.output.must_equal "select:\n ⬡ one\n\e[36m‣\e[0m\e[36m⬢\e[0m two\n ⬡ three\n"
|
36
36
|
|
37
37
|
IOHelper.keys = ["space","down","space","enter"]
|
38
|
-
Checkbox.ask( "select", ["one","two","three"], clear: false
|
38
|
+
Checkbox.ask( "select", ["one","two","three"], clear: false, response: false
|
39
39
|
).must_equal [true,true,false]
|
40
40
|
IOHelper.output.must_equal "select:\n \e[36m⬢\e[0m one\n\e[36m‣\e[0m\e[36m⬢\e[0m two\n ⬡ three\n"
|
41
41
|
|
42
42
|
IOHelper.keys = ["space","down","space","down","space","enter"]
|
43
|
-
Checkbox.ask( "select", ["one","two","three"], clear: false
|
43
|
+
Checkbox.ask( "select", ["one","two","three"], clear: false, response: false
|
44
44
|
).must_equal [true,true,true]
|
45
45
|
IOHelper.output.must_equal "select:\n \e[36m⬢\e[0m one\n \e[36m⬢\e[0m two\n\e[36m‣\e[0m\e[36m⬢\e[0m three\n"
|
46
46
|
|
47
47
|
IOHelper.keys = ["down","down","down","space","enter"]
|
48
|
-
Checkbox.ask( "select", ["one","two","three"], clear: false
|
48
|
+
Checkbox.ask( "select", ["one","two","three"], clear: false, response: false
|
49
49
|
).must_equal [true,false,false]
|
50
50
|
IOHelper.output.must_equal "select:\n\e[36m‣\e[0m\e[36m⬢\e[0m one\n ⬡ two\n ⬡ three\n"
|
51
51
|
|
52
52
|
IOHelper.keys = ["up","space","enter"]
|
53
|
-
Checkbox.ask( "select", ["one","two","three"], clear: false
|
53
|
+
Checkbox.ask( "select", ["one","two","three"], clear: false, response: false
|
54
54
|
).must_equal [false,false,true]
|
55
55
|
IOHelper.output.must_equal "select:\n ⬡ one\n ⬡ two\n\e[36m‣\e[0m\e[36m⬢\e[0m three\n"
|
56
56
|
end
|
57
57
|
|
58
|
+
it "selects and renders response correctly" do
|
59
|
+
IOHelper.keys = ["down","space","enter"]
|
60
|
+
Checkbox.ask( "select", ["one","two","three"])
|
61
|
+
IOHelper.output.must_equal "select: \e[36mtwo\e[0m\n"
|
62
|
+
|
63
|
+
IOHelper.keys = ["space","down","space","enter"]
|
64
|
+
Checkbox.ask( "select", ["one","two","three"])
|
65
|
+
IOHelper.output.must_equal "select: \e[36mone, two\e[0m\n"
|
66
|
+
end
|
67
|
+
|
58
68
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'minitest_helper'
|
3
|
+
|
4
|
+
describe Confirm do
|
5
|
+
before :each do
|
6
|
+
IOHelper.output = ""
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return true for y and Y and enter when default" do
|
10
|
+
IOHelper.keys = "y"
|
11
|
+
Confirm.ask("Are you sure?").must_equal true
|
12
|
+
IOHelper.keys = "Y"
|
13
|
+
Confirm.ask("Are you sure?").must_equal true
|
14
|
+
IOHelper.keys = "\r"
|
15
|
+
Confirm.ask("Are you sure?", default: true).must_equal true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return false for n and N and enter when default" do
|
19
|
+
IOHelper.keys = "n"
|
20
|
+
Confirm.ask("Are you sure?").must_equal false
|
21
|
+
IOHelper.keys = "N"
|
22
|
+
Confirm.ask("Are you sure?").must_equal false
|
23
|
+
IOHelper.keys = "\r"
|
24
|
+
Confirm.ask("Are you sure?", default: false).must_equal false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return true if not default given" do
|
28
|
+
IOHelper.keys = "\r"
|
29
|
+
Confirm.ask("Are you sure?").must_equal true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "accepts and renders response correctly" do
|
33
|
+
IOHelper.keys = "n"
|
34
|
+
Confirm.ask("Are you sure?")
|
35
|
+
IOHelper.output.must_equal "Are you sure?: \e[36mNo\e[0m\n"
|
36
|
+
|
37
|
+
IOHelper.keys = "N"
|
38
|
+
Confirm.ask("Are you sure?")
|
39
|
+
IOHelper.output.must_equal "Are you sure?: \e[36mNo\e[0m\n"
|
40
|
+
|
41
|
+
IOHelper.keys = "y"
|
42
|
+
Confirm.ask("Are you sure?")
|
43
|
+
IOHelper.output.must_equal "Are you sure?: \e[36mYes\e[0m\n"
|
44
|
+
|
45
|
+
IOHelper.keys = "y"
|
46
|
+
Confirm.ask("Are you sure?")
|
47
|
+
IOHelper.output.must_equal "Are you sure?: \e[36mYes\e[0m\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'minitest_helper'
|
3
|
+
|
4
|
+
describe Input do
|
5
|
+
before :each do
|
6
|
+
IOHelper.output = ""
|
7
|
+
IOHelper.keys = ['t','y','p','e','d',' ','i','n','p','u','t',"\r"]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should use chars value from the user" do
|
11
|
+
Input.ask("please type input").must_equal "typed input"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "accepts and renders response correctly" do
|
15
|
+
Input.ask("please type input")
|
16
|
+
IOHelper.output.must_equal "please type input: \e[36mtyped input\e[0m\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return default value if given and there is no input" do
|
20
|
+
IOHelper.keys = "\r"
|
21
|
+
Confirm.ask("Are you sure?", default: "I'm default").must_equal "I'm default"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/test/classes/list_spec.rb
CHANGED
@@ -8,51 +8,61 @@ describe List do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "finishes rendering with a clear" do
|
11
|
-
List.ask "select", ["one","two","three"]
|
11
|
+
List.ask "select", ["one","two","three"], response: false
|
12
12
|
IOHelper.output.must_equal ""
|
13
13
|
end
|
14
14
|
|
15
15
|
it "doesn't render the dialog with 0 items" do
|
16
|
-
List.ask "select", [], clear: false
|
16
|
+
List.ask "select", [], clear: false, response: false
|
17
17
|
IOHelper.output.must_equal ""
|
18
18
|
end
|
19
19
|
|
20
20
|
it "renders the dialog with 3 items" do
|
21
|
-
List.ask "select", ["one","two","three"], clear: false
|
21
|
+
List.ask "select", ["one","two","three"], clear: false, response: false
|
22
22
|
IOHelper.output.must_equal "select:\n\e[36m‣\e[0m \e[36mone\e[0m\n two\n three\n"
|
23
23
|
end
|
24
24
|
|
25
25
|
it "it finishes selection on pressing enter" do
|
26
26
|
IOHelper.keys = "enter"
|
27
|
-
List.ask( "select", ["one","two","three"], clear: false
|
27
|
+
List.ask( "select", ["one","two","three"], clear: false, response: false
|
28
28
|
).must_equal 0
|
29
29
|
end
|
30
30
|
|
31
31
|
it "selects and renders other items correctly (press down, press up, cycle)" do
|
32
32
|
IOHelper.keys = ["down","enter"]
|
33
|
-
List.ask( "select", ["one","two","three"], clear: false
|
33
|
+
List.ask( "select", ["one","two","three"], clear: false, response: false
|
34
34
|
).must_equal 1
|
35
35
|
IOHelper.output.must_equal "select:\n one\n\e[36m‣\e[0m \e[36mtwo\e[0m\n three\n"
|
36
36
|
|
37
37
|
IOHelper.keys = ["down","down","enter"]
|
38
|
-
List.ask( "select", ["one","two","three"], clear: false
|
38
|
+
List.ask( "select", ["one","two","three"], clear: false, response: false
|
39
39
|
).must_equal 2
|
40
40
|
IOHelper.output.must_equal "select:\n one\n two\n\e[36m‣\e[0m \e[36mthree\e[0m\n"
|
41
41
|
|
42
42
|
IOHelper.keys = ["down","down","down","enter"]
|
43
|
-
List.ask( "select", ["one","two","three"], clear: false
|
43
|
+
List.ask( "select", ["one","two","three"], clear: false, response: false
|
44
44
|
).must_equal 0
|
45
45
|
IOHelper.output.must_equal "select:\n\e[36m‣\e[0m \e[36mone\e[0m\n two\n three\n"
|
46
46
|
|
47
47
|
IOHelper.keys = ["down","up","enter"]
|
48
|
-
List.ask( "select", ["one","two","three"], clear: false
|
48
|
+
List.ask( "select", ["one","two","three"], clear: false, response: false
|
49
49
|
).must_equal 0
|
50
50
|
IOHelper.output.must_equal "select:\n\e[36m‣\e[0m \e[36mone\e[0m\n two\n three\n"
|
51
51
|
|
52
52
|
IOHelper.keys = ["up","enter"]
|
53
|
-
List.ask( "select", ["one","two","three"], clear: false
|
53
|
+
List.ask( "select", ["one","two","three"], clear: false, response: false
|
54
54
|
).must_equal 2
|
55
55
|
IOHelper.output.must_equal "select:\n one\n two\n\e[36m‣\e[0m \e[36mthree\e[0m\n"
|
56
56
|
end
|
57
57
|
|
58
|
+
it "selects and renders response correctly" do
|
59
|
+
IOHelper.keys = ["down","enter"]
|
60
|
+
List.ask( "select", ["one","two","three"])
|
61
|
+
IOHelper.output.must_equal "select: \e[36mtwo\e[0m\n"
|
62
|
+
|
63
|
+
IOHelper.keys = ["down","down","enter"]
|
64
|
+
List.ask( "select", ["one","two","three"])
|
65
|
+
IOHelper.output.must_equal "select: \e[36mthree\e[0m\n"
|
66
|
+
end
|
67
|
+
|
58
68
|
end
|
data/test/minitest_helper.rb
CHANGED
@@ -34,7 +34,9 @@ module IOHelper
|
|
34
34
|
def rerender sth
|
35
35
|
@output = sth
|
36
36
|
end
|
37
|
-
def read_key_while &block
|
38
|
-
Array(@keys).each
|
37
|
+
def read_key_while return_char = false, &block
|
38
|
+
Array(@keys).each do |key|
|
39
|
+
break unless block.(key)
|
40
|
+
end
|
39
41
|
end
|
40
|
-
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inquirer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Richter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: term-ansicolor
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.2.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.2.2
|
27
27
|
description: Interactive user prompts on CLI for ruby.
|
@@ -30,7 +30,7 @@ executables: []
|
|
30
30
|
extensions: []
|
31
31
|
extra_rdoc_files: []
|
32
32
|
files:
|
33
|
-
- .travis.yml
|
33
|
+
- ".travis.yml"
|
34
34
|
- CHANGELOG.md
|
35
35
|
- Gemfile
|
36
36
|
- LICENSE
|
@@ -38,16 +38,24 @@ files:
|
|
38
38
|
- Rakefile
|
39
39
|
- example/checkbox.png
|
40
40
|
- example/checkbox.rb
|
41
|
+
- example/confirm.png
|
42
|
+
- example/confirm.rb
|
43
|
+
- example/input.png
|
44
|
+
- example/input.rb
|
41
45
|
- example/list.png
|
42
46
|
- example/list.rb
|
43
47
|
- inquirer.gemspec
|
44
48
|
- lib/inquirer.rb
|
45
49
|
- lib/inquirer/prompts/checkbox.rb
|
50
|
+
- lib/inquirer/prompts/confirm.rb
|
51
|
+
- lib/inquirer/prompts/input.rb
|
46
52
|
- lib/inquirer/prompts/list.rb
|
47
53
|
- lib/inquirer/style.rb
|
48
54
|
- lib/inquirer/utils/iohelper.rb
|
49
55
|
- lib/inquirer/version.rb
|
50
56
|
- test/classes/checkbox_spec.rb
|
57
|
+
- test/classes/confirm_spec.rb
|
58
|
+
- test/classes/input_spec.rb
|
51
59
|
- test/classes/list_spec.rb
|
52
60
|
- test/minitest_helper.rb
|
53
61
|
homepage: https://github.com/arlimus/inquirer.rb
|
@@ -60,19 +68,18 @@ require_paths:
|
|
60
68
|
- lib
|
61
69
|
required_ruby_version: !ruby/object:Gem::Requirement
|
62
70
|
requirements:
|
63
|
-
- -
|
71
|
+
- - ">="
|
64
72
|
- !ruby/object:Gem::Version
|
65
73
|
version: '0'
|
66
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
75
|
requirements:
|
68
|
-
- -
|
76
|
+
- - ">="
|
69
77
|
- !ruby/object:Gem::Version
|
70
78
|
version: '0'
|
71
79
|
requirements: []
|
72
80
|
rubyforge_project:
|
73
|
-
rubygems_version: 2.0
|
81
|
+
rubygems_version: 2.2.0
|
74
82
|
signing_key:
|
75
83
|
specification_version: 4
|
76
84
|
summary: Interactive user prompts on CLI for ruby.
|
77
85
|
test_files: []
|
78
|
-
has_rdoc:
|