class HighLine::Menu


to {HighLine#choose} can detail all aspects of menu display and control.
Using the accessors and {Menu#choice} and {Menu#choices}, the block passed
{HighLine#choose HighLine#choose}.
Menu objects encapsulate all the details of a call to

def add_item(item)

def add_item(item)
  @items << item
  @help.merge!(item.item_help)
  update_responses
end

def all_items

def all_items
  @items + @hidden_items
end

def build_item(*args)

def build_item(*args)
  Menu::Item.new(*args)
end

def choice(name, help = nil, text = nil, &action)

def choice(name, help = nil, text = nil, &action)
  item = Menu::Item.new(name, text: text, help: help, action: action)
  @items << item
  @help.merge!(item.item_help)
  update_responses # rebuild responses based on our settings
end

def choices(*names, &action)

Other tags:
    Example: -

Returns:
  • (void) -

Parameters:
  • action () --
  • names (Array<#to_s>) -- menu item titles/headers/names to be
def choices(*names, &action)
  names.each { |n| choice(n, &action) }
end

def decorate_index(index)

def decorate_index(index)
  if index_color
    HighLine.color(index, index_color)
  else
    index
  end
end

def decorate_item(text, ix)

def decorate_item(text, ix)
  decorated, non_decorated = mark_for_decoration(text, ix)
  decorate_index(decorated) + non_decorated
end

def find_item_from_selection(items, selection)

def find_item_from_selection(items, selection)
  if selection =~ /^\d+$/ # is a number?
    get_item_by_number(items, selection)
  else
    get_item_by_letter(items, selection)
  end
end

def gather_selected(highline_context, selections, details = nil)

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
    raise ArgumentError, "selections must be either Array or Hash"
  end
end

def get_item_by_letter(items, selection)

Parameters:
  • selection (String) -- menu's title/header/name
def get_item_by_letter(items, selection)
  item = items.find { |i| i.name == selection }
  return item if item
  # 97 is the "a" letter at ascii table
  # Ex: For "a" it will return 0, and for "c" it will return 2
  index = selection.downcase.ord - 97
  items[index]
end

def get_item_by_number(items, selection)

Parameters:
  • selection (Integer) -- menu item's index.
def get_item_by_number(items, selection)
  items[selection.to_i - 1]
end

def help(topic, help)

Parameters:
  • help (String) -- the help message to be associated with the menu
  • topic (String) -- the menu item header/title/name to be associated
def help(topic, help)
  @help[topic] = help
end

def hidden(name, help = nil, &action)

def hidden(name, help = nil, &action)
  item = Menu::Item.new(name, text: name, help: help, action: action)
  @hidden_items << item
  @help.merge!(item.item_help)
end

def index=(style)


Because of this, you should make a habit of setting the _index_ first.
_index_suffix_ to a single space and _select_by_ to :name.
Setting the _index_ to :none or a literal String also adjusts

any String:: Will be used as the literal _index_.
:none:: No index will be appended to menu items.
with a.
:letter:: Items will be indexed alphabetically, starting
with 1. This is the default method of indexing.
:number:: Menu items will be indexed numerically, starting

menu items, when displayed in list form. The available settings are:
Sets the indexing style for this Menu object. Indexes are appended to
def index=(style)
  @index = style
  return unless @index == :none || @index.is_a?(::String)
  # Default settings.
  @index_suffix = " "
  @select_by    = :name
end

def init_help


action code, and the default help listing.
Initializes the help system by adding a :help choice, some
def init_help
  return if @items.include?(:help)
  topics    = @help.keys.sort
  help_help =
    if @help.include?("help")
      @help["help"]
    else
      "This command will display helpful messages about " \
        "functionality, like this one.  To see the help for " \
        "a specific topic enter:\n\thelp [TOPIC]\nTry asking " \
        "for help on any of the following:\n\n" \
        "<%= list(#{topics.inspect}, :columns_across) %>"
    end
  choice(:help, help_help) do |_command, topic|
    topic.strip!
    topic.downcase!
    if topic.empty?
      @highline.say(@help["help"])
    else
      @highline.say("= #{topic}\n\n#{@help[topic]}")
    end
  end
end

def initialize

def initialize
  #
  # Initialize Question objects with ignored values, we'll
  # adjust ours as needed.
  #
  super("Ignored", [], &nil) # avoiding passing the block along
  @items           = []
  @hidden_items    = []
  @help            = Hash.new("There's no help for that topic.")
  @index           = :number
  @index_suffix    = ". "
  @select_by       = :index_or_name
  @flow            = :rows
  @list_option     = nil
  @header          = nil
  @prompt          = "?  "
  @layout          = :list
  @shell           = false
  @nil_on_handled  = false
  # Used for coloring Menu indices.
  # Set it to default. But you may override it.
  @index_color     = self.class.index_color
  # Override Questions responses, we'll set our own.
  @responses       = {}
  # Context for action code.
  @highline        = nil
  yield self if block_given?
  init_help if @shell && !@help.empty?
end

def layout=(new_layout)


:inline.
will default to :none and _flow_ will default to
If set to either :one_line, or :menu_only, _index_

context so each method is properly delegated.
otherwise evaluated in the TemplateRenderer
menu and prompt, but is
String can access header,
any ERb String:: Will be taken as the literal _layout_. This
short _prompt_.
:menu_only:: Just the menu items, followed up by a likely
items between trailing parenthesis.
colon and spaces, then the _prompt_ with menu
The _header_ comes first followed by a
:one_line:: A shorter _layout_ that fits on one line.
will be used as the ask()-like question.
items will follow. Finally, the _prompt_
a trailing colon. Then the list of menu
will appear at the top on its own line with
:list:: The default _layout_. The _header_ if set

Accepted settings for _layout_ are:

configuration block, if needed.
account for that, you probably want to set a _layout_ first in your
of the Menu object, to ideal defaults for the chosen _layout_. To
Setting a _layout_ with this method also adjusts some other attributes
def layout=(new_layout)
  @layout = new_layout
  # Default settings.
  case @layout
  when :one_line, :menu_only
    self.index = :none
    @flow = :inline
  end
end

def map_items_by_index

def map_items_by_index
  size = all_items.size
  case @index
  when :letter
    ("a".."z").first(size)
  when :capital_letter
    ("A".."Z").first(size)
  else
    (1..size).map(&:to_s)
  end
end

def map_items_by_name

def map_items_by_name
  all_items.map(&:name)
end

def mark_for_decoration(text, ix)

def mark_for_decoration(text, ix)
  case @index
  when :number
    ["#{ix + 1}#{@index_suffix}", text]
  when :letter, :capital_letter
    first_letter = (@index == :capital_letter ? 'A' : 'a')
    ["#{(first_letter.ord + ix).chr}#{@index_suffix}", text]
  when :none
    [text, ""]
  else
    ["#{index}#{@index_suffix}", text]
  end
end

def options


on the settings of _index_ and _select_by_.
This method returns all possible options for auto-completion, based
def options
  case @select_by
  when :index
    map_items_by_index
  when :name
    map_items_by_name
  else
    map_items_by_index + map_items_by_name
  end
end

def parse_list

def parse_list
  "<%= list( menu, #{@flow.inspect},
       #{@list_option.inspect} ) %>"
end

def select(highline_context, selection, details = nil)

Returns:
  • (nil, Object) - if @nil_on_handled is set it returns +nil+,

Parameters:
  • details () -- additional parameter to be passed when in shell mode.
  • selection (String, Integer) -- index or title of the selected
  • highline_context (HighLine) -- a HighLine instance to be used
def select(highline_context, selection, details = nil)
  # add in any hidden menu commands
  items = all_items
  # Find the selected action.
  selected_item = find_item_from_selection(items, selection)
  # Run or return it.
  @highline = highline_context
  value_for_selected_item(selected_item, details)
end

def show_default_if_any

def show_default_if_any
  default.to_s.empty? ? "" : "(#{default}) "
end

def to_ary


indexes.
This method returns all menu items to be displayed, complete with
Allows Menu objects to pass as Arrays, for use with HighLine.list().
def to_ary
  @items.map.with_index { |item, ix| decorate_item(item.text.to_s, ix) }
end

def to_s


_layout_ to be rendered, which is used by HighLine.say().
Allows Menu to behave as a String, just like Question. Returns the
def to_s
  case @layout
  when :list
    %(<%= header ? "#{header}:\n" : '' %>) +
      parse_list +
      show_default_if_any +
      "<%= prompt %>"
  when :one_line
    %(<%= header ? "#{header}:  " : '' %>) +
      "<%= prompt %>" \
      "(" + parse_list + ")" +
      show_default_if_any +
      "<%= prompt[/\s*$/] %>"
  when :menu_only
    parse_list +
      show_default_if_any +
      "<%= prompt %>"
  else
    @layout
  end
end

def update_responses


'options' will be used to populate choice lists.
build_responses method, overriding its default arguments to specify
Menu specific differences. Calls the superclass' (Question's)
This method will update the intelligent responses to account for
def update_responses
  build_responses(options)
end

def value_for_array_selections(items, selections, details)

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
  index = 0
  selected_items.map do |selected_item|
    value = value_for_selected_item(selected_item, self.shell ? details[index] : nil)
    index += 1
    value
  end
end

def value_for_hash_selections(items, selections, details)

def value_for_hash_selections(items, selections, details)
  # Find the selected items and return in hash form
  index = 0
  selections.each_with_object({}) do |(key, selection), memo|
    selected_item = find_item_from_selection(items, selection)
    value = value_for_selected_item(selected_item, self.shell ? details[index] : nil)
    index += 1
    memo[key] = value
  end
end

def value_for_selected_item(item, details)

def value_for_selected_item(item, details)
  if item.action
    result = if @shell
               item.action.call(item.name, details)
             else
               item.action.call(item.name)
             end
    @nil_on_handled ? nil : result
  else
    item.name
  end
end