File: confirm_question.rb

package info (click to toggle)
ruby-tty-prompt 0.23.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 1,452 kB
  • sloc: ruby: 8,847; makefile: 4
file content (158 lines) | stat: -rw-r--r-- 3,951 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# frozen_string_literal: true

require_relative "question"
require_relative "utils"

module TTY
  class Prompt
    class ConfirmQuestion < Question
      # Create confirmation question
      #
      # @param [Hash] options
      # @option options [String] :suffix
      # @option options [String] :positive
      # @option options [String] :negative
      #
      # @api public
      def initialize(prompt, **options)
        super
        @suffix   = options.fetch(:suffix)   { UndefinedSetting }
        @positive = options.fetch(:positive) { UndefinedSetting }
        @negative = options.fetch(:negative) { UndefinedSetting }
      end

      def positive?
        @positive != UndefinedSetting
      end

      def negative?
        @negative != UndefinedSetting
      end

      def suffix?
        @suffix != UndefinedSetting
      end

      # Set question suffix
      #
      # @api public
      def suffix(value = (not_set = true))
        return @negative if not_set

        @suffix = value
      end

      # Set value for matching positive choice
      #
      # @api public
      def positive(value = (not_set = true))
        return @positive if not_set

        @positive = value
      end

      # Set value for matching negative choice
      #
      # @api public
      def negative(value = (not_set = true))
        return @negative if not_set

        @negative = value
      end

      def call(message, &block)
        return if Utils.blank?(message)

        @message = message
        block.call(self) if block
        setup_defaults
        render
      end

      # Render confirmation question
      #
      # @return [String]
      #
      # @api private
      def render_question
        header = "#{@prefix}#{message} "
        if !@done
          header += @prompt.decorate("(#{@suffix})", @help_color) + " "
        else
          answer = conversion.call(@input)
          label  = answer ? @positive : @negative
          header += @prompt.decorate(label, @active_color)
        end
        header << "\n" if @done
        header
      end

      protected

      # Decide how to handle input from user
      #
      # @api private
      def process_input(question)
        @input = read_input(question)
        if Utils.blank?(@input)
          @input = default ? positive : negative
        end
        @evaluator.call(@input)
      end

      # @api private
      def setup_defaults
        infer_default
        @convert = conversion
        return if suffix? && positive?

        if suffix? && (!positive? || !negative?)
          parts = @suffix.split("/")
          @positive = parts[0]
          @negative = parts[1]
        elsif !suffix? && positive?
          @suffix = create_suffix
        else
          create_default_labels
        end
      end

      # @api private
      def infer_default
        converted = Converters.convert(:bool, default.to_s)
        if converted == Const::Undefined
          raise InvalidArgument, "default needs to be `true` or `false`"
        else
          default(converted)
        end
      end

      # @api private
      def create_default_labels
        @suffix   = default ? "Y/n" : "y/N"
        @positive = default ? "Yes" : "yes"
        @negative = default ? "no" : "No"
        @validation = /^(y(es)?|no?)$/i
        @messages[:valid?] = "Invalid input."
      end

      # @api private
      def create_suffix
        (default ? positive.capitalize : positive.downcase) + "/" +
          (default ? negative.downcase : negative.capitalize)
      end

      # Create custom conversion
      #
      # @api private
      def conversion
        ->(input) do
          positive_word   = Regexp.escape(positive)
          positive_letter = Regexp.escape(positive[0])
          pattern = Regexp.new("^(#{positive_word}|#{positive_letter})$", true)
          !input.match(pattern).nil?
        end
      end
    end # ConfirmQuestion
  end # Prompt
end # TTY