tty-prompt 0.18.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +95 -0
  3. data/README.md +598 -256
  4. data/lib/tty-prompt.rb +1 -2
  5. data/lib/tty/prompt.rb +192 -144
  6. data/lib/tty/prompt/answers_collector.rb +5 -5
  7. data/lib/tty/prompt/{enum_paginator.rb → block_paginator.rb} +20 -19
  8. data/lib/tty/prompt/choice.rb +9 -10
  9. data/lib/tty/prompt/choices.rb +30 -12
  10. data/lib/tty/prompt/confirm_question.rb +42 -16
  11. data/lib/tty/prompt/const.rb +17 -0
  12. data/lib/tty/prompt/converter_dsl.rb +6 -7
  13. data/lib/tty/prompt/converter_registry.rb +31 -26
  14. data/lib/tty/prompt/converters.rb +139 -32
  15. data/lib/tty/prompt/enum_list.rb +81 -26
  16. data/lib/tty/prompt/errors.rb +31 -0
  17. data/lib/tty/prompt/evaluator.rb +2 -2
  18. data/lib/tty/prompt/expander.rb +45 -15
  19. data/lib/tty/prompt/keypress.rb +33 -36
  20. data/lib/tty/prompt/list.rb +198 -63
  21. data/lib/tty/prompt/mask_question.rb +11 -8
  22. data/lib/tty/prompt/multi_list.rb +131 -28
  23. data/lib/tty/prompt/multiline.rb +9 -7
  24. data/lib/tty/prompt/paginator.rb +38 -26
  25. data/lib/tty/prompt/question.rb +92 -37
  26. data/lib/tty/prompt/question/checks.rb +20 -2
  27. data/lib/tty/prompt/question/modifier.rb +4 -2
  28. data/lib/tty/prompt/question/validation.rb +3 -3
  29. data/lib/tty/prompt/selected_choices.rb +77 -0
  30. data/lib/tty/prompt/slider.rb +125 -30
  31. data/lib/tty/prompt/statement.rb +3 -3
  32. data/lib/tty/prompt/suggestion.rb +7 -6
  33. data/lib/tty/prompt/symbols.rb +58 -34
  34. data/lib/tty/prompt/test.rb +36 -0
  35. data/lib/tty/prompt/timer.rb +75 -0
  36. data/lib/tty/prompt/utils.rb +1 -3
  37. data/lib/tty/prompt/version.rb +1 -1
  38. metadata +29 -227
  39. data/Rakefile +0 -8
  40. data/examples/ask.rb +0 -7
  41. data/examples/ask_valid.rb +0 -12
  42. data/examples/collect.rb +0 -21
  43. data/examples/echo.rb +0 -11
  44. data/examples/enum_select.rb +0 -7
  45. data/examples/enum_select_disabled.rb +0 -16
  46. data/examples/enum_select_paged.rb +0 -9
  47. data/examples/enum_select_wrapped.rb +0 -15
  48. data/examples/expand.rb +0 -29
  49. data/examples/in.rb +0 -9
  50. data/examples/inputs.rb +0 -10
  51. data/examples/key_events.rb +0 -15
  52. data/examples/keypress.rb +0 -9
  53. data/examples/mask.rb +0 -13
  54. data/examples/multi_select.rb +0 -8
  55. data/examples/multi_select_disabled.rb +0 -17
  56. data/examples/multi_select_paged.rb +0 -9
  57. data/examples/multi_select_wrapped.rb +0 -15
  58. data/examples/multiline.rb +0 -9
  59. data/examples/pause.rb +0 -9
  60. data/examples/select.rb +0 -24
  61. data/examples/select_disabled.rb +0 -18
  62. data/examples/select_enum.rb +0 -8
  63. data/examples/select_filtered.rb +0 -11
  64. data/examples/select_paginated.rb +0 -11
  65. data/examples/select_wrapped.rb +0 -15
  66. data/examples/slider.rb +0 -6
  67. data/examples/validation.rb +0 -9
  68. data/examples/yes_no.rb +0 -7
  69. data/lib/tty/prompt/messages.rb +0 -49
  70. data/lib/tty/prompt/timeout.rb +0 -78
  71. data/lib/tty/test_prompt.rb +0 -20
  72. data/spec/spec_helper.rb +0 -45
  73. data/spec/unit/ask_spec.rb +0 -132
  74. data/spec/unit/choice/eql_spec.rb +0 -22
  75. data/spec/unit/choice/from_spec.rb +0 -96
  76. data/spec/unit/choices/add_spec.rb +0 -12
  77. data/spec/unit/choices/each_spec.rb +0 -13
  78. data/spec/unit/choices/find_by_spec.rb +0 -10
  79. data/spec/unit/choices/new_spec.rb +0 -10
  80. data/spec/unit/choices/pluck_spec.rb +0 -9
  81. data/spec/unit/collect_spec.rb +0 -96
  82. data/spec/unit/converters/convert_bool_spec.rb +0 -58
  83. data/spec/unit/converters/convert_char_spec.rb +0 -11
  84. data/spec/unit/converters/convert_custom_spec.rb +0 -14
  85. data/spec/unit/converters/convert_date_spec.rb +0 -34
  86. data/spec/unit/converters/convert_file_spec.rb +0 -18
  87. data/spec/unit/converters/convert_number_spec.rb +0 -39
  88. data/spec/unit/converters/convert_path_spec.rb +0 -15
  89. data/spec/unit/converters/convert_range_spec.rb +0 -22
  90. data/spec/unit/converters/convert_regex_spec.rb +0 -12
  91. data/spec/unit/converters/convert_string_spec.rb +0 -21
  92. data/spec/unit/converters/on_error_spec.rb +0 -9
  93. data/spec/unit/distance/distance_spec.rb +0 -73
  94. data/spec/unit/enum_paginator_spec.rb +0 -75
  95. data/spec/unit/enum_select_spec.rb +0 -446
  96. data/spec/unit/error_spec.rb +0 -20
  97. data/spec/unit/evaluator_spec.rb +0 -67
  98. data/spec/unit/expand_spec.rb +0 -198
  99. data/spec/unit/keypress_spec.rb +0 -72
  100. data/spec/unit/mask_spec.rb +0 -132
  101. data/spec/unit/multi_select_spec.rb +0 -511
  102. data/spec/unit/multiline_spec.rb +0 -77
  103. data/spec/unit/new_spec.rb +0 -20
  104. data/spec/unit/ok_spec.rb +0 -10
  105. data/spec/unit/paginator_spec.rb +0 -73
  106. data/spec/unit/question/checks_spec.rb +0 -97
  107. data/spec/unit/question/default_spec.rb +0 -31
  108. data/spec/unit/question/echo_spec.rb +0 -38
  109. data/spec/unit/question/in_spec.rb +0 -115
  110. data/spec/unit/question/initialize_spec.rb +0 -12
  111. data/spec/unit/question/modifier/apply_to_spec.rb +0 -24
  112. data/spec/unit/question/modifier/letter_case_spec.rb +0 -41
  113. data/spec/unit/question/modifier/whitespace_spec.rb +0 -51
  114. data/spec/unit/question/modify_spec.rb +0 -41
  115. data/spec/unit/question/required_spec.rb +0 -92
  116. data/spec/unit/question/validate_spec.rb +0 -115
  117. data/spec/unit/question/validation/call_spec.rb +0 -31
  118. data/spec/unit/question/validation/coerce_spec.rb +0 -30
  119. data/spec/unit/result_spec.rb +0 -40
  120. data/spec/unit/say_spec.rb +0 -67
  121. data/spec/unit/select_spec.rb +0 -660
  122. data/spec/unit/slider_spec.rb +0 -100
  123. data/spec/unit/statement/initialize_spec.rb +0 -15
  124. data/spec/unit/subscribe_spec.rb +0 -22
  125. data/spec/unit/suggest_spec.rb +0 -28
  126. data/spec/unit/warn_spec.rb +0 -21
  127. data/spec/unit/yes_no_spec.rb +0 -251
  128. data/tasks/console.rake +0 -11
  129. data/tasks/coverage.rake +0 -11
  130. data/tasks/spec.rake +0 -29
  131. data/tty-prompt.gemspec +0 -33
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Choices, '#pluck' do
4
- it "plucks choice by key name" do
5
- collection = [{name: 'large'},{name: 'medium'},{name: 'small'}]
6
- choices = described_class[*collection]
7
- expect(choices.pluck(:name)).to eq(['large', 'medium', 'small'])
8
- end
9
- end
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt, '#collect' do
4
-
5
- subject(:prompt) { TTY::TestPrompt.new }
6
-
7
- def collect(&block)
8
- prompt = subject
9
- count = 0
10
-
11
- result = prompt.collect do
12
- while prompt.yes?("continue?")
13
- instance_eval(&block)
14
- count += 1
15
- end
16
- end
17
-
18
- result[:count] = count
19
- result
20
- end
21
-
22
- context "when receiving multiple answers" do
23
- let(:colors) { %w(red blue yellow) }
24
-
25
- before do
26
- subject.input << "y\r" + colors.join("\ry\r") + "\rn\r"
27
- subject.input.rewind
28
- end
29
-
30
- it "collects as a list if values method used in chain" do
31
- result = collect { key(:colors).values.ask("color:") }
32
- expect(result[:count]).to eq(3)
33
- expect(result[:colors]).to eq(colors)
34
- end
35
-
36
- it "collects as a list if values method used in chain with block" do
37
- result = collect do
38
- key(:colors).values { key(:name).ask("color:") }
39
- end
40
- expect(result[:count]).to eq(3)
41
- expect(result[:colors]).to eq(colors.map { |c| { name: c } })
42
- end
43
-
44
- context "with multiple keys" do
45
- let(:colors) { ["red\rblue", "yellow\rgreen"] }
46
- let(:expected_pairs) do
47
- colors.map { |s| Hash[%i(hot cold).zip(s.split("\r"))] }
48
- end
49
-
50
- it "collects into the appropriate keys" do
51
- result = collect do
52
- key(:pairs).values do
53
- key(:hot).ask("color:")
54
- key(:cold).ask("color:")
55
- end
56
- end
57
-
58
- expect(result[:count]).to eq(2)
59
- expect(result[:pairs]).to eq(expected_pairs)
60
- end
61
- end
62
-
63
- it "overrides a non-array key on multiple answers" do
64
- result = collect { key(:colors).ask("color:") }
65
- expect(result[:colors]).to eq(colors.last)
66
- expect(result[:count]).to eq(3)
67
- end
68
- end
69
-
70
- it "collects more than one answer" do
71
- prompt.input << "Piotr\r30\rStreet\rCity\r123\r"
72
- prompt.input.rewind
73
-
74
- result = prompt.collect do
75
- key(:name).ask('Name?')
76
-
77
- key(:age).ask('Age?', convert: :int)
78
-
79
- key(:address) do
80
- key(:street).ask('Street?', required: true)
81
- key(:city).ask('City?')
82
- key(:zip).ask('Zip?', validate: /\A\d{3}\Z/)
83
- end
84
- end
85
-
86
- expect(result).to include({
87
- name: 'Piotr',
88
- age: 30,
89
- address: {
90
- street: 'Street',
91
- city: 'City',
92
- zip: '123'
93
- }
94
- })
95
- end
96
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert bool' do
4
-
5
- subject(:prompt) { TTY::TestPrompt.new}
6
-
7
- it 'fails to convert boolean' do
8
- prompt.input << 'invalid'
9
- prompt.input.rewind
10
- expect {
11
- prompt.ask("Do you read books?", convert: :bool)
12
- }.to raise_error(TTY::Prompt::ConversionError)
13
- end
14
-
15
- it "handles default values" do
16
- prompt.input << "\n"
17
- prompt.input.rewind
18
- response = prompt.ask('Do you read books?', convert: :bool, default: true)
19
- expect(response).to eql(true)
20
- expect(prompt.output.string).to eq([
21
- "Do you read books? \e[90m(true)\e[0m ",
22
- "\e[2K\e[1GDo you read books? \e[90m(true)\e[0m \n",
23
- "\e[1A\e[2K\e[1G",
24
- "Do you read books? \e[32mtrue\e[0m\n"
25
- ].join)
26
- end
27
-
28
- it "handles default values" do
29
- prompt.input << "\n"
30
- prompt.input.rewind
31
- response = prompt.ask("Do you read books?") { |q|
32
- q.default true
33
- q.convert :bool
34
- }
35
- expect(response).to eq(true)
36
- end
37
-
38
- it 'converts negative boolean' do
39
- prompt.input << 'No'
40
- prompt.input.rewind
41
- response = prompt.ask('Do you read books?', convert: :bool)
42
- expect(response).to eq(false)
43
- end
44
-
45
- it 'converts positive boolean' do
46
- prompt.input << 'Yes'
47
- prompt.input.rewind
48
- response = prompt.ask("Do you read books?", convert: :bool)
49
- expect(response).to eq(true)
50
- end
51
-
52
- it 'converts single positive boolean' do
53
- prompt.input << 'y'
54
- prompt.input.rewind
55
- response = prompt.ask('Do you read books?', convert: :bool)
56
- expect(response).to eq(true)
57
- end
58
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert char' do
4
- it 'reads single character' do
5
- prompt = TTY::TestPrompt.new
6
- prompt.input << "abcde"
7
- prompt.input.rewind
8
- response = prompt.ask("What is your favourite letter?", convert: :char)
9
- expect(response).to eq('a')
10
- end
11
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert custom' do
4
-
5
- subject(:prompt) { TTY::TestPrompt.new }
6
-
7
- it 'converts response with custom conversion' do
8
- prompt.input << "one,two,three\n"
9
- prompt.input.rewind
10
- conversion = proc { |input| input.split(/,\s*/) }
11
- answer = prompt.ask('Ingredients? (comma sep list)', convert: conversion)
12
- expect(answer).to eq(['one','two','three'])
13
- end
14
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert date' do
4
-
5
- subject(:prompt) { TTY::TestPrompt.new}
6
-
7
- it 'fails to convert date' do
8
- prompt.input << 'invalid'
9
- prompt.input.rewind
10
- expect {
11
- prompt.ask("When were you born?", convert: :date)
12
- }.to raise_error(TTY::Prompt::ConversionError)
13
- end
14
-
15
- it 'converts date' do
16
- prompt.input << "20th April 1887"
17
- prompt.input.rewind
18
- response = prompt.ask("When were your born?", convert: :date)
19
- expect(response).to be_kind_of(Date)
20
- expect(response.day).to eq(20)
21
- expect(response.month).to eq(4)
22
- expect(response.year).to eq(1887)
23
- end
24
-
25
- it "converts datetime" do
26
- prompt.input << "20th April 1887"
27
- prompt.input.rewind
28
- response = prompt.ask("When were your born?", convert: :datetime)
29
- expect(response).to be_kind_of(DateTime)
30
- expect(response.day).to eq(20)
31
- expect(response.month).to eq(4)
32
- expect(response.year).to eq(1887)
33
- end
34
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert file' do
4
- it "converts to file" do
5
- ::File.write('test.txt', 'foobar')
6
-
7
- prompt = TTY::TestPrompt.new
8
- prompt.input << "test.txt"
9
- prompt.input.rewind
10
-
11
- answer = prompt.ask("Which file to open?", convert: :file)
12
-
13
- expect(::File.basename(answer)).to eq('test.txt')
14
- expect(::File.read(answer)).to eq('foobar')
15
-
16
- ::File.unlink('test.txt') unless Gem.win_platform?
17
- end
18
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert numbers' do
4
-
5
- subject(:prompt) { TTY::TestPrompt.new }
6
-
7
- it 'fails to convert integer' do
8
- prompt.input << 'invalid'
9
- prompt.input.rewind
10
- expect {
11
- prompt.ask("What temparture?", convert: :int)
12
- }.to raise_error(TTY::Prompt::ConversionError)
13
- end
14
-
15
- it 'converts integer' do
16
- prompt.input << 35
17
- prompt.input.rewind
18
- answer = prompt.ask("What temperature?", convert: :int)
19
- expect(answer).to be_a(Integer)
20
- expect(answer).to eq(35)
21
- end
22
-
23
- it 'fails to convert float' do
24
- prompt.input << 'invalid'
25
- prompt.input.rewind
26
- expect {
27
- prompt.ask("How tall are you?", convert: :float)
28
- }.to raise_error(TTY::Prompt::ConversionError)
29
- end
30
-
31
- it 'converts float' do
32
- number = 6.666
33
- prompt.input << number
34
- prompt.input.rewind
35
- answer = prompt.ask('How tall are you?', convert: :float)
36
- expect(answer).to be_a(Float)
37
- expect(answer).to eq(number)
38
- end
39
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert path' do
4
- subject(:prompt) { TTY::TestPrompt.new }
5
-
6
- it "converts pathname" do
7
- path = Pathname.new(::File.join(Dir.pwd, 'spec/unit'))
8
- prompt.input << "spec/unit"
9
- prompt.input.rewind
10
-
11
- answer = prompt.ask('File location?', convert: :path)
12
-
13
- expect(answer).to eql(path)
14
- end
15
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert range' do
4
-
5
- subject(:prompt) { TTY::TestPrompt.new}
6
-
7
- it 'converts with valid range' do
8
- prompt.input << "20-30"
9
- prompt.input.rewind
10
- answer = prompt.ask("Which age group?", convert: :range)
11
- expect(answer).to be_a(Range)
12
- expect(answer).to eq(20..30)
13
- end
14
-
15
- it "fails to convert to range" do
16
- prompt.input << "abcd"
17
- prompt.input.rewind
18
- expect {
19
- prompt.ask('Which age group?', convert: :range)
20
- }.to raise_error(TTY::Prompt::ConversionError)
21
- end
22
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert regexp' do
4
- it "converts regex" do
5
- prompt = TTY::TestPrompt.new
6
- prompt.input << "[a-z]*"
7
- prompt.input.rewind
8
- answer = prompt.ask("Regex?", convert: :regexp)
9
- expect(answer).to be_a(Regexp)
10
- expect(answer).to eq(/[a-z]*/)
11
- end
12
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Question, 'convert string' do
4
- it 'converts string' do
5
- prompt = TTY::TestPrompt.new
6
- prompt.input << 'Piotr'
7
- prompt.input.rewind
8
- answer = prompt.ask("What is your name?", convert: :string)
9
- expect(answer).to be_a(String)
10
- expect(answer).to eq('Piotr')
11
- end
12
-
13
- it "converts symbol" do
14
- prompt = TTY::TestPrompt.new
15
- prompt.input << 'Piotr'
16
- prompt.input.rewind
17
- answer = prompt.ask("What is your name?", convert: :symbol)
18
- expect(answer).to be_a(Symbol)
19
- expect(answer).to eq(:Piotr)
20
- end
21
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Converters do
4
- it "enforces block argument" do
5
- expect {
6
- TTY::Prompt::Converters.on_error
7
- }.to raise_error(ArgumentError, 'You need to provide a block argument.')
8
- end
9
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe TTY::Prompt::Distance, '.distance' do
4
- let(:object) { described_class.new }
5
-
6
- subject(:distance) { object.distance(*strings) }
7
-
8
- context 'when nil' do
9
- let(:strings) { [nil, nil] }
10
-
11
- it { is_expected.to eql(0) }
12
- end
13
-
14
- context 'when empty' do
15
- let(:strings) { ['', ''] }
16
-
17
- it { is_expected.to eql(0) }
18
- end
19
-
20
- context 'with one non empty' do
21
- let(:strings) { ['abc', ''] }
22
-
23
- it { is_expected.to eql(3) }
24
- end
25
-
26
- context 'when single char' do
27
- let(:strings) { ['a', 'abc'] }
28
-
29
- it { is_expected.to eql(2) }
30
- end
31
-
32
- context 'when similar' do
33
- let(:strings) { ['abc', 'abc'] }
34
-
35
- it { is_expected.to eql(0) }
36
- end
37
-
38
- context 'when similar' do
39
- let(:strings) { ['abc', 'acb'] }
40
-
41
- it { is_expected.to eql(1) }
42
- end
43
-
44
- context 'when end similar' do
45
- let(:strings) { ['saturday', 'sunday'] }
46
-
47
- it { is_expected.to eql(3) }
48
- end
49
-
50
- context 'when contain similar' do
51
- let(:strings) { ['which', 'witch'] }
52
-
53
- it { is_expected.to eql(2) }
54
- end
55
-
56
- context 'when prefix' do
57
- let(:strings) { ['sta', 'status'] }
58
-
59
- it { is_expected.to eql(3) }
60
- end
61
-
62
- context 'when similar' do
63
- let(:strings) { ['smellyfish','jellyfish'] }
64
-
65
- it { is_expected.to eql(2) }
66
- end
67
-
68
- context 'when unicode' do
69
- let(:strings) { ['マラソン五輪代表', 'ララソン五輪代表'] }
70
-
71
- it { is_expected.to eql(1) }
72
- end
73
- end