tty-prompt 0.1.0 → 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/.travis.yml +0 -2
- data/CHANGELOG.md +12 -0
- data/README.md +223 -59
- data/lib/tty/prompt/choice.rb +83 -0
- data/lib/tty/prompt/choices.rb +92 -0
- data/lib/tty/prompt/codes.rb +32 -0
- data/lib/tty/prompt/cursor.rb +131 -0
- data/lib/tty/prompt/list.rb +209 -0
- data/lib/tty/prompt/mode/echo.rb +10 -9
- data/lib/tty/prompt/mode/raw.rb +10 -9
- data/lib/tty/prompt/multi_list.rb +105 -0
- data/lib/tty/prompt/question/validation.rb +12 -27
- data/lib/tty/prompt/question.rb +58 -107
- data/lib/tty/prompt/reader.rb +44 -11
- data/lib/tty/prompt/response.rb +31 -36
- data/lib/tty/prompt/response_delegation.rb +3 -2
- data/lib/tty/prompt/statement.rb +10 -10
- data/lib/tty/prompt/test.rb +15 -0
- data/lib/tty/prompt/version.rb +3 -3
- data/lib/tty/prompt.rb +72 -9
- data/lib/tty-prompt.rb +11 -0
- data/spec/unit/ask_spec.rb +32 -35
- data/spec/unit/choice/eql_spec.rb +24 -0
- data/spec/unit/choice/from_spec.rb +25 -0
- data/spec/unit/choices/add_spec.rb +14 -0
- data/spec/unit/choices/each_spec.rb +15 -0
- data/spec/unit/choices/new_spec.rb +12 -0
- data/spec/unit/choices/pluck_spec.rb +11 -0
- data/spec/unit/cursor/new_spec.rb +74 -0
- data/spec/unit/error_spec.rb +4 -8
- data/spec/unit/multi_select_spec.rb +163 -0
- data/spec/unit/question/character_spec.rb +5 -16
- data/spec/unit/question/default_spec.rb +4 -10
- data/spec/unit/question/in_spec.rb +15 -12
- data/spec/unit/question/initialize_spec.rb +1 -6
- data/spec/unit/question/modify_spec.rb +25 -24
- data/spec/unit/question/required_spec.rb +31 -0
- data/spec/unit/question/validate_spec.rb +25 -17
- data/spec/unit/question/validation/call_spec.rb +22 -0
- data/spec/unit/response/read_bool_spec.rb +38 -27
- data/spec/unit/response/read_char_spec.rb +5 -8
- data/spec/unit/response/read_date_spec.rb +8 -12
- data/spec/unit/response/read_email_spec.rb +25 -22
- data/spec/unit/response/read_multiple_spec.rb +11 -13
- data/spec/unit/response/read_number_spec.rb +12 -16
- data/spec/unit/response/read_range_spec.rb +10 -13
- data/spec/unit/response/read_spec.rb +39 -38
- data/spec/unit/response/read_string_spec.rb +7 -12
- data/spec/unit/say_spec.rb +10 -14
- data/spec/unit/select_spec.rb +192 -0
- data/spec/unit/statement/initialize_spec.rb +0 -4
- data/spec/unit/suggest_spec.rb +6 -9
- data/spec/unit/warn_spec.rb +4 -8
- metadata +32 -8
- data/spec/unit/question/argument_spec.rb +0 -30
- data/spec/unit/question/valid_spec.rb +0 -46
- data/spec/unit/question/validation/valid_value_spec.rb +0 -22
    
        data/lib/tty/prompt.rb
    CHANGED
    
    | @@ -20,12 +20,12 @@ module TTY | |
| 20 20 | 
             
                # @api private
         | 
| 21 21 | 
             
                attr_reader :output
         | 
| 22 22 |  | 
| 23 | 
            -
                #  | 
| 23 | 
            +
                # Prompt prefix
         | 
| 24 24 | 
             
                #
         | 
| 25 25 | 
             
                # @api private
         | 
| 26 26 | 
             
                attr_reader :prefix
         | 
| 27 27 |  | 
| 28 | 
            -
                # Initialize a  | 
| 28 | 
            +
                # Initialize a Prompt
         | 
| 29 29 | 
             
                #
         | 
| 30 30 | 
             
                # @api public
         | 
| 31 31 | 
             
                def initialize(input = stdin, output = stdout, options = {})
         | 
| @@ -37,7 +37,7 @@ module TTY | |
| 37 37 | 
             
                # Ask a question.
         | 
| 38 38 | 
             
                #
         | 
| 39 39 | 
             
                # @example
         | 
| 40 | 
            -
                #   shell = TTY:: | 
| 40 | 
            +
                #   shell = TTY::Prompt.new
         | 
| 41 41 | 
             
                #   shell.ask("What is your name?")
         | 
| 42 42 | 
             
                #
         | 
| 43 43 | 
             
                # @param [String] statement
         | 
| @@ -51,22 +51,85 @@ module TTY | |
| 51 51 | 
             
                # @return [TTY::Question]
         | 
| 52 52 | 
             
                #
         | 
