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'
- ALL_ARG =
'*'
- ALL_REGEXP =
/^(\*)(?::)?(\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_all_args(tokens) ⇒ Object
- #map_array_of_tokens(tokens) ⇒ Object
- #map_hash_of_tokens(tokens) ⇒ 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)
44 45 46 47 48 |
# File 'lib/hirb/menu.rb', line 44 def self.render(output, ={}, &block) new().render(output, &block) rescue Error=>e $stderr.puts "Error: #{e.}" end |
Instance Method Details
#action_object ⇒ Object
212 213 214 |
# File 'lib/hirb/menu.rb', line 212 def action_object @options[:action_object] || eval("self", TOPLEVEL_BINDING) end |
#add_chosen_to_args(items) ⇒ Object
199 200 201 202 203 |
# File 'lib/hirb/menu.rb', line 199 def add_chosen_to_args(items) args = @new_args.dup args[args.index(CHOSEN_ARG)] = items args end |
#choose_from_menu ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/hirb/menu.rb', line 91 def return unasked_choice if @output.size == 1 && !@options[:ask] if (helper_class = 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
188 189 190 191 192 193 194 195 196 197 |
# File 'lib/hirb/menu.rb', line 188 def cleanup_new_args if @new_args.all? {|e| e == CHOSEN_ARG } @new_args = [CHOSEN_ARG] elsif @new_args.index(ALL_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
205 206 207 208 209 210 |
# File 'lib/hirb/menu.rb', line 205 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
220 221 222 |
# File 'lib/hirb/menu.rb', line 220 def default_field @default_field ||= @options[:default_field] || fields[0] end |
#execute_action(chosen) ⇒ Object
110 111 112 113 114 115 116 117 |
# File 'lib/hirb/menu.rb', line 110 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
225 226 227 228 |
# File 'lib/hirb/menu.rb', line 225 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
65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/hirb/menu.rb', line 65 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
78 79 80 81 82 |
# File 'lib/hirb/menu.rb', line 78 def get_readline_input(prompt) input = Readline.readline prompt Readline::HISTORY << input input end |
#input_to_tokens(input) ⇒ Object
162 163 164 165 166 167 |
# File 'lib/hirb/menu.rb', line 162 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
119 120 121 |
# File 'lib/hirb/menu.rb', line 119 def invoke(cmd, args) action_object.send(cmd, *args) end |
#map_all_args(tokens) ⇒ Object
144 145 146 147 148 149 150 151 152 |
# File 'lib/hirb/menu.rb', line 144 def map_all_args(tokens) tokens.map { |arr,f| if arr == ALL_ARG f.nil? ? @output : yield(@output, f) else yield(arr, f) end }.flatten end |
#map_array_of_tokens(tokens) ⇒ Object
158 159 160 |
# File 'lib/hirb/menu.rb', line 158 def map_array_of_tokens(tokens) map_all_args(tokens) { |arr,f| arr.map {|e| e.is_a?(Array) && f.is_a?(Integer) ? e[f] : e.send(f) } } end |
#map_hash_of_tokens(tokens) ⇒ Object
154 155 156 |
# File 'lib/hirb/menu.rb', line 154 def map_hash_of_tokens(tokens) map_all_args(tokens) { |arr,f| arr.map {|e| e[f]} } end |
#map_tokens(tokens) ⇒ Object
132 133 134 135 136 137 138 |
# File 'lib/hirb/menu.rb', line 132 def map_tokens(tokens) if return_cell_values? @output[0].is_a?(Hash) ? map_hash_of_tokens(tokens) : map_array_of_tokens(tokens) else map_all_args(tokens) { |arr, f| arr[0] } end end |
#parse_input(input) ⇒ Object
123 124 125 126 127 128 129 130 |
# File 'lib/hirb/menu.rb', line 123 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
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/hirb/menu.rb', line 169 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.") if return_cell_values? [Util.choose_from_array(@output, word), field] else [[Util.choose_from_array(@output, word)], nil] end elsif word[ALL_REGEXP] @new_args << CHOSEN_ARG $2 ? [ALL_ARG, unalias_field($2)] : ALL_ARG else @new_args << word nil end end |
#pre_prompt ⇒ Object
84 85 86 87 88 89 |
# File 'lib/hirb/menu.rb', line 84 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
238 239 240 241 242 243 |
# File 'lib/hirb/menu.rb', line 238 def readline_loads? require 'readline' true rescue LoadError false end |
#render(output, &block) ⇒ Object
57 58 59 60 61 62 63 |
# File 'lib/hirb/menu.rb', line 57 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
140 141 142 |
# File 'lib/hirb/menu.rb', line 140 def return_cell_values? @options[:two_d] end |
#split_input_args(input) ⇒ Object
216 217 218 |
# File 'lib/hirb/menu.rb', line 216 def split_input_args(input) input.split(/\s+/) end |
#table_helper_class? ⇒ Boolean
230 231 232 |
# File 'lib/hirb/menu.rb', line 230 def table_helper_class? @options[:helper_class].is_a?(Class) && @options[:helper_class] < Helpers::Table end |
#unalias_field(field) ⇒ Object
234 235 236 |
# File 'lib/hirb/menu.rb', line 234 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
103 104 105 106 107 108 |
# File 'lib/hirb/menu.rb', line 103 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 |