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
|
# frozen_string_literal: true
require_relative "distance"
module TTY
# A class responsible for terminal prompt interactions.
class Prompt
# A class representing a suggestion out of possible choices
#
# @api public
class Suggestion
DEFAULT_INDENT = 8
SINGLE_TEXT = "Did you mean this?"
PLURAL_TEXT = "Did you mean one of these?"
# Number of spaces
#
# @api public
attr_reader :indent
# Text for a single suggestion
#
# @api public
attr_reader :single_text
# Text for multiple suggestions
#
# @api public
attr_reader :plural_text
# Initialize a Suggestion
#
# @api public
def initialize(**options)
@indent = options.fetch(:indent) { DEFAULT_INDENT }
@single_text = options.fetch(:single_text) { SINGLE_TEXT }
@plural_text = options.fetch(:plural_text) { PLURAL_TEXT }
@suggestions = []
@comparator = Distance.new
end
# Suggest matches out of possibile strings
#
# @param [String] message
#
# @param [Array[String]] possibilities
#
# @api public
def suggest(message, possibilities)
distances = measure_distances(message, possibilities)
minimum_distance = distances.keys.min
max_distance = distances.keys.max
if minimum_distance < max_distance
@suggestions = distances[minimum_distance].sort
end
evaluate
end
private
# Measure distances between messag and possibilities
#
# @param [String] message
#
# @param [Array[String]] possibilities
#
# @return [Hash]
#
# @api private
def measure_distances(message, possibilities)
distances = Hash.new { |hash, key| hash[key] = [] }
possibilities.each do |possibility|
distances[@comparator.distance(message, possibility)] << possibility
end
distances
end
# Build up a suggestion string
#
# @param [Array[String]] suggestions
#
# @return [String]
#
# @api private
def evaluate
return @suggestions if @suggestions.empty?
if @suggestions.one?
build_single_suggestion
else
build_multiple_suggestions
end
end
# @api private
def build_single_suggestion
single_text + "\n" + (" " * indent) + @suggestions.first
end
# @api private
def build_multiple_suggestions
plural_text + "\n" +
@suggestions.map do |sugest|
" " * indent + sugest
end.join("\n")
end
end # Suggestion
end # Prompt
end # TTY
|