Class: Hirb::Menu
- Inherits:
-
Object
- Object
- Hirb::Menu
- Defined in:
- lib/hirb/menu.rb
Overview
This class provides a menu using Hirb’s table helpers by default to display choices. Menu choices (syntax at Hirb::Util.choose_from_array) refer to rows. However, when in two_d mode, choices refer to specific cells by appending a ‘:field’ to a choice. A field name can be an abbreviated. Menus can also have an action mode, which turns the menu prompt into a commandline that executes the choices as arguments and uses methods as actions/commands.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- CHOSEN_REGEXP =
Detects valid choices and optional field/column
/^(\d([^:]+)?|\*)(?::)?(\S+)?/
- CHOSEN_ARG =
'%s'
- DIRECTIONS =
"Specify individual choices (4,7), range of choices (1-3) or all choices (*)."
Class Method Summary collapse
-
.render(output, options = {}, &block) ⇒ Object
This method will return an array unless it’s exited by simply pressing return, which returns nil.
Instance Method Summary collapse
- #action_object ⇒ Object
- #add_chosen_to_args(items) ⇒ Object
- #choose_from_menu ⇒ Object
- #cleanup_new_args ⇒ Object
- #command ⇒ Object
- #default_field ⇒ Object
- #execute_action(chosen) ⇒ Object
-
#fields ⇒ Object
Has to be called after displaying menu.
- #get_input ⇒ Object
- #get_readline_input(prompt) ⇒ Object
-
#initialize(options = {}) ⇒ Menu
constructor
:stopdoc:.
- #input_to_tokens(input) ⇒ Object
- #invoke(cmd, args) ⇒ Object
- #map_tokens(tokens) ⇒ Object
- #parse_input(input) ⇒ Object
- #parse_word(word) ⇒ Object
- #pre_prompt ⇒ Object
- #readline_loads? ⇒ Boolean
- #render(output, &block) ⇒ Object
- #return_cell_values? ⇒ Boolean
- #split_input_args(input) ⇒ Object
- #table_helper_class? ⇒ Boolean
- #unalias_field(field) ⇒ Object
- #unasked_choice ⇒ Object
Constructor Details
Class Method Details
.render(output, options = {}, &block) ⇒ Object
This method will return an array unless it’s exited by simply pressing return, which returns nil. If given a block, the block will yield if and with any menu items are chosen. All options except for the ones below are passed to render the menu.
Options:
- :helper_class
-
Helper class to render menu. Helper class is expected to implement numbering given a :number option. To use a very basic menu, set this to false. Defaults to Hirb::Helpers::AutoTable.
- :prompt
-
String for menu prompt. Defaults to “Choose: ”.
- :ask
-
Always ask for input, even if there is only one choice. Default is true.
- :directions
-
Display directions before prompt. Default is true.
- :readline
-
Use readline to get user input if available. Input strings are added to readline history. Default is false.
- :two_d
-
Turn menu into a 2 dimensional (2D) menu by allowing user to pick values from table cells. Default is false.
- :default_field
-
Default field for a 2D menu. Defaults to first field in a table.
- :action
-
Turn menu into an action menu by letting user pass menu choices as an argument to a method/command. A menu choice’s place amongst other arguments is preserved. Default is false.
- :multi_action
-
Execute action menu multiple times iterating over the menu choices. Default is false.
- :action_object
-
Object that takes method/command calls. Default is main.
- :command
-
Default method/command to call when no command given.
- :reopen
-
Reopens $stdin with given file or with /dev/tty when set to true. Use when $stdin is already reading in piped data.
Examples:
>> extend Hirb::Console
=> self
>> menu [1,2,3], :prompt=> "So many choices, so little time: "
>> menu [{:a=>1, :b=>2}, {:a=>3, :b=>4}], :fields=>[:a,b], :two_d=>true)
42 43 44 45 46 |
# File 'lib/hirb/menu.rb', line 42 def self.render(output, ={}, &block) new().render(output, &block) rescue Error=>e $stderr.puts "Error: #{e.}" end |
Instance Method Details
#action_object ⇒ Object
192 193 194 |
# File 'lib/hirb/menu.rb', line 192 def action_object @options[:action_object] || eval("self", TOPLEVEL_BINDING) end |
#add_chosen_to_args(items) ⇒ Object
179 180 181 182 183 |
# File 'lib/hirb/menu.rb', line 179 def add_chosen_to_args(items) args = @new_args.dup args[args.index(CHOSEN_ARG)] = items args end |
#choose_from_menu ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/hirb/menu.rb', line 89 def return unasked_choice if @output.size == 1 && !@options[:ask] if (Util.any_const_get(@options[:helper_class])) View.render_output(@output, :class=>@options[:helper_class], :options=>@options.merge(:number=>true)) else @output.each_with_index {|e,i| puts "#{i+1}: #{e}" } end parse_input get_input end |
#cleanup_new_args ⇒ Object
169 170 171 172 173 174 175 176 177 |
# File 'lib/hirb/menu.rb', line 169 def cleanup_new_args if @new_args.all? {|e| e == CHOSEN_ARG } @new_args = [CHOSEN_ARG] else i = @new_args.index(CHOSEN_ARG) || raise(Error, "No rows chosen") @new_args.delete(CHOSEN_ARG) @new_args.insert(i, CHOSEN_ARG) end end |
#command ⇒ Object
185 186 187 188 189 190 |
# File 'lib/hirb/menu.rb', line 185 def command @command ||= begin cmd = (@new_args == [CHOSEN_ARG]) ? nil : @new_args.shift cmd ||= @options[:command] || raise(Error, "No command given for action menu") end end |
#default_field ⇒ Object
200 201 202 |
# File 'lib/hirb/menu.rb', line 200 def default_field @default_field ||= @options[:default_field] || fields[0] end |
#execute_action(chosen) ⇒ Object
108 109 110 111 112 113 114 115 |
# File 'lib/hirb/menu.rb', line 108 def execute_action(chosen) return nil if chosen.size.zero? if @options[:multi_action] chosen.each {|e| invoke command, add_chosen_to_args(e) } else invoke command, add_chosen_to_args(chosen) end end |
#fields ⇒ Object
Has to be called after displaying menu
205 206 207 208 |
# File 'lib/hirb/menu.rb', line 205 def fields @fields ||= @options[:fields] || (@options[:ask] && table_helper_class? && Helpers::Table.last_table ? Helpers::Table.last_table.fields[1..-1] : []) end |
#get_input ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/hirb/menu.rb', line 63 def get_input prompt = pre_prompt + @options[:prompt] prompt = DIRECTIONS+"\n"+prompt if @options[:directions] $stdin.reopen @options[:reopen] if @options[:reopen] if @options[:readline] && readline_loads? get_readline_input(prompt) else print prompt $stdin.gets.chomp.strip end end |
#get_readline_input(prompt) ⇒ Object
76 77 78 79 80 |
# File 'lib/hirb/menu.rb', line 76 def get_readline_input(prompt) input = Readline.readline prompt Readline::HISTORY << input input end |
#input_to_tokens(input) ⇒ Object
147 148 149 150 151 152 |
# File 'lib/hirb/menu.rb', line 147 def input_to_tokens(input) @new_args = [] tokens = (@args = split_input_args(input)).map {|word| parse_word(word) }.compact cleanup_new_args tokens end |
#invoke(cmd, args) ⇒ Object
117 118 119 |
# File 'lib/hirb/menu.rb', line 117 def invoke(cmd, args) action_object.send(cmd, *args) end |
#map_tokens(tokens) ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/hirb/menu.rb', line 130 def map_tokens(tokens) values = if return_cell_values? @output[0].is_a?(Hash) ? tokens.map {|arr,f| arr.map {|e| e[f]} } : tokens.map {|arr,f| arr.map {|e| e.is_a?(Array) && f.is_a?(Integer) ? e[f] : e.send(f) } } else tokens.map {|arr, f| arr[0] } end values.flatten end |
#parse_input(input) ⇒ Object
121 122 123 124 125 126 127 128 |
# File 'lib/hirb/menu.rb', line 121 def parse_input(input) if (@options[:two_d] || @options[:action]) tokens = input_to_tokens(input) map_tokens(tokens) else Util.choose_from_array(@output, input) end end |
#parse_word(word) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/hirb/menu.rb', line 154 def parse_word(word) if word[CHOSEN_REGEXP] @new_args << CHOSEN_ARG field = $3 ? unalias_field($3) : default_field || raise(Error, "No default field/column found. Fields must be explicitly picked.") token = Util.choose_from_array(@output, word) token = [token] if word[/\*|-|\.\.|,/] && !return_cell_values? [token, field] else @new_args << word nil end end |
#pre_prompt ⇒ Object
82 83 84 85 86 87 |
# File 'lib/hirb/menu.rb', line 82 def pre_prompt prompt = '' prompt << "Default field: #{default_field}\n" if @options[:two_d] && default_field prompt << "Default command: #{@options[:command]}\n" if @options[:action] && @options[:command] prompt end |
#readline_loads? ⇒ Boolean
218 219 220 221 222 223 |
# File 'lib/hirb/menu.rb', line 218 def readline_loads? require 'readline' true rescue LoadError false end |
#render(output, &block) ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/hirb/menu.rb', line 55 def render(output, &block) @output = Array(output) return [] if @output.size.zero? chosen = block.call(chosen) if block && chosen.size > 0 @options[:action] ? execute_action(chosen) : chosen end |
#return_cell_values? ⇒ Boolean
143 144 145 |
# File 'lib/hirb/menu.rb', line 143 def return_cell_values? @options[:two_d] end |
#split_input_args(input) ⇒ Object
196 197 198 |
# File 'lib/hirb/menu.rb', line 196 def split_input_args(input) input.split(/\s+/) end |
#table_helper_class? ⇒ Boolean
210 211 212 |
# File 'lib/hirb/menu.rb', line 210 def table_helper_class? @options[:helper_class].is_a?(Class) && @options[:helper_class] < Helpers::Table end |
#unalias_field(field) ⇒ Object
214 215 216 |
# File 'lib/hirb/menu.rb', line 214 def unalias_field(field) fields.sort_by {|e| e.to_s }.find {|e| e.to_s[/^#{field}/] } || raise(Error, "Invalid field '#{field}'") end |
#unasked_choice ⇒ Object
101 102 103 104 105 106 |
# File 'lib/hirb/menu.rb', line 101 def unasked_choice return @output unless @options[:action] raise(Error, "Default command and field required for unasked action menu") unless default_field && @options[:command] @new_args = [@options[:command], CHOSEN_ARG] map_tokens([[@output, default_field]]) end |