inquirer 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
![List example](example/list.png)
|
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
|
![Checkbox example](example/checkbox.png)
|
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
|
+
![Input example](example/input.png)
|
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
|
+
![Input example](example/confirm.png)
|
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://avatars1.githubusercontent.com/u/228037?s=16) [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:
|