summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbinoam P. Marques Jr <abinoam@gmail.com>2016-02-19 04:30:15 -0300
committerAbinoam P. Marques Jr <abinoam@gmail.com>2016-02-19 04:30:15 -0300
commita3166e918311f3caf24fba89b76179c62c3ccbd7 (patch)
tree6aa7de97ce479a2d4fb2b11b920b0b9013760f0a
parent446ceb184dbfffbd83bd25edb15bcee3e630b3e4 (diff)
parentd82032b2439241f7f05aa0294538d28cc4142b4d (diff)
downloadhighline-a3166e918311f3caf24fba89b76179c62c3ccbd7.tar.gz
Merge pull request #186 from JEG2/pr184_rebasedv2.0.0.pre.develop.6
Rebased PR #184 (original by @matrinox)
-rw-r--r--.gitignore1
-rw-r--r--Changelog.md7
-rwxr-xr-xlib/highline.rb13
-rw-r--r--lib/highline/menu.rb196
-rwxr-xr-xlib/highline/question.rb36
-rw-r--r--lib/highline/question_asker.rb17
-rw-r--r--lib/highline/version.rb2
-rw-r--r--test/test_menu.rb303
8 files changed, 444 insertions, 131 deletions
diff --git a/.gitignore b/.gitignore
index a49838e..b8c8e9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ doc
pkg
.DS_Store
coverage
+Gemfile.lock
diff --git a/Changelog.md b/Changelog.md
index fb95962..fe42734 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,13 @@
Below is a complete listing of changes for each revision of HighLine.
+### 2.0.0-develop.6 / 2016-02-01
+* PR #184 - Menu improvements, bug fixes, and more tests by Geoff Lee (@matrinox)
+ * Add third arg to menu that overides the choice displayed to the user
+ * FIX: autocomplete prompt does not include menu choices after the first
+ * Add specs to cover the new features and the bug fix
+* PR #183 - Fix menu example in README.md by Fabien Foerster (@fabienfoerster)
+
### 2.0.0-develop.5 / 2015-12-27
* Fix #180 with PR #181 - Make it possible to overwrite the menu prompt shown on errors.
diff --git a/lib/highline.rb b/lib/highline.rb
index ba409b6..775a4ac 100755
--- a/lib/highline.rb
+++ b/lib/highline.rb
@@ -251,11 +251,18 @@ class HighLine
menu.answer_type = menu.shell ? shell_style_lambda(menu) : menu.options
selected = ask(menu)
+ return unless selected
if menu.shell
- menu.select(self, *selected)
+ selection, details = selected
else
- menu.select(self, selected)
+ selection = selected
+ end
+
+ if menu.gather
+ menu.gather_selected(self, selection, details)
+ else
+ menu.select(self, selection, details)
end
end
@@ -485,7 +492,7 @@ class HighLine
# of the question.
#
def explain_error(error, question)
- say(question.responses[error]) if error
+ say(question.final_responses[error]) if error
say(question.ask_on_error_msg)
end
diff --git a/lib/highline/menu.rb b/lib/highline/menu.rb
index e0c18de..1560fde 100644
--- a/lib/highline/menu.rb
+++ b/lib/highline/menu.rb
@@ -154,21 +154,46 @@ class HighLine
# cli.choose do |menu|
# menu.shell = true
#
- # menu.choice(:load, "Load a file.")
- # menu.choice(:save, "Save data in file.")
- # menu.choice(:quit, "Exit program.")
+ # menu.choice(:load, text: 'Load a file', help: "Load a file using your favourite editor.")
+ # menu.choice(:save, help: "Save data in file.")
+ # menu.choice(:quit, help: "Exit program.")
#
# menu.help("rules", "The rules of this system are as follows...")
# end
- def choice( name, help = nil, &action )
- @items << [name, action]
-
- @help[name.to_s.downcase] = help if help
+ def choice( name, help = nil, text = nil, &action )
+ item = MenuItem.new(name, text: text, help: help, action: action)
+ @items << item
+ @help.merge!(item.item_help)
update_responses # rebuild responses based on our settings
end
#
+ # This method helps reduce the namespaces in the original call, which would look
+ # like this: HighLine::Menu::MenuItem.new(...)
+ # With #build_item, it looks like this: menu.build_item(...)
+ # @param *args splat args, the same args you would pass to an initialization of
+ # HighLine::Menu::MenuItem
+ # @return [HighLine::Menu::MenuItem] the menu item
+
+ def build_item(*args)
+ MenuItem.new(*args)
+ end
+
+ #
+ # Adds an item directly to the menu. If you want more configuraiton or options,
+ # use this method
+ #
+ # @param item [Menu::MenuItem] item containing choice fields and more
+ # @return [void]
+
+ def add_item(item)
+ @items << item
+ @help.merge!(item.item_help)
+ update_responses
+ end
+
+ #
# A shortcut for multiple calls to the sister method {#choice}. <b>Be
# warned:</b> An _action_ set here will apply to *all* provided
# _names_. This is considered to be a feature, so you can easily
@@ -177,6 +202,10 @@ class HighLine
# @param action (see #choice)
# @return [void]
# @example (see HighLine::Menu#initialize)
+ #
+ # choice has more options available to you, like longer text or help (and
+ # of course, individual actions)
+ #
def choices( *names, &action )
names.each { |n| choice(n, &action) }
end
@@ -189,9 +218,9 @@ class HighLine
# @return (see #choice)
def hidden( name, help = nil, &action )
- @hidden_items << [name, action]
-
- @help[name.to_s.downcase] = help if help
+ item = MenuItem.new(name, text: name, help: help, action: action)
+ @hidden_items << item
+ @help.merge!(item.item_help)
end
#
@@ -302,27 +331,29 @@ class HighLine
#
def options( )
# add in any hidden menu commands
- @items.concat(@hidden_items)
-
- by_index = if @index == :letter
- l_index = "`"
- @items.map { "#{l_index.succ!}" }
- else
- (1 .. @items.size).collect { |s| String(s) }
- end
- by_name = @items.collect { |c| c.first }
+ items = all_items
case @select_by
when :index then
- by_index
+ map_items_by_index(items, @index)
when :name
- by_name
+ items.map(&:name)
+ else
+ map_items_by_index(items, @index) + items.map(&:name)
+ end
+ end
+
+ def map_items_by_index(items, index = nil)
+ if index == :letter
+ l_index = "`"
+ items.map { "#{l_index.succ!}" }
else
- by_index + by_name
+ (1 .. items.size).map(&:to_s)
end
- ensure
- # make sure the hidden items are removed, before we return
- @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
+ end
+
+ def all_items
+ @items + @hidden_items
end
#
@@ -337,44 +368,83 @@ class HighLine
# else it returns the action return value.
def select( highline_context, selection, details = nil )
# add in any hidden menu commands
- @items.concat(@hidden_items)
+ items = all_items
# Find the selected action.
- name, action = if selection =~ /^\d+$/ # is a number?
- get_item_by_number(selection)
- else
- get_item_by_letter(selection)
- end
+ selected_item = find_item_from_selection(items, selection)
# Run or return it.
- if action
- @highline = highline_context
- if @shell
- result = action.call(name, details)
- else
- result = action.call(name)
- end
- @nil_on_handled ? nil : result
+ @highline = highline_context
+ value_for_selected_item(selected_item, details)
+ end
+
+ def find_item_from_selection(items, selection)
+ if selection =~ /^\d+$/ # is a number?
+ get_item_by_number(items, selection)
else
- name
+ get_item_by_letter(items, selection)
end
- ensure
- # make sure the hidden items are removed, before we return
- @items.slice!(@items.size - @hidden_items.size, @hidden_items.size)
end
# Returns the menu item referenced by its index
# @param selection [Integer] menu item's index.
- def get_item_by_number(selection)
- @items[selection.to_i - 1]
+ def get_item_by_number(items, selection)
+ items[selection.to_i - 1]
end
# Returns the menu item referenced by its title/header/name.
# @param selection [String] menu's title/header/name
- def get_item_by_letter(selection)
+ def get_item_by_letter(items, selection)
+ item = items.find { |i| i.name == selection }
+ return item if item
l_index = "`" # character before the letter "a"
- index = @items.map { "#{l_index.succ!}" }.index(selection)
- @items.find { |c| c.first == selection } or @items[index]
+ index = items.map { "#{l_index.succ!}" }.index(selection)
+ items[index]
+ end
+
+ def value_for_selected_item(item, details)
+ if item.action
+ if @shell
+ result = item.action.call(item.name, details)
+ else
+ result = item.action.call(item.name)
+ end
+ @nil_on_handled ? nil : result
+ else
+ item.name
+ end
+ end
+
+ def gather_selected(highline_context, selections, details = nil)
+ @highline = highline_context
+ # add in any hidden menu commands
+ items = all_items
+
+ if selections.is_a?(Array)
+ value_for_array_selections(items, selections, details)
+ elsif selections.is_a?(Hash)
+ value_for_hash_selections(items, selections, details)
+ else
+ fail ArgumentError, 'selections must be either Array or Hash'
+ end
+ end
+
+ def value_for_array_selections(items, selections, details)
+ # Find the selected items and return values
+ selected_items = selections.map do |selection|
+ find_item_from_selection(items, selection)
+ end
+ selected_items.map do |selected_item|
+ value_for_selected_item(selected_item, details)
+ end
+ end
+
+ def value_for_hash_selections(items, selections, details)
+ # Find the selected items and return in hash form
+ selections.each_with_object({}) do |(key, selection), memo|
+ selected_item = find_item_from_selection(items, selection)
+ memo[key] = value_for_selected_item(selected_item, details)
+ end
end
#
@@ -385,14 +455,14 @@ class HighLine
def to_ary( )
case @index
when :number
- @items.map { |c| "#{@items.index(c) + 1}#{@index_suffix}#{c.first}" }
+ @items.map { |i| "#{@items.index(i) + 1}#{@index_suffix}#{i.text}" }
when :letter
l_index = "`"
- @items.map { |c| "#{l_index.succ!}#{@index_suffix}#{c.first}" }
+ @items.map { |i| "#{l_index.succ!}#{@index_suffix}#{i.text}" }
when :none
- @items.map { |c| "#{c.first}" }
+ @items.map { |i| "#{i.text}" }
else
- @items.map { |c| "#{index}#{@index_suffix}#{c.first}" }
+ @items.map { |i| "#{index}#{@index_suffix}#{i.text}" }
end
end
@@ -430,5 +500,27 @@ class HighLine
def update_responses
build_responses(options)
end
+
+ class MenuItem
+ attr_reader :name, :text, :help, :action
+
+ #
+ # @param name [String] The name that is matched against the user input
+ # @param text: [String] The text that displays for that choice (defaults to name)
+ # @param help: [String] help, see above (not sure how it works)
+ # @param action: [Block] a block that gets called when choice is selected
+ #
+ def initialize(name, attributes)
+ @name = name
+ @text = attributes[:text] || @name
+ @help = attributes[:help]
+ @action = attributes[:action]
+ end
+
+ def item_help
+ return {} unless help
+ { name.to_s.downcase => help }
+ end
+ end
end
end
diff --git a/lib/highline/question.rb b/lib/highline/question.rb
index 769da39..3724c67 100755
--- a/lib/highline/question.rb
+++ b/lib/highline/question.rb
@@ -61,7 +61,8 @@ class HighLine
@first_answer = nil
@directory = Pathname.new(File.expand_path(File.dirname($0)))
@glob = "*"
- @responses = Hash.new
+ @user_responses = Hash.new
+ @internal_responses = default_responses_hash
@overwrite = false
# allow block to override settings
@@ -214,7 +215,9 @@ class HighLine
# <tt>:not_valid</tt>:: The error message shown when
# validation checks fail.
#
- attr_reader :responses
+ def responses
+ @user_responses
+ end
#
# When set to +true+ the question is asked, but output does not progress to
# the next line. The Cursor is moved back to the beginning of the question
@@ -242,16 +245,21 @@ class HighLine
# @return [Hash] responses Hash winner (new and old merge).
# @param message_source [Class] Array or String for example.
# Same as {#answer_type}.
- # @param new_hash_wins [Boolean] merge precedence (new vs. old).
- def build_responses(message_source = answer_type, new_hash_wins = false)
+ def build_responses(message_source = answer_type)
append_default if [::String, Symbol].include? default.class
- old_hash = responses
-
new_hash = build_responses_new_hash(message_source)
+ # Update our internal responses with the new hash
+ # generated from the message source
+ @internal_responses = @internal_responses.merge(new_hash)
+ end
- @responses = new_hash_wins ? old_hash.merge(new_hash) : new_hash.merge(old_hash)
+ def default_responses_hash
+ {
+ :ask_on_error => "? ",
+ :mismatch => "Your entries didn't match."
+ }
end
# When updating the responses hash, it generates the new one.
@@ -260,17 +268,21 @@ class HighLine
def build_responses_new_hash(message_source)
{ :ambiguous_completion => "Ambiguous choice. Please choose one of " +
choice_error_str(message_source) + '.',
- :ask_on_error => "? ",
:invalid_type => "You must enter a valid #{message_source}.",
:no_completion => "You must choose one of " +
choice_error_str(message_source) + '.',
:not_in_range => "Your answer isn't within the expected range " +
"(#{expected_range}).",
- :mismatch => "Your entries didn't match.",
:not_valid => "Your answer isn't valid (must match " +
"#{validate.inspect})." }
end
+ # This is the actual responses hash that gets used in determining output
+ # Notice that we give @user_responses precedence over the responses
+ # generated internally via build_response
+ def final_responses
+ @internal_responses.merge(@user_responses)
+ end
#
# Returns the provided _answer_string_ after changing character case by
@@ -531,10 +543,10 @@ class HighLine
# @return [self] if :ask_on_error on responses Hash is set to :question
# @return [String] if :ask_on_error on responses Hash is set to something else
def ask_on_error_msg
- if responses[:ask_on_error] == :question
+ if final_responses[:ask_on_error] == :question
self
- elsif responses[:ask_on_error]
- responses[:ask_on_error]
+ elsif final_responses[:ask_on_error]
+ final_responses[:ask_on_error]
end
end
diff --git a/lib/highline/question_asker.rb b/lib/highline/question_asker.rb
index b8c8ebc..06e6647 100644
--- a/lib/highline/question_asker.rb
+++ b/lib/highline/question_asker.rb
@@ -105,13 +105,11 @@ class HighLine
# with keys provided by the Hash on {Question#gather}
# @return [Hash]
def gather_hash
- answers = {}
-
- question.gather.keys.sort.each do |key|
+ sorted_keys = question.gather.keys.sort_by(&:to_s)
+ sorted_keys.each_with_object({}) do |key, answers|
@highline.key = key
answers[key] = ask_once
end
- answers
end
@@ -119,7 +117,7 @@ class HighLine
## Delegate to Highline
def explain_error(error)
- @highline.say(question.responses[error]) if error
+ @highline.say(question.final_responses[error]) if error
@highline.say(question.ask_on_error_msg)
end
@@ -133,15 +131,18 @@ class HighLine
end
def answer_matches_regex(answer)
- (question.gather.is_a?(::String) && answer.to_s == question.gather) ||
- (question.gather.is_a?(Regexp) && answer.to_s =~ question.gather)
+ if question.gather.is_a?(::String) || question.gather.is_a?(Symbol)
+ answer.to_s == question.gather.to_s
+ else question.gather.is_a?(Regexp)
+ answer.to_s =~ question.gather
+ end
end
def gather_answers_based_on_type
case question.gather
when Integer
gather_integer
- when ::String, Regexp
+ when ::String, Symbol, Regexp
gather_regexp
when Hash
gather_hash
diff --git a/lib/highline/version.rb b/lib/highline/version.rb
index 7977660..d4d5537 100644
--- a/lib/highline/version.rb
+++ b/lib/highline/version.rb
@@ -2,5 +2,5 @@
class HighLine
# The version of the installed library.
- VERSION = "2.0.0-develop.5".freeze
+ VERSION = "2.0.0-develop.6".freeze
end
diff --git a/test/test_menu.rb b/test/test_menu.rb
index 594f622..f870245 100644
--- a/test/test_menu.rb
+++ b/test/test_menu.rb
@@ -37,21 +37,21 @@ class TestMenu < Minitest::Test
@terminal.choose do |menu|
# Default: menu.flow = :rows
-
- menu.choice "Sample1"
- menu.choice "Sample2"
- menu.choice "Sample3"
+
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "Sample3"
end
assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n? ", @output.string)
@output.truncate(@output.rewind)
@input.rewind
-
+
@terminal.choose do |menu|
menu.flow = :columns_across
-
- menu.choice "Sample1"
- menu.choice "Sample2"
+
+ menu.choice "Sample1"
+ menu.choice "Sample2"
menu.choice "Sample3"
end
assert_equal("1. Sample1 2. Sample2 3. Sample3\n? ", @output.string)
@@ -63,13 +63,13 @@ class TestMenu < Minitest::Test
menu.flow = :inline
menu.index = :none
- menu.choice "Sample1"
- menu.choice "Sample2"
- menu.choice "Sample3"
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "Sample3"
end
assert_equal("Sample1, Sample2 or Sample3? ", @output.string)
end
-
+
def test_unicode_flow
@input << "1\n"
@input.rewind
@@ -81,6 +81,76 @@ class TestMenu < Minitest::Test
assert_equal("1. Unicode right single quotation mark: ’\n? ".encode(@output.external_encoding, { :undef => :replace }), @output.string)
end
+ def test_text_override_index_selects_name
+ @input << "1\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.choice("Sample1", nil, "Sample2")
+ menu.choice("Sample2", nil, "Sample1")
+ end
+ assert_equal(selected, "Sample1")
+ assert_equal("1. Sample2\n" +
+ "2. Sample1\n" +
+ "? ", @output.string)
+ end
+
+ def test_text_override_selections_matches_name
+ @input << "Sample2\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.choice("Sample1", nil, "Sample2")
+ menu.choice("Sample2", nil, "Sample1")
+ end
+ assert_equal(selected, "Sample2")
+ assert_equal("1. Sample2\n" +
+ "2. Sample1\n" +
+ "? ", @output.string)
+ end
+
+ def test_menu_add_item_index_selects_name
+ @input << "1\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample1", text: "Sample2"))
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample2", text: "Sample1"))
+ end
+ assert_equal(selected, "Sample1")
+ assert_equal("1. Sample2\n" +
+ "2. Sample1\n" +
+ "? ", @output.string)
+ end
+
+ def test_menu_add_item_selections_matches_name
+ @input << "Sample2\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample1", text: "Sample2"))
+ menu.add_item(HighLine::Menu::MenuItem.new("Sample2", text: "Sample1"))
+ end
+ assert_equal(selected, "Sample2")
+ assert_equal("1. Sample2\n" +
+ "2. Sample1\n" +
+ "? ", @output.string)
+ end
+
+ def test_menu_build_item
+ @input << "Sample2\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.add_item(menu.build_item("Sample1", text: "Sample2"))
+ menu.add_item(menu.build_item("Sample2", text: "Sample1"))
+ end
+ assert_equal(selected, "Sample2")
+ assert_equal("1. Sample2\n" +
+ "2. Sample1\n" +
+ "? ", @output.string)
+ end
+
def test_help
@input << "help\nhelp load\nhelp rules\nhelp missing\n"
@input.rewind
@@ -92,7 +162,7 @@ class TestMenu < Minitest::Test
menu.choice(:load, "Load a file.")
menu.choice(:save, "Save data in file.")
menu.choice(:quit, "Exit program.")
-
+
menu.help("rules", "The rules of this system are as follows...")
end
end
@@ -102,15 +172,15 @@ class TestMenu < Minitest::Test
"specific topic enter:\n" +
"\thelp [TOPIC]\n" +
"Try asking for help on any of the following:\n" +
- "\nload quit rules save \n" +
+ "\nload quit rules save \n" +
"1. load\n2. save\n3. quit\n4. help\n? " +
- "= load\n\n" +
+ "= load\n\n" +
"Load a file.\n" +
"1. load\n2. save\n3. quit\n4. help\n? " +
"= rules\n\n" +
"The rules of this system are as follows...\n" +
"1. load\n2. save\n3. quit\n4. help\n? " +
- "= missing\n\n" +
+ "= missing\n\n" +
"There's no help for that topic.\n", @output.string )
end
@@ -120,22 +190,22 @@ class TestMenu < Minitest::Test
@terminal.choose do |menu|
# Default: menu.index = :number
-
- menu.choice "Sample1"
- menu.choice "Sample2"
- menu.choice "Sample3"
+
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "Sample3"
end
assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n? ", @output.string)
@output.truncate(@output.rewind)
@input.rewind
-
+
@terminal.choose do |menu|
menu.index = :letter
menu.index_suffix = ") "
-
- menu.choice "Sample1"
- menu.choice "Sample2"
+
+ menu.choice "Sample1"
+ menu.choice "Sample2"
menu.choice "Sample3"
end
assert_equal("a) Sample1\nb) Sample2\nc) Sample3\n? ", @output.string)
@@ -146,15 +216,15 @@ class TestMenu < Minitest::Test
@terminal.choose do |menu|
menu.index = :none
- menu.choice "Sample1"
- menu.choice "Sample2"
- menu.choice "Sample3"
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "Sample3"
end
assert_equal("Sample1\nSample2\nSample3\n? ", @output.string)
@output.truncate(@output.rewind)
@input.rewind
-
+
@terminal.choose do |menu|
menu.index = "*"
@@ -164,11 +234,11 @@ class TestMenu < Minitest::Test
end
assert_equal("* Sample1\n* Sample2\n* Sample3\n? ", @output.string)
end
-
+
def test_layouts
@input << "save\n"
@input.rewind
-
+
@terminal.choose(:load, :save, :quit) # Default: layout = :list
assert_equal("1. load\n2. save\n3. quit\n? ", @output.string)
@@ -178,7 +248,7 @@ class TestMenu < Minitest::Test
@terminal.choose(:load, :save, :quit) do |menu|
menu.header = "File Menu"
end
- assert_equal( "File Menu:\n" +
+ assert_equal( "File Menu:\n" +
"1. load\n2. save\n3. quit\n? ", @output.string )
@input.rewind
@@ -189,7 +259,7 @@ class TestMenu < Minitest::Test
menu.header = "File Menu"
menu.prompt = "Operation? "
end
- assert_equal( "File Menu: Operation? " +
+ assert_equal( "File Menu: Operation? " +
"(load, save or quit) ", @output.string )
@input.rewind
@@ -208,7 +278,7 @@ class TestMenu < Minitest::Test
end
assert_equal("1. load\n2. save\n3. quit\nFile Menu: ", @output.string)
end
-
+
def test_list_option
@input << "l\n"
@input.rewind
@@ -252,18 +322,18 @@ class TestMenu < Minitest::Test
end
assert_equal("Sample2", output)
end
-
+
def test_passed_command
@input << "q\n"
@input.rewind
-
+
selected = nil
@terminal.choose do |menu|
menu.choices(:load, :save, :quit) { |command| selected = command }
end
assert_equal(:quit, selected)
end
-
+
def test_question_options
@input << "save\n"
@input.rewind
@@ -286,19 +356,19 @@ class TestMenu < Minitest::Test
def test_select_by
@input << "Sample1\n2\n"
@input.rewind
-
+
selected = @terminal.choose do |menu|
menu.choice "Sample1"
menu.choice "Sample2"
menu.choice "Sample3"
end
assert_equal("Sample1", selected)
-
+
@input.rewind
selected = @terminal.choose do |menu|
menu.select_by = :index
-
+
menu.choice "Sample1"
menu.choice "Sample2"
menu.choice "Sample3"
@@ -309,7 +379,7 @@ class TestMenu < Minitest::Test
selected = @terminal.choose do |menu|
menu.select_by = :name
-
+
menu.choice "Sample1"
menu.choice "Sample2"
menu.choice "Sample3"
@@ -320,7 +390,7 @@ class TestMenu < Minitest::Test
def test_hidden
@input << "Hidden\n4\n"
@input.rewind
-
+
selected = @terminal.choose do |menu|
menu.choice "Sample1"
menu.choice "Sample2"
@@ -329,12 +399,12 @@ class TestMenu < Minitest::Test
end
assert_equal("Hidden!", selected)
assert_equal("1. Sample1\n2. Sample2\n3. Sample3\n? ", @output.string)
-
+
@input.rewind
selected = @terminal.choose do |menu|
menu.select_by = :index
-
+
menu.choice "Sample1"
menu.choice "Sample2"
menu.choice "Sample3"
@@ -346,7 +416,7 @@ class TestMenu < Minitest::Test
selected = @terminal.choose do |menu|
menu.select_by = :name
-
+
menu.choice "Sample1"
menu.choice "Sample2"
menu.choice "Sample3"
@@ -360,8 +430,8 @@ class TestMenu < Minitest::Test
def test_select_by_letter
@input << "b\n"
@input.rewind
-
- selected = @terminal.choose do |menu|
+
+ selected = @terminal.choose do |menu|
menu.index = :letter
menu.choice :save
menu.choice :load
@@ -369,7 +439,7 @@ class TestMenu < Minitest::Test
end
assert_equal(:load, selected)
end
-
+
def test_shell
@input << "save --some-option my_file.txt\n"
@input.rewind
@@ -381,7 +451,7 @@ class TestMenu < Minitest::Test
menu.choice(:save) do |command, details|
selected = command
options = details
-
+
"Saved!"
end
menu.shell = true
@@ -402,9 +472,9 @@ class TestMenu < Minitest::Test
def test_symbols
@input << "3\n"
@input.rewind
-
+
selected = @terminal.choose do |menu|
- menu.choices(:save, :load, :quit)
+ menu.choices(:save, :load, :quit)
end
assert_equal(:quit, selected)
end
@@ -414,13 +484,12 @@ class TestMenu < Minitest::Test
# Will page twice, so start with two new lines
@input << "\n\n3\n"
@input.rewind
-
- # Sadly this goes into an infinite loop without the fix to page_print
- selected = @terminal.choose(* 1..10)
+
+ # Sadly this goes into an infinite loop without the fix to page_print
+ selected = @terminal.choose(* 1..10)
assert_equal(selected, 3)
end
-
def test_cancel_paging
# Tests that paging can be cancelled halfway through
@terminal.page_at = 5
@@ -434,12 +503,31 @@ class TestMenu < Minitest::Test
# Make sure paging message appeared
assert( @output.string.index('press enter/return to continue or q to stop'),
"Paging message did not appear." )
-
+
# Make sure it only appeared once
assert( @output.string !~ /q to stop.*q to stop/m,
"Paging message appeared more than once." )
end
+ def test_autocomplete_prompt
+ @input << "lisp\nRuby\n"
+ @input.rewind
+
+ answer = @terminal.choose do |menu|
+ menu.choice(:Perl)
+ menu.choice(:Python)
+ menu.choice(:Ruby)
+ menu.prompt = "What is your favorite programming language? "
+ end
+ languages = [:Perl, :Python, :Ruby]
+ assert_equal("1. Perl\n" +
+ "2. Python\n" +
+ "3. Ruby\n" +
+ "What is your favorite programming language? " +
+ "You must choose one of [1, 2, 3, Perl, Python, Ruby].\n" +
+ "? ", @output.string )
+ end
+
# Issue #180 - https://github.com/JEG2/highline/issues/180
def test_menu_prompt
@input << "2\n1\n"
@@ -458,4 +546,109 @@ class TestMenu < Minitest::Test
assert_equal complete_interaction, @output.string
end
+
+ def test_menu_gather_integer
+ @input << "Sample1\nlast\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.gather = 2
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "last"
+ end
+ assert_equal(["Sample1", "last"], selected)
+
+ assert_equal("1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? 1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? ", @output.string)
+ end
+
+ def test_menu_gather_string
+ @input << "Sample1\nlast\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.gather = :last
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice :last
+ end
+ assert_equal(["Sample1"], selected)
+
+ assert_equal("1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? 1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? ", @output.string)
+ end
+
+ def test_menu_gather_symbol
+ @input << "Sample1\nlast\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.gather = "last"
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "last"
+ end
+ assert_equal(["Sample1"], selected)
+
+ assert_equal("1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? 1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? ", @output.string)
+ end
+
+ def test_menu_gather_regexp
+ @input << "Sample1\nlast\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.gather = /la/
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "last"
+ end
+ assert_equal(["Sample1"], selected)
+
+ assert_equal("1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? 1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? ", @output.string)
+ end
+
+ def test_menu_gather_hash
+ @input << "Sample1\n3\n"
+ @input.rewind
+
+ selected = @terminal.choose do |menu|
+ menu.gather = { "First" => true, second: true }
+ menu.choice "Sample1"
+ menu.choice "Sample2"
+ menu.choice "last"
+ end
+ assert_equal({ "First" => "Sample1", second: "last" }, selected)
+
+ assert_equal("1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? 1. Sample1\n" +
+ "2. Sample2\n" +
+ "3. last\n" +
+ "? ", @output.string)
+ end
end