hirber 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gemspec +21 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.rdoc +165 -0
- data/CONTRIBUTING.md +1 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +205 -0
- data/Rakefile +35 -0
- data/lib/bond/completions/hirb.rb +15 -0
- data/lib/hirb.rb +84 -0
- data/lib/hirb/console.rb +43 -0
- data/lib/hirb/dynamic_view.rb +113 -0
- data/lib/hirb/formatter.rb +126 -0
- data/lib/hirb/helpers.rb +18 -0
- data/lib/hirb/helpers/auto_table.rb +24 -0
- data/lib/hirb/helpers/markdown_table.rb +14 -0
- data/lib/hirb/helpers/object_table.rb +14 -0
- data/lib/hirb/helpers/parent_child_tree.rb +24 -0
- data/lib/hirb/helpers/tab_table.rb +24 -0
- data/lib/hirb/helpers/table.rb +376 -0
- data/lib/hirb/helpers/table/filters.rb +10 -0
- data/lib/hirb/helpers/table/resizer.rb +82 -0
- data/lib/hirb/helpers/tree.rb +181 -0
- data/lib/hirb/helpers/unicode_table.rb +15 -0
- data/lib/hirb/helpers/vertical_table.rb +37 -0
- data/lib/hirb/import_object.rb +10 -0
- data/lib/hirb/menu.rb +226 -0
- data/lib/hirb/pager.rb +106 -0
- data/lib/hirb/string.rb +44 -0
- data/lib/hirb/util.rb +96 -0
- data/lib/hirb/version.rb +3 -0
- data/lib/hirb/view.rb +272 -0
- data/lib/hirb/views.rb +8 -0
- data/lib/hirb/views/couch_db.rb +11 -0
- data/lib/hirb/views/misc_db.rb +15 -0
- data/lib/hirb/views/mongo_db.rb +17 -0
- data/lib/hirb/views/orm.rb +11 -0
- data/lib/hirb/views/rails.rb +19 -0
- data/lib/ripl/hirb.rb +15 -0
- data/test/auto_table_test.rb +33 -0
- data/test/console_test.rb +27 -0
- data/test/dynamic_view_test.rb +94 -0
- data/test/formatter_test.rb +176 -0
- data/test/hirb_test.rb +39 -0
- data/test/import_test.rb +9 -0
- data/test/menu_test.rb +272 -0
- data/test/object_table_test.rb +79 -0
- data/test/pager_test.rb +162 -0
- data/test/resizer_test.rb +62 -0
- data/test/table_test.rb +667 -0
- data/test/test_helper.rb +60 -0
- data/test/tree_test.rb +184 -0
- data/test/util_test.rb +59 -0
- data/test/view_test.rb +178 -0
- data/test/views_test.rb +22 -0
- metadata +164 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
# Base tree class which given an array of nodes produces different types of trees.
|
2
|
+
# The types of trees currently are:
|
3
|
+
# * basic:
|
4
|
+
# 0
|
5
|
+
# 1
|
6
|
+
# 2
|
7
|
+
# 3
|
8
|
+
# 4
|
9
|
+
#
|
10
|
+
# * directory:
|
11
|
+
# 0
|
12
|
+
# |-- 1
|
13
|
+
# | |-- 2
|
14
|
+
# | `-- 3
|
15
|
+
# `-- 4
|
16
|
+
#
|
17
|
+
# * number:
|
18
|
+
# 1. 0
|
19
|
+
# 1. 1
|
20
|
+
# 1. 2
|
21
|
+
# 2. 3
|
22
|
+
# 2. 4
|
23
|
+
#
|
24
|
+
# Tree nodes can be given as an array of arrays or an array of hashes.
|
25
|
+
# To render the above basic tree with an array of hashes:
|
26
|
+
# Hirb::Helpers::Tree.render([{:value=>0, :level=>0}, {:value=>1, :level=>1}, {:value=>2, :level=>2},
|
27
|
+
# {:value=>3, :level=>2}, {:value=>4, :level=>1}])
|
28
|
+
# Note from the hash keys that :level refers to the depth of the tree while :value refers to the text displayed
|
29
|
+
# for a node.
|
30
|
+
#
|
31
|
+
# To render the above basic tree with an array of arrays:
|
32
|
+
# Hirb::Helpers::Tree.render([[0,0], [1,1], [2,2], [2,3], [1,4]])
|
33
|
+
# Note that the each array pair consists of the level and the value for the node.
|
34
|
+
class Hirb::Helpers::Tree
|
35
|
+
class ParentlessNodeError < StandardError; end
|
36
|
+
|
37
|
+
class <<self
|
38
|
+
# Main method which renders a tree.
|
39
|
+
# ==== Options:
|
40
|
+
# [:type] Type of tree. Either :basic, :directory or :number. Default is :basic.
|
41
|
+
# [:validate] Boolean to validate tree. Checks to see if all nodes have parents. Raises ParentlessNodeError if
|
42
|
+
# an invalid node is found. Default is false.
|
43
|
+
# [:indent] Number of spaces to indent between levels for basic + number trees. Default is 4.
|
44
|
+
# [:limit] Limits the level or depth of a tree that is displayed. Root node is level 0.
|
45
|
+
# [:description] Displays brief description about tree ie how many nodes it has.
|
46
|
+
# [:multi_line_nodes] Handles multi-lined nodes by indenting their newlines. Default is false.
|
47
|
+
# Examples:
|
48
|
+
# Hirb::Helpers::Tree.render([[0, 'root'], [1, 'child']], :type=>:directory)
|
49
|
+
def render(nodes, options={})
|
50
|
+
new(nodes, options).render
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# :stopdoc:
|
55
|
+
attr_accessor :nodes
|
56
|
+
|
57
|
+
def initialize(input_nodes, options={})
|
58
|
+
@options = options
|
59
|
+
@type = options[:type] || :basic
|
60
|
+
if input_nodes[0].is_a?(Array)
|
61
|
+
@nodes = input_nodes.map {|e| Node.new(:level=>e[0], :value=>e[1]) }
|
62
|
+
else
|
63
|
+
@nodes = input_nodes.map {|e| Node.new(e)}
|
64
|
+
end
|
65
|
+
@nodes.each_with_index {|e,i| e.merge!(:tree=>self, :index=>i)}
|
66
|
+
@nodes.each {|e| e[:value] = e[:value].to_s }
|
67
|
+
validate_nodes if options[:validate]
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def render
|
72
|
+
body = render_tree
|
73
|
+
body += render_description if @options[:description]
|
74
|
+
body
|
75
|
+
end
|
76
|
+
|
77
|
+
def render_description
|
78
|
+
"\n\n#{@nodes.length} #{@nodes.length == 1 ? 'node' : 'nodes'} in tree"
|
79
|
+
end
|
80
|
+
|
81
|
+
def render_tree
|
82
|
+
@indent = ' ' * (@options[:indent] || 4 )
|
83
|
+
@nodes = @nodes.select {|e| e[:level] <= @options[:limit] } if @options[:limit]
|
84
|
+
case @type.to_s
|
85
|
+
when 'directory' then render_directory
|
86
|
+
when 'number' then render_number
|
87
|
+
else render_basic
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def render_nodes
|
92
|
+
value_indent = @options[:multi_line_nodes] ? @indent : nil
|
93
|
+
@nodes.map {|e| yield(e) + e.value(value_indent) }.join("\n")
|
94
|
+
end
|
95
|
+
|
96
|
+
def render_directory
|
97
|
+
mark_last_nodes_per_level
|
98
|
+
render_nodes {|e|
|
99
|
+
value = ''
|
100
|
+
unless e.root?
|
101
|
+
value << e.render_parent_characters
|
102
|
+
value << (e[:last_node] ? "`-- " : "|-- ")
|
103
|
+
end
|
104
|
+
value
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
def render_number
|
109
|
+
counter = {}
|
110
|
+
@nodes.each {|e|
|
111
|
+
parent_level_key = "#{(e.parent ||{})[:index]}.#{e[:level]}"
|
112
|
+
counter[parent_level_key] ||= 0
|
113
|
+
counter[parent_level_key] += 1
|
114
|
+
e[:pre_value] = "#{counter[parent_level_key]}. "
|
115
|
+
}
|
116
|
+
render_nodes {|e| @indent * e[:level] + e[:pre_value] }
|
117
|
+
end
|
118
|
+
|
119
|
+
def render_basic
|
120
|
+
render_nodes {|e| @indent * e[:level] }
|
121
|
+
end
|
122
|
+
|
123
|
+
def validate_nodes
|
124
|
+
@nodes.each do |e|
|
125
|
+
raise ParentlessNodeError if (e[:level] > e.previous[:level]) && (e[:level] - e.previous[:level]) > 1
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# walks tree accumulating last nodes per unique parent+level
|
130
|
+
def mark_last_nodes_per_level
|
131
|
+
@nodes.each {|e| e.delete(:last_node)}
|
132
|
+
last_node_hash = @nodes.inject({}) {|h,e|
|
133
|
+
h["#{(e.parent ||{})[:index]}.#{e[:level]}"] = e; h
|
134
|
+
}
|
135
|
+
last_node_hash.values.uniq.each {|e| e[:last_node] = true}
|
136
|
+
end
|
137
|
+
#:startdoc:
|
138
|
+
class Node < ::Hash #:nodoc:
|
139
|
+
class MissingLevelError < StandardError; end
|
140
|
+
class MissingValueError < StandardError; end
|
141
|
+
|
142
|
+
def initialize(hash)
|
143
|
+
super
|
144
|
+
raise MissingLevelError unless hash.has_key?(:level)
|
145
|
+
raise MissingValueError unless hash.has_key?(:value)
|
146
|
+
replace(hash)
|
147
|
+
end
|
148
|
+
|
149
|
+
def value(indent=nil)
|
150
|
+
indent ? self[:value].gsub("\n", "\n#{indent * self[:level]}") : self[:value]
|
151
|
+
end
|
152
|
+
|
153
|
+
def parent
|
154
|
+
self[:tree].nodes.slice(0 .. self[:index]).reverse.detect {|e| e[:level] < self[:level]}
|
155
|
+
end
|
156
|
+
|
157
|
+
def next
|
158
|
+
self[:tree].nodes[self[:index] + 1]
|
159
|
+
end
|
160
|
+
|
161
|
+
def previous
|
162
|
+
self[:tree].nodes[self[:index] - 1]
|
163
|
+
end
|
164
|
+
|
165
|
+
def root?; self[:level] == 0; end
|
166
|
+
|
167
|
+
# refers to characters which connect parent nodes
|
168
|
+
def render_parent_characters
|
169
|
+
parent_chars = []
|
170
|
+
get_parents_character(parent_chars)
|
171
|
+
parent_chars.reverse.map {|level| level + ' ' * 3 }.join('')
|
172
|
+
end
|
173
|
+
|
174
|
+
def get_parents_character(parent_chars)
|
175
|
+
if self.parent
|
176
|
+
parent_chars << (self.parent[:last_node] ? ' ' : '|') unless self.parent.root?
|
177
|
+
self.parent.get_parents_character(parent_chars)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
class Hirb::Helpers::UnicodeTable < Hirb::Helpers::Table
|
3
|
+
CHARS = {
|
4
|
+
:top => {:left => '┌', :center => '┬', :right => '┐', :horizontal => '─',
|
5
|
+
:vertical => {:outside => '│', :inside => '│'} },
|
6
|
+
:middle => {:left => '├', :center => '┼', :right => '┤', :horizontal => '─'},
|
7
|
+
:bottom => {:left => '└', :center => '┴', :right => '┘', :horizontal => '─',
|
8
|
+
:vertical => {:outside => '│', :inside => '╎'} }
|
9
|
+
}
|
10
|
+
|
11
|
+
# Renders a unicode table
|
12
|
+
def self.render(rows, options={})
|
13
|
+
new(rows, options).render
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Hirb::Helpers::VerticalTable < Hirb::Helpers::Table
|
2
|
+
|
3
|
+
# Renders a vertical table using the same options as Hirb::Helpers::Table.render except for the ones below
|
4
|
+
# and :max_fields, :vertical and :max_width which aren't used.
|
5
|
+
# ==== Options:
|
6
|
+
# [:hide_empty] Boolean which hides empty values (nil or '') from being displayed. Default is false.
|
7
|
+
def self.render(rows, options={})
|
8
|
+
new(rows, {:escape_special_chars=>false, :resize=>false}.merge(options)).render
|
9
|
+
end
|
10
|
+
|
11
|
+
#:stopdoc:
|
12
|
+
def setup_field_lengths
|
13
|
+
@field_lengths = default_field_lengths
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_header; []; end
|
17
|
+
def render_footer; []; end
|
18
|
+
|
19
|
+
def render_rows
|
20
|
+
i = 0
|
21
|
+
longest_header = Hirb::String.size @headers.values.sort_by {|e| Hirb::String.size(e) }.last
|
22
|
+
stars = "*" * [(longest_header + (longest_header / 2)), 3].max
|
23
|
+
@rows.map do |row|
|
24
|
+
row = "#{stars} #{i+1}. row #{stars}\n" +
|
25
|
+
@fields.map {|f|
|
26
|
+
if !@options[:hide_empty] || (@options[:hide_empty] && !row[f].empty?)
|
27
|
+
"#{Hirb::String.rjust(@headers[f], longest_header)}: #{row[f]}"
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
}.compact.join("\n")
|
32
|
+
i+= 1
|
33
|
+
row
|
34
|
+
end
|
35
|
+
end
|
36
|
+
#:startdoc:
|
37
|
+
end
|
data/lib/hirb/menu.rb
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
module Hirb
|
2
|
+
# This class provides a menu using Hirb's table helpers by default to display choices.
|
3
|
+
# Menu choices (syntax at Hirb::Util.choose_from_array) refer to rows. However, when in
|
4
|
+
# two_d mode, choices refer to specific cells by appending a ':field' to a choice.
|
5
|
+
# A field name can be an abbreviated. Menus can also have an action mode, which turns the
|
6
|
+
# menu prompt into a commandline that executes the choices as arguments and uses methods as
|
7
|
+
# actions/commands.
|
8
|
+
class Menu
|
9
|
+
class Error < StandardError; end
|
10
|
+
|
11
|
+
# Detects valid choices and optional field/column
|
12
|
+
CHOSEN_REGEXP = /^(\d([^:]+)?|\*)(?::)?(\S+)?/
|
13
|
+
CHOSEN_ARG = '%s'
|
14
|
+
DIRECTIONS = "Specify individual choices (4,7), range of choices (1-3) or all choices (*)."
|
15
|
+
|
16
|
+
|
17
|
+
# This method will return an array unless it's exited by simply pressing return, which returns nil.
|
18
|
+
# If given a block, the block will yield if and with any menu items are chosen.
|
19
|
+
# All options except for the ones below are passed to render the menu.
|
20
|
+
#
|
21
|
+
# ==== Options:
|
22
|
+
# [*:helper_class*] Helper class to render menu. Helper class is expected to implement numbering given a :number option.
|
23
|
+
# To use a very basic menu, set this to false. Defaults to Hirb::Helpers::AutoTable.
|
24
|
+
# [*:prompt*] String for menu prompt. Defaults to "Choose: ".
|
25
|
+
# [*:ask*] Always ask for input, even if there is only one choice. Default is true.
|
26
|
+
# [*:directions*] Display directions before prompt. Default is true.
|
27
|
+
# [*:readline*] Use readline to get user input if available. Input strings are added to readline history. Default is false.
|
28
|
+
# [*:two_d*] Turn menu into a 2 dimensional (2D) menu by allowing user to pick values from table cells. Default is false.
|
29
|
+
# [*:default_field*] Default field for a 2D menu. Defaults to first field in a table.
|
30
|
+
# [*:action*] Turn menu into an action menu by letting user pass menu choices as an argument to a method/command.
|
31
|
+
# A menu choice's place amongst other arguments is preserved. Default is false.
|
32
|
+
# [*:multi_action*] Execute action menu multiple times iterating over the menu choices. Default is false.
|
33
|
+
# [*:action_object*] Object that takes method/command calls. Default is main.
|
34
|
+
# [*:command*] Default method/command to call when no command given.
|
35
|
+
# [*:reopen*] Reopens $stdin with given file or with /dev/tty when set to true. Use when
|
36
|
+
# $stdin is already reading in piped data.
|
37
|
+
# Examples:
|
38
|
+
# >> extend Hirb::Console
|
39
|
+
# => self
|
40
|
+
# >> menu [1,2,3], :prompt=> "So many choices, so little time: "
|
41
|
+
# >> menu [{:a=>1, :b=>2}, {:a=>3, :b=>4}], :fields=>[:a,b], :two_d=>true)
|
42
|
+
def self.render(output, options={}, &block)
|
43
|
+
new(options).render(output, &block)
|
44
|
+
rescue Error=>e
|
45
|
+
$stderr.puts "Error: #{e.message}"
|
46
|
+
end
|
47
|
+
|
48
|
+
#:stopdoc:
|
49
|
+
def initialize(options={})
|
50
|
+
@options = {:helper_class=>Hirb::Helpers::AutoTable, :prompt=>"Choose: ", :ask=>true,
|
51
|
+
:directions=>true}.merge options
|
52
|
+
@options[:reopen] = '/dev/tty' if @options[:reopen] == true
|
53
|
+
end
|
54
|
+
|
55
|
+
def render(output, &block)
|
56
|
+
@output = Array(output)
|
57
|
+
return [] if @output.size.zero?
|
58
|
+
chosen = choose_from_menu
|
59
|
+
block.call(chosen) if block && chosen.size > 0
|
60
|
+
@options[:action] ? execute_action(chosen) : chosen
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_input
|
64
|
+
prompt = pre_prompt + @options[:prompt]
|
65
|
+
prompt = DIRECTIONS+"\n"+prompt if @options[:directions]
|
66
|
+
$stdin.reopen @options[:reopen] if @options[:reopen]
|
67
|
+
|
68
|
+
if @options[:readline] && readline_loads?
|
69
|
+
get_readline_input(prompt)
|
70
|
+
else
|
71
|
+
print prompt
|
72
|
+
$stdin.gets.chomp.strip
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_readline_input(prompt)
|
77
|
+
input = Readline.readline prompt
|
78
|
+
Readline::HISTORY << input
|
79
|
+
input
|
80
|
+
end
|
81
|
+
|
82
|
+
def pre_prompt
|
83
|
+
prompt = ''
|
84
|
+
prompt << "Default field: #{default_field}\n" if @options[:two_d] && default_field
|
85
|
+
prompt << "Default command: #{@options[:command]}\n" if @options[:action] && @options[:command]
|
86
|
+
prompt
|
87
|
+
end
|
88
|
+
|
89
|
+
def choose_from_menu
|
90
|
+
return unasked_choice if @output.size == 1 && !@options[:ask]
|
91
|
+
|
92
|
+
if (Util.any_const_get(@options[:helper_class]))
|
93
|
+
View.render_output(@output, :class=>@options[:helper_class], :options=>@options.merge(:number=>true))
|
94
|
+
else
|
95
|
+
@output.each_with_index {|e,i| puts "#{i+1}: #{e}" }
|
96
|
+
end
|
97
|
+
|
98
|
+
parse_input get_input
|
99
|
+
end
|
100
|
+
|
101
|
+
def unasked_choice
|
102
|
+
return @output unless @options[:action]
|
103
|
+
raise(Error, "Default command and field required for unasked action menu") unless default_field && @options[:command]
|
104
|
+
@new_args = [@options[:command], CHOSEN_ARG]
|
105
|
+
map_tokens([[@output, default_field]])
|
106
|
+
end
|
107
|
+
|
108
|
+
def execute_action(chosen)
|
109
|
+
return nil if chosen.size.zero?
|
110
|
+
if @options[:multi_action]
|
111
|
+
chosen.each {|e| invoke command, add_chosen_to_args(e) }
|
112
|
+
else
|
113
|
+
invoke command, add_chosen_to_args(chosen)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def invoke(cmd, args)
|
118
|
+
action_object.send(cmd, *args)
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_input(input)
|
122
|
+
if (@options[:two_d] || @options[:action])
|
123
|
+
tokens = input_to_tokens(input)
|
124
|
+
map_tokens(tokens)
|
125
|
+
else
|
126
|
+
Util.choose_from_array(@output, input)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def map_tokens(tokens)
|
131
|
+
values = if return_cell_values?
|
132
|
+
@output[0].is_a?(Hash) ?
|
133
|
+
tokens.map {|arr,f| arr.map {|e| e[f]} } :
|
134
|
+
tokens.map {|arr,f|
|
135
|
+
arr.map {|e| e.is_a?(Array) && f.is_a?(Integer) ? e[f] : e.send(f) }
|
136
|
+
}
|
137
|
+
else
|
138
|
+
tokens.map {|arr, f| arr[0] }
|
139
|
+
end
|
140
|
+
values.flatten
|
141
|
+
end
|
142
|
+
|
143
|
+
def return_cell_values?
|
144
|
+
@options[:two_d]
|
145
|
+
end
|
146
|
+
|
147
|
+
def input_to_tokens(input)
|
148
|
+
@new_args = []
|
149
|
+
tokens = (@args = split_input_args(input)).map {|word| parse_word(word) }.compact
|
150
|
+
cleanup_new_args
|
151
|
+
tokens
|
152
|
+
end
|
153
|
+
|
154
|
+
def parse_word(word)
|
155
|
+
if word[CHOSEN_REGEXP]
|
156
|
+
@new_args << CHOSEN_ARG
|
157
|
+
field = $3 ? unalias_field($3) : default_field ||
|
158
|
+
raise(Error, "No default field/column found. Fields must be explicitly picked.")
|
159
|
+
|
160
|
+
token = Util.choose_from_array(@output, word)
|
161
|
+
token = [token] if word[/\*|-|\.\.|,/] && !return_cell_values?
|
162
|
+
[token, field]
|
163
|
+
else
|
164
|
+
@new_args << word
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def cleanup_new_args
|
170
|
+
if @new_args.all? {|e| e == CHOSEN_ARG }
|
171
|
+
@new_args = [CHOSEN_ARG]
|
172
|
+
else
|
173
|
+
i = @new_args.index(CHOSEN_ARG) || raise(Error, "No rows chosen")
|
174
|
+
@new_args.delete(CHOSEN_ARG)
|
175
|
+
@new_args.insert(i, CHOSEN_ARG)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def add_chosen_to_args(items)
|
180
|
+
args = @new_args.dup
|
181
|
+
args[args.index(CHOSEN_ARG)] = items
|
182
|
+
args
|
183
|
+
end
|
184
|
+
|
185
|
+
def command
|
186
|
+
@command ||= begin
|
187
|
+
cmd = (@new_args == [CHOSEN_ARG]) ? nil : @new_args.shift
|
188
|
+
cmd ||= @options[:command] || raise(Error, "No command given for action menu")
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def action_object
|
193
|
+
@options[:action_object] || eval("self", TOPLEVEL_BINDING)
|
194
|
+
end
|
195
|
+
|
196
|
+
def split_input_args(input)
|
197
|
+
input.split(/\s+/)
|
198
|
+
end
|
199
|
+
|
200
|
+
def default_field
|
201
|
+
@default_field ||= @options[:default_field] || fields[0]
|
202
|
+
end
|
203
|
+
|
204
|
+
# Has to be called after displaying menu
|
205
|
+
def fields
|
206
|
+
@fields ||= @options[:fields] || (@options[:ask] && table_helper_class? && Helpers::Table.last_table ?
|
207
|
+
Helpers::Table.last_table.fields[1..-1] : [])
|
208
|
+
end
|
209
|
+
|
210
|
+
def table_helper_class?
|
211
|
+
@options[:helper_class].is_a?(Class) && @options[:helper_class] < Helpers::Table
|
212
|
+
end
|
213
|
+
|
214
|
+
def unalias_field(field)
|
215
|
+
fields.sort_by {|e| e.to_s }.find {|e| e.to_s[/^#{field}/] } || raise(Error, "Invalid field '#{field}'")
|
216
|
+
end
|
217
|
+
|
218
|
+
def readline_loads?
|
219
|
+
require 'readline'
|
220
|
+
true
|
221
|
+
rescue LoadError
|
222
|
+
false
|
223
|
+
end
|
224
|
+
#:startdoc:
|
225
|
+
end
|
226
|
+
end
|