| 53 53 | 
             
                # @api public
         | 
| 54 | 
            -
                def ask( | 
| 54 | 
            +
                def ask(message, *args, &block)
         | 
| 55 55 | 
             
                  options = Utils.extract_options!(args)
         | 
| 56 56 |  | 
| 57 | 
            -
                  question = Question.new | 
| 58 | 
            -
                  question. | 
| 59 | 
            -
             | 
| 57 | 
            +
                  question = Question.new(self, options)
         | 
| 58 | 
            +
                  question.call(message, &block)
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                # Ask a question with a list of options
         | 
| 62 | 
            +
                #
         | 
| 63 | 
            +
                # @example
         | 
| 64 | 
            +
                #   prompt = TTY::Prompt.new
         | 
| 65 | 
            +
                #   prompt.select("What size?", %w(large medium small))
         | 
| 66 | 
            +
                #
         | 
| 67 | 
            +
                # @example
         | 
| 68 | 
            +
                #   prompt = TTY::Prompt.new
         | 
| 69 | 
            +
                #   prompt.select("What size?") do |menu|
         | 
| 70 | 
            +
                #     menu.choice :large
         | 
| 71 | 
            +
                #     menu.choices %w(:medium :small)
         | 
| 72 | 
            +
                #   end
         | 
| 73 | 
            +
                #
         | 
| 74 | 
            +
                # @param [String] question
         | 
| 75 | 
            +
                #   the question to ask
         | 
| 76 | 
            +
                #
         | 
| 77 | 
            +
                # @param [Array[Object]] choices
         | 
| 78 | 
            +
                #   the choices to select from
         | 
| 79 | 
            +
                #
         | 
| 80 | 
            +
                # @api public
         | 
| 81 | 
            +
                def select(question, *args, &block)
         | 
| 82 | 
            +
                  options = Utils.extract_options!(args)
         | 
| 83 | 
            +
                  choices = if block
         | 
| 84 | 
            +
                              []
         | 
| 85 | 
            +
                            elsif args.empty?
         | 
| 86 | 
            +
                              options
         | 
| 87 | 
            +
                            else
         | 
| 88 | 
            +
                              args.flatten
         | 
| 89 | 
            +
                            end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  list = List.new(self, options)
         | 
| 92 | 
            +
                  list.call(question, choices, &block)
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                # Ask a question with multiple attributes activated
         | 
| 96 | 
            +
                #
         | 
| 97 | 
            +
                # @example
         | 
| 98 | 
            +
                #   prompt = TTY::Prompt.new
         | 
| 99 | 
            +
                #   choices = %w(Scorpion Jax Kitana Baraka Jade)
         | 
| 100 | 
            +
                #   prompt.multi_select("Choose your destiny?", choices)
         | 
| 101 | 
            +
                #
         | 
| 102 | 
            +
                # @param [String] question
         | 
| 103 | 
            +
                #   the question to ask
         | 
| 104 | 
            +
                #
         | 
| 105 | 
            +
                # @param [Array[Object]] choices
         | 
| 106 | 
            +
                #   the choices to select from
         | 
| 107 | 
            +
                #
         | 
| 108 | 
            +
                # @return [String]
         | 
| 109 | 
            +
                #
         | 
| 110 | 
            +
                # @api public
         | 
| 111 | 
            +
                def multi_select(question, *args, &block)
         | 
| 112 | 
            +
                  options = Utils.extract_options!(args)
         | 
| 113 | 
            +
                  choices = if block
         | 
| 114 | 
            +
                              []
         | 
| 115 | 
            +
                            elsif args.empty?
         | 
| 116 | 
            +
                              options
         | 
| 117 | 
            +
                            else
         | 
| 118 | 
            +
                              args.flatten
         | 
| 119 | 
            +
                            end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  list = MultiList.new(self, options)
         | 
| 122 | 
            +
                  list.call(question, choices, &block)
         | 
| 60 123 | 
             
                end
         | 
| 61 124 |  | 
| 62 125 | 
             
                # A shortcut method to ask the user positive question and return
         | 
| 63 | 
            -
                # true for 'yes' reply.
         | 
| 126 | 
            +
                # true for 'yes' reply, false for 'no'.
         | 
| 64 127 | 
             
                #
         | 
| 65 128 | 
             
                # @return [Boolean]
         | 
| 66 129 | 
             
                #
         | 
| 67 130 | 
             
                # @api public
         | 
| 68 131 | 
             
                def yes?(statement, *args, &block)
         | 
| 69 | 
            -
                  ask(statement,  | 
| 132 | 
            +
                  ask(statement, {read: :bool}, &block)
         | 
| 70 133 | 
             
                end
         | 
| 71 134 |  | 
| 72 135 | 
             
                # A shortcut method to ask the user negative question and return
         | 
    
        data/lib/tty-prompt.rb
    CHANGED
    
    | @@ -5,11 +5,22 @@ require 'pastel' | |
| 5 5 | 
             
            require 'tty-platform'
         | 
| 6 6 |  | 
| 7 7 | 
             
            require 'tty/prompt'
         | 
| 8 | 
            +
            require 'tty/prompt/choice'
         | 
| 9 | 
            +
            require 'tty/prompt/choices'
         | 
| 10 | 
            +
            require 'tty/prompt/codes'
         | 
| 11 | 
            +
            require 'tty/prompt/cursor'
         | 
| 12 | 
            +
            require 'tty/prompt/list'
         | 
| 13 | 
            +
            require 'tty/prompt/multi_list'
         | 
| 8 14 | 
             
            require 'tty/prompt/mode'
         | 
| 9 15 | 
             
            require 'tty/prompt/question'
         | 
| 10 16 | 
             
            require 'tty/prompt/reader'
         | 
| 11 17 | 
             
            require 'tty/prompt/response'
         | 
| 12 18 | 
             
            require 'tty/prompt/statement'
         | 
| 13 19 | 
             
            require 'tty/prompt/suggestion'
         | 
| 20 | 
            +
            require 'tty/prompt/test'
         | 
| 14 21 | 
             
            require 'tty/prompt/utils'
         | 
| 15 22 | 
             
            require 'tty/prompt/version'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            module TTY
         | 
| 25 | 
            +
              PromptConfigurationError = Class.new(StandardError)
         | 
| 26 | 
            +
            end
         | 
    
        data/spec/unit/ask_spec.rb
    CHANGED
    
    | @@ -3,74 +3,71 @@ | |
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 4 |  | 
| 5 5 | 
             
            RSpec.describe TTY::Prompt, '#ask' do
         | 
| 6 | 
            -
              let(:input)  { StringIO.new }
         | 
| 7 | 
            -
              let(:output) { StringIO.new }
         | 
| 8 | 
            -
              let(:prefix) { '' }
         | 
| 9 | 
            -
              let(:options) { { prefix: prefix } }
         | 
| 10 6 |  | 
| 11 | 
            -
              subject(:prompt) { TTY:: | 
| 7 | 
            +
              subject(:prompt) { TTY::TestPrompt.new }
         | 
| 12 8 |  | 
| 13 9 | 
             
              it 'prints message' do
         | 
| 14 | 
            -
                prompt.ask | 
| 15 | 
            -
                expect(output.string).to eql | 
| 10 | 
            +
                prompt.ask("What is your name?")
         | 
| 11 | 
            +
                expect(prompt.output.string).to eql("What is your name?")
         | 
| 16 12 | 
             
              end
         | 
| 17 13 |  | 
| 18 14 | 
             
              it 'prints an empty message ' do
         | 
| 19 | 
            -
                prompt.ask | 
| 20 | 
            -
                expect(output.string).to eql | 
| 15 | 
            +
                prompt.ask('')
         | 
| 16 | 
            +
                expect(prompt.output.string).to eql('')
         | 
| 21 17 | 
             
              end
         | 
| 22 18 |  | 
| 23 19 | 
             
              it 'prints an empty message and returns nil if EOF is sent to stdin' do
         | 
| 24 | 
            -
                input << nil
         | 
| 25 | 
            -
                input.rewind
         | 
| 26 | 
            -
                 | 
| 27 | 
            -
                expect( | 
| 20 | 
            +
                prompt.input << nil
         | 
| 21 | 
            +
                prompt.input.rewind
         | 
| 22 | 
            +
                response = prompt.ask("")
         | 
| 23 | 
            +
                expect(response).to eql(nil)
         | 
| 24 | 
            +
                expect(prompt.output.string).to eq('')
         | 
| 28 25 | 
             
              end
         | 
| 29 26 |  | 
| 30 | 
            -
               | 
| 31 | 
            -
                 | 
| 32 | 
            -
             | 
| 33 | 
            -
                 | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
                  expect(output.string).to eql " > Are you Polish?\n"
         | 
| 38 | 
            -
                end
         | 
| 27 | 
            +
              it "asks a question with a prefix '>'" do
         | 
| 28 | 
            +
                prompt = TTY::TestPrompt.new(prefix: ' > ')
         | 
| 29 | 
            +
                prompt.input << ''
         | 
| 30 | 
            +
                prompt.input.rewind
         | 
| 31 | 
            +
                response = prompt.ask "Are you Polish?"
         | 
| 32 | 
            +
                expect(response).to eq(nil)
         | 
| 33 | 
            +
                expect(prompt.output.string).to eql " > Are you Polish?"
         | 
| 39 34 | 
             
              end
         | 
| 40 35 |  | 
| 41 36 | 
             
              it 'asks a question with block' do
         | 
| 42 | 
            -
                input << ''
         | 
| 43 | 
            -
                input.rewind
         | 
| 44 | 
            -
                 | 
| 45 | 
            -
                  default 'Piotr'
         | 
| 37 | 
            +
                prompt.input << ''
         | 
| 38 | 
            +
                prompt.input.rewind
         | 
| 39 | 
            +
                value = prompt.ask "What is your name?" do |q|
         | 
| 40 | 
            +
                  q.default 'Piotr'
         | 
| 46 41 | 
             
                end
         | 
| 47 | 
            -
                expect( | 
| 42 | 
            +
                expect(value).to eql "Piotr"
         | 
| 43 | 
            +
                expect(prompt.output.string).to eq('What is your name?')
         | 
| 48 44 | 
             
              end
         | 
| 49 45 |  | 
| 50 46 | 
             
              context 'yes?' do
         | 
| 51 47 | 
             
                it 'agrees' do
         | 
| 52 | 
            -
                  input << 'yes'
         | 
| 53 | 
            -
                  input.rewind
         | 
| 48 | 
            +
                  prompt.input << 'yes'
         | 
| 49 | 
            +
                  prompt.input.rewind
         | 
| 54 50 | 
             
                  expect(prompt.yes?("Are you a human?")).to eq(true)
         | 
| 51 | 
            +
                  expect(prompt.output.string).to eq('Are you a human?')
         | 
| 55 52 | 
             
                end
         | 
| 56 53 |  | 
| 57 54 | 
             
                it 'disagrees' do
         | 
| 58 | 
            -
                  input << 'no'
         | 
| 59 | 
            -
                  input.rewind
         | 
| 55 | 
            +
                  prompt.input << 'no'
         | 
| 56 | 
            +
                  prompt.input.rewind
         | 
| 60 57 | 
             
                  expect(prompt.yes?("Are you a human?")).to eq(false)
         | 
| 61 58 | 
             
                end
         | 
| 62 59 | 
             
              end
         | 
| 63 60 |  | 
| 64 61 | 
             
              context 'no?' do
         | 
| 65 62 | 
             
                it 'agrees' do
         | 
| 66 | 
            -
                  input << 'no'
         | 
| 67 | 
            -
                  input.rewind
         | 
| 63 | 
            +
                  prompt.input << 'no'
         | 
| 64 | 
            +
                  prompt.input.rewind
         | 
| 68 65 | 
             
                  expect(prompt.no?("Are you a human?")).to eq(true)
         | 
| 69 66 | 
             
                end
         | 
| 70 67 |  | 
| 71 68 | 
             
                it 'disagrees' do
         | 
| 72 | 
            -
                  input << 'yes'
         | 
| 73 | 
            -
                  input.rewind
         | 
| 69 | 
            +
                  prompt.input << 'yes'
         | 
| 70 | 
            +
                  prompt.input.rewind
         | 
| 74 71 | 
             
                  expect(prompt.no?("Are you a human?")).to eq(false)
         | 
| 75 72 | 
             
                end
         | 
| 76 73 | 
             
              end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt::Choice, '#==' do
         | 
| 6 | 
            +
              it "is true with the same name and value attributes" do
         | 
| 7 | 
            +
                expect(described_class.new(:large, 1)).
         | 
| 8 | 
            +
                  to eq(described_class.new(:large, 1))
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              it "is false with different name attribute" do
         | 
| 12 | 
            +
                expect(described_class.new(:large, 1)).
         | 
| 13 | 
            +
                  not_to eq(described_class.new(:medium, 1))
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              it "is false with different value attribute" do
         | 
| 17 | 
            +
                expect(described_class.new(:large, 1)).
         | 
| 18 | 
            +
                  not_to eq(described_class.new(:large, 2))
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              it "is false with non-choice object" do
         | 
| 22 | 
            +
                expect(described_class.new(:large, 1)).not_to eq(:other)
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt::Choice, '#from' do
         | 
| 6 | 
            +
              it "creates choice from choice" do
         | 
| 7 | 
            +
                choice = described_class.new(:large, 1)
         | 
| 8 | 
            +
                expect(described_class.from(choice)).to eq(choice)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              it "creates choice from string" do
         | 
| 12 | 
            +
                choice = described_class.new('large', 'large')
         | 
| 13 | 
            +
                expect(described_class.from('large')).to eq(choice)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              it "creates choice from array" do
         | 
| 17 | 
            +
                choice = described_class.new('large', 1)
         | 
| 18 | 
            +
                expect(described_class.from([:large, 1])).to eq(choice)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              it "creates choice from hash value" do
         | 
| 22 | 
            +
                choice = described_class.new('large', 1)
         | 
| 23 | 
            +
                expect(described_class.from({large: 1})).to eq(choice)
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt::Choices, '#<<' do
         | 
| 6 | 
            +
              it "adds choice to collection" do
         | 
| 7 | 
            +
                choices = described_class.new
         | 
| 8 | 
            +
                expect(choices).to be_empty
         | 
| 9 | 
            +
                choice = TTY::Prompt::Choice.from([:label, 1])
         | 
| 10 | 
            +
                choices << [:label, 1]
         | 
| 11 | 
            +
                expect(choices.size).to eq(1)
         | 
| 12 | 
            +
                expect(choices.to_ary).to eq([choice])
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt::Choices, '.each' do
         | 
| 6 | 
            +
              it "iterates over collection" do
         | 
| 7 | 
            +
                choices = described_class[:large, :medium, :small]
         | 
| 8 | 
            +
                actual = []
         | 
| 9 | 
            +
                choices.each do |choice|
         | 
| 10 | 
            +
                  actual << choice.name
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                expect(actual).to eq([:large, :medium, :small])
         | 
| 13 | 
            +
                expect(choices.each).to be_kind_of(Enumerator)
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt::Choices, '.new' do
         | 
| 6 | 
            +
              it "creates choices collection" do
         | 
| 7 | 
            +
                choice_1 = TTY::Prompt::Choice.from(:label1)
         | 
| 8 | 
            +
                choice_2 = TTY::Prompt::Choice.from(:label2)
         | 
| 9 | 
            +
                collection = described_class[:label1, :label2]
         | 
| 10 | 
            +
                expect(collection.choices).to eq([choice_1, choice_2])
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt::Choices, '.pluck' do
         | 
| 6 | 
            +
              it "plucks choice from collection by name" do
         | 
| 7 | 
            +
                collection = %w(large medium small)
         | 
| 8 | 
            +
                choices = described_class[*collection]
         | 
| 9 | 
            +
                expect(choices.pluck('medium').name).to eq('medium')
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt::Cursor do
         | 
| 6 | 
            +
              it "allows to print without mutating state" do
         | 
| 7 | 
            +
                cursor = described_class.new
         | 
| 8 | 
            +
                expect(cursor.shell).to eq(false)
         | 
| 9 | 
            +
                expect(cursor.print.shell).to eq(true)
         | 
| 10 | 
            +
                expect(cursor.shell).to eq(false)
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              it "shows cursor" do
         | 
| 14 | 
            +
                cursor = described_class.new
         | 
| 15 | 
            +
                expect(cursor.show).to eq("\e[?25h")
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              it "hides cursor" do
         | 
| 19 | 
            +
                cursor = described_class.new
         | 
| 20 | 
            +
                expect(cursor.hide).to eq("\e[?25l")
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              it "saves cursor position" do
         | 
| 24 | 
            +
                cursor = described_class.new
         | 
| 25 | 
            +
                expect(cursor.save).to eq("\e[s")
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              it "restores cursor position" do
         | 
| 29 | 
            +
                cursor = described_class.new
         | 
| 30 | 
            +
                expect(cursor.restore).to eq("\e[u")
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              it "moves up default by 1 line" do
         | 
| 34 | 
            +
                cursor = described_class.new
         | 
| 35 | 
            +
                expect(cursor.move_up).to eq("\e[1A")
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              it "moves up by 5 lines" do
         | 
| 39 | 
            +
                cursor = described_class.new
         | 
| 40 | 
            +
                expect(cursor.move_up(5)).to eq("\e[5A")
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              it "moves down default by 1 line" do
         | 
| 44 | 
            +
                cursor = described_class.new
         | 
| 45 | 
            +
                expect(cursor.move_down).to eq("\e[1B")
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              it "clears line" do
         | 
| 49 | 
            +
                cursor = described_class.new
         | 
| 50 | 
            +
                expect(cursor.clear_line).to eq("\e[1000D\e[K")
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              it "clears 5 lines up" do
         | 
| 54 | 
            +
                cursor = described_class.new
         | 
| 55 | 
            +
                expect(cursor.clear_lines(5)).to eq([
         | 
| 56 | 
            +
                  "\e[1A\e[1000D\e[K",
         | 
| 57 | 
            +
                  "\e[1A\e[1000D\e[K",
         | 
| 58 | 
            +
                  "\e[1A\e[1000D\e[K",
         | 
| 59 | 
            +
                  "\e[1A\e[1000D\e[K",
         | 
| 60 | 
            +
                  "\e[1A\e[1000D\e[K"
         | 
| 61 | 
            +
                ].join)
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              it "clears 5 lines down" do
         | 
| 65 | 
            +
                cursor = described_class.new
         | 
| 66 | 
            +
                expect(cursor.clear_lines(5, :down)).to eq([
         | 
| 67 | 
            +
                  "\e[1B\e[1000D\e[K",
         | 
| 68 | 
            +
                  "\e[1B\e[1000D\e[K",
         | 
| 69 | 
            +
                  "\e[1B\e[1000D\e[K",
         | 
| 70 | 
            +
                  "\e[1B\e[1000D\e[K",
         | 
| 71 | 
            +
                  "\e[1B\e[1000D\e[K"
         | 
| 72 | 
            +
                ].join)
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
    
        data/spec/unit/error_spec.rb
    CHANGED
    
    | @@ -3,28 +3,24 @@ | |
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 4 |  | 
| 5 5 | 
             
            RSpec.describe TTY::Prompt, '.error' do
         | 
| 6 | 
            -
              let(:input)  { StringIO.new }
         | 
| 7 | 
            -
              let(:output) { StringIO.new }
         | 
| 8 6 | 
             
              let(:color)  { Pastel.new(enabled: true) }
         | 
| 9 7 |  | 
| 10 | 
            -
              subject(:prompt) {  | 
| 8 | 
            +
              subject(:prompt) { TTY::TestPrompt.new }
         | 
| 11 9 |  | 
| 12 10 | 
             
              before { allow(Pastel).to receive(:new).and_return(color) }
         | 
| 13 11 |  | 
| 14 | 
            -
              after { output.rewind }
         | 
| 15 | 
            -
             | 
| 16 12 | 
             
              it 'displays one message' do
         | 
| 17 13 | 
             
                prompt.error "Nothing is fine!"
         | 
| 18 | 
            -
                expect(output.string).to eql "\e[31mNothing is fine!\e[0m\n"
         | 
| 14 | 
            +
                expect(prompt.output.string).to eql "\e[31mNothing is fine!\e[0m\n"
         | 
| 19 15 | 
             
              end
         | 
| 20 16 |  | 
| 21 17 | 
             
              it 'displays many messages' do
         | 
| 22 18 | 
             
                prompt.error "Nothing is fine!", "All is broken!"
         | 
| 23 | 
            -
                expect(output.string).to eql "\e[31mNothing is fine!\e[0m\n\e[31mAll is broken!\e[0m\n"
         | 
| 19 | 
            +
                expect(prompt.output.string).to eql "\e[31mNothing is fine!\e[0m\n\e[31mAll is broken!\e[0m\n"
         | 
| 24 20 | 
             
              end
         | 
| 25 21 |  | 
| 26 22 | 
             
              it 'displays message with option' do
         | 
| 27 23 | 
             
                prompt.error "Nothing is fine!", newline: false
         | 
| 28 | 
            -
                expect(output.string).to eql "\e[31mNothing is fine!\e[0m"
         | 
| 24 | 
            +
                expect(prompt.output.string).to eql "\e[31mNothing is fine!\e[0m"
         | 
| 29 25 | 
             
              end
         | 
| 30 26 | 
             
            end
         | 
| @@ -0,0 +1,163 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'spec_helper'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.describe TTY::Prompt do
         | 
| 6 | 
            +
              let(:color) { Pastel.new(enabled: true) }
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              before { allow(Pastel).to receive(:new).and_return(color) }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              it "selects nothing when return pressed immediately" do
         | 
| 11 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 12 | 
            +
                choices = %w(vodka beer wine whisky bourbon)
         | 
| 13 | 
            +
                prompt.input << "\r"
         | 
| 14 | 
            +
                prompt.input.rewind
         | 
| 15 | 
            +
                expect(prompt.multi_select("Select drinks?", choices)). to eq([])
         | 
| 16 | 
            +
                expect(prompt.output.string).to eq([
         | 
| 17 | 
            +
                  "\e[?25lSelect drinks? \e[90m(Use arrow keys, press Space to select and Enter to finish)\e[0m\n",
         | 
| 18 | 
            +
                  "‣ ⬡ vodka\n",
         | 
| 19 | 
            +
                  "  ⬡ beer\n",
         | 
| 20 | 
            +
                  "  ⬡ wine\n",
         | 
| 21 | 
            +
                  "  ⬡ whisky\n",
         | 
| 22 | 
            +
                  "  ⬡ bourbon\n",
         | 
| 23 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 24 | 
            +
                  "Select drinks? \n\e[?25h"
         | 
| 25 | 
            +
                ].join)
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              it "selects item when space pressed" do
         | 
| 29 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 30 | 
            +
                choices = %w(vodka beer wine whisky bourbon)
         | 
| 31 | 
            +
                prompt.input << " \r"
         | 
| 32 | 
            +
                prompt.input.rewind
         | 
| 33 | 
            +
                expect(prompt.multi_select("Select drinks?", choices)). to eq(['vodka'])
         | 
| 34 | 
            +
                expect(prompt.output.string).to eq([
         | 
| 35 | 
            +
                  "\e[?25lSelect drinks? \e[90m(Use arrow keys, press Space to select and Enter to finish)\e[0m\n",
         | 
| 36 | 
            +
                  "‣ ⬡ vodka\n",
         | 
| 37 | 
            +
                  "  ⬡ beer\n",
         | 
| 38 | 
            +
                  "  ⬡ wine\n",
         | 
| 39 | 
            +
                  "  ⬡ whisky\n",
         | 
| 40 | 
            +
                  "  ⬡ bourbon\n",
         | 
| 41 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 42 | 
            +
                  "Select drinks? vodka\n",
         | 
| 43 | 
            +
                  "‣ \e[32m⬢\e[0m vodka\n",
         | 
| 44 | 
            +
                  "  ⬡ beer\n",
         | 
| 45 | 
            +
                  "  ⬡ wine\n",
         | 
| 46 | 
            +
                  "  ⬡ whisky\n",
         | 
| 47 | 
            +
                  "  ⬡ bourbon\n",
         | 
| 48 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 49 | 
            +
                  "Select drinks? \e[32mvodka\e[0m\n\e[?25h"
         | 
| 50 | 
            +
                ].join)
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              it "sets choice custom values" do
         | 
| 54 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 55 | 
            +
                choices = {vodka: 1, beer: 2, wine: 3, whisky: 4, bourbon: 5}
         | 
| 56 | 
            +
                prompt.input << " \r"
         | 
| 57 | 
            +
                prompt.input.rewind
         | 
| 58 | 
            +
                expect(prompt.multi_select("Select drinks?", choices)).to eq([1])
         | 
| 59 | 
            +
                expect(prompt.output.string).to eq([
         | 
| 60 | 
            +
                  "\e[?25lSelect drinks? \e[90m(Use arrow keys, press Space to select and Enter to finish)\e[0m\n",
         | 
| 61 | 
            +
                  "‣ ⬡ vodka\n",
         | 
| 62 | 
            +
                  "  ⬡ beer\n",
         | 
| 63 | 
            +
                  "  ⬡ wine\n",
         | 
| 64 | 
            +
                  "  ⬡ whisky\n",
         | 
| 65 | 
            +
                  "  ⬡ bourbon\n",
         | 
| 66 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 67 | 
            +
                  "Select drinks? vodka\n",
         | 
| 68 | 
            +
                  "‣ \e[32m⬢\e[0m vodka\n",
         | 
| 69 | 
            +
                  "  ⬡ beer\n",
         | 
| 70 | 
            +
                  "  ⬡ wine\n",
         | 
| 71 | 
            +
                  "  ⬡ whisky\n",
         | 
| 72 | 
            +
                  "  ⬡ bourbon\n",
         | 
| 73 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 74 | 
            +
                  "Select drinks? \e[32mvodka\e[0m\n\e[?25h"
         | 
| 75 | 
            +
                ].join)
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              it "sets choice name and value through DSL" do
         | 
| 79 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 80 | 
            +
                prompt.input << " \r"
         | 
| 81 | 
            +
                prompt.input.rewind
         | 
| 82 | 
            +
                value = prompt.multi_select("Select drinks?") do |menu|
         | 
| 83 | 
            +
                          menu.choice :vodka, {score: 1}
         | 
| 84 | 
            +
                          menu.choice :beer, 2
         | 
| 85 | 
            +
                          menu.choice :wine, 3
         | 
| 86 | 
            +
                          menu.choices whisky: 4, bourbon: 5
         | 
| 87 | 
            +
                        end
         | 
| 88 | 
            +
                expect(value).to eq([{score: 1}])
         | 
| 89 | 
            +
                expect(prompt.output.string).to eq([
         | 
| 90 | 
            +
                  "\e[?25lSelect drinks? \e[90m(Use arrow keys, press Space to select and Enter to finish)\e[0m\n",
         | 
| 91 | 
            +
                  "‣ ⬡ vodka\n",
         | 
| 92 | 
            +
                  "  ⬡ beer\n",
         | 
| 93 | 
            +
                  "  ⬡ wine\n",
         | 
| 94 | 
            +
                  "  ⬡ whisky\n",
         | 
| 95 | 
            +
                  "  ⬡ bourbon\n",
         | 
| 96 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 97 | 
            +
                  "Select drinks? vodka\n",
         | 
| 98 | 
            +
                  "‣ \e[32m⬢\e[0m vodka\n",
         | 
| 99 | 
            +
                  "  ⬡ beer\n",
         | 
| 100 | 
            +
                  "  ⬡ wine\n",
         | 
| 101 | 
            +
                  "  ⬡ whisky\n",
         | 
| 102 | 
            +
                  "  ⬡ bourbon\n",
         | 
| 103 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 104 | 
            +
                  "Select drinks? \e[32mvodka\e[0m\n\e[?25h"
         | 
| 105 | 
            +
                ].join)
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              it "sets default options through DSL syntax" do
         | 
| 109 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 110 | 
            +
                prompt.input << "\r"
         | 
| 111 | 
            +
                prompt.input.rewind
         | 
| 112 | 
            +
                value = prompt.multi_select("Select drinks?") do |menu|
         | 
| 113 | 
            +
                          menu.default 2, 5
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                          menu.choice :vodka,   {score: 10}
         | 
| 116 | 
            +
                          menu.choice :beer,    {score: 20}
         | 
| 117 | 
            +
                          menu.choice :wine,    {score: 30}
         | 
| 118 | 
            +
                          menu.choice :whisky,  {score: 40}
         | 
| 119 | 
            +
                          menu.choice :bourbon, {score: 50}
         | 
| 120 | 
            +
                        end
         | 
| 121 | 
            +
                expect(value).to match_array([{score: 20}, {score: 50}])
         | 
| 122 | 
            +
                expect(prompt.output.string).to eq([
         | 
| 123 | 
            +
                  "\e[?25lSelect drinks? beer, bourbon\n",
         | 
| 124 | 
            +
                  "  ⬡ vodka\n",
         | 
| 125 | 
            +
                  "  \e[32m⬢\e[0m beer\n",
         | 
| 126 | 
            +
                  "  ⬡ wine\n",
         | 
| 127 | 
            +
                  "  ⬡ whisky\n",
         | 
| 128 | 
            +
                  "‣ \e[32m⬢\e[0m bourbon\n",
         | 
| 129 | 
            +
                  "\e[1A\e[1000D\e[K" * 6,
         | 
| 130 | 
            +
                  "Select drinks? \e[32mbeer, bourbon\e[0m\n\e[?25h",
         | 
| 131 | 
            +
                ].join)
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
              it "sets default options through hash syntax" do
         | 
| 135 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 136 | 
            +
                prompt.input << "\r"
         | 
| 137 | 
            +
                prompt.input.rewind
         | 
| 138 | 
            +
                value = prompt.multi_select("Select drinks?",default: [2, 5]) do |menu|
         | 
| 139 | 
            +
                          menu.choice :vodka,   {score: 10}
         | 
| 140 | 
            +
                          menu.choice :beer,    {score: 20}
         | 
| 141 | 
            +
                          menu.choice :wine,    {score: 30}
         | 
| 142 | 
            +
                          menu.choice :whisky,  {score: 40}
         | 
| 143 | 
            +
                          menu.choice :bourbon, {score: 50}
         | 
| 144 | 
            +
                        end
         | 
| 145 | 
            +
                expect(value).to match_array([{score: 20}, {score: 50}])
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
              it "raises error for defaults out of range" do
         | 
| 149 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 150 | 
            +
                prompt.input << "\r"
         | 
| 151 | 
            +
                prompt.input.rewind
         | 
| 152 | 
            +
                expect {
         | 
| 153 | 
            +
                  prompt.multi_select("Select drinks?",default: [2, 6]) do |menu|
         | 
| 154 | 
            +
                    menu.choice :vodka,   {score: 10}
         | 
| 155 | 
            +
                    menu.choice :beer,    {score: 20}
         | 
| 156 | 
            +
                    menu.choice :wine,    {score: 30}
         | 
| 157 | 
            +
                    menu.choice :whisky,  {score: 40}
         | 
| 158 | 
            +
                    menu.choice :bourbon, {score: 50}
         | 
| 159 | 
            +
                  end
         | 
| 160 | 
            +
                }.to raise_error(TTY::PromptConfigurationError,
         | 
| 161 | 
            +
                                 /default index `6` out of range \(1 - 5\)/)
         | 
| 162 | 
            +
              end
         | 
| 163 | 
            +
            end
         | 
| @@ -3,22 +3,11 @@ | |
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 4 |  | 
| 5 5 | 
             
            RSpec.describe TTY::Prompt::Question, '#character' do
         | 
| 6 | 
            -
              let(:input)  { StringIO.new }
         | 
| 7 | 
            -
              let(:output) { StringIO.new }
         | 
| 8 | 
            -
              let(:prompt) { TTY::Prompt.new(input, output) }
         | 
| 9 | 
            -
             | 
| 10 6 | 
             
              it 'switches to character input' do
         | 
| 11 | 
            -
                 | 
| 12 | 
            -
                input | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
                expect( | 
| 16 | 
            -
              end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
              it 'acts as reader without arguments' do
         | 
| 19 | 
            -
                input << "abcd"
         | 
| 20 | 
            -
                input.rewind
         | 
| 21 | 
            -
                q = prompt.ask("Which one do you prefer a, b, c or d?")
         | 
| 22 | 
            -
                expect(q.char).to eq(false)
         | 
| 7 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 8 | 
            +
                prompt.input << "abcd"
         | 
| 9 | 
            +
                prompt.input.rewind
         | 
| 10 | 
            +
                answer = prompt.ask("Which one do you prefer a, b, c or d?") { |q| q.char(true) }
         | 
| 11 | 
            +
                expect(answer).to eq("abcd")
         | 
| 23 12 | 
             
              end
         | 
| 24 13 | 
             
            end
         | 
| @@ -3,23 +3,17 @@ | |
| 3 3 | 
             
            require 'spec_helper'
         | 
| 4 4 |  | 
| 5 5 | 
             
            RSpec.describe TTY::Prompt::Question, '#default' do
         | 
| 6 | 
            -
              let(:input)  { StringIO.new }
         | 
| 7 | 
            -
              let(:output) { StringIO.new }
         | 
| 8 | 
            -
              let(:prompt) { TTY::Prompt.new(input, output) }
         | 
| 9 | 
            -
             | 
| 10 6 | 
             
              it 'uses default value' do
         | 
| 7 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 11 8 | 
             
                name = 'Anonymous'
         | 
| 12 | 
            -
                 | 
| 13 | 
            -
                answer = q.read
         | 
| 9 | 
            +
                answer = prompt.ask('What is your name?', default: name)
         | 
| 14 10 | 
             
                expect(answer).to eq(name)
         | 
| 15 11 | 
             
              end
         | 
| 16 12 |  | 
| 17 13 | 
             
              it 'uses default value in block' do
         | 
| 14 | 
            +
                prompt = TTY::TestPrompt.new
         | 
| 18 15 | 
             
                name = 'Anonymous'
         | 
| 19 | 
            -
                 | 
| 20 | 
            -
                  default name
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
                answer = q.read
         | 
| 16 | 
            +
                answer = prompt.ask('What is your name?') { |q| q.default(name) }
         | 
| 23 17 | 
             
                expect(answer).to eq(name)
         | 
| 24 18 | 
             
              end
         | 
| 25 19 | 
             
            end
         |