-
Notifications
You must be signed in to change notification settings - Fork 1
/
location.rb
109 lines (93 loc) · 2.3 KB
/
location.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
require './search_engine'
# Factory method for menu locations
module Location
def self.get(props, origin = nil, path = nil)
if props.is_a?(Array)
ArrayLocation.new(props, origin, path)
elsif props.is_a?(Hash)
HashLocation.new(props, origin, path)
else
raise "Unsupported location type #{props.class}"
end
end
end
# Menu location abstract class
class MenuLocation
attr_reader :props, :origin, :path
def initialize(props, origin = nil, path = nil)
@props = props
@origin = origin
@path = path
end
def select_from_menu(menu)
loop do
choice = Readline.readline("#{@path}> ", true)
choice.strip!
exit if %w[exit quit].include?(choice)
return choice if menu.include?(choice)
return '..' if choice == '..'
puts "ERROR: Incorrect choice \"#{choice}\""
end
end
def init_autocomplete(menu)
Readline.completion_proc = proc { |s| menu.grep(/^#{Regexp.escape(s)}/) }
end
end
# Hash menu location, allows to select one of the hash keys
class HashLocation < MenuLocation
def next
menu = props.keys.sort
usage(menu)
choice = select_from_menu(menu)
if props[choice]
Location.get(props[choice], self, choice)
else
self
end
end
def usage(menu)
puts
puts 'Select one of the following tables (press Tab for autocomplete):'
puts '-' * 3
puts menu
init_autocomplete(menu)
end
end
# Array location, performs O(N) search over model entries
class ArrayLocation < MenuLocation
include SearchEngine
def next
menu = props.first.props.keys
term = search_term(menu)
return origin if term == '..'
value = search_value(term)
return origin if value == '..'
print_results(
search(props, term, value)
)
self
end
private
def print_results(results)
if results.empty?
puts '(not found)'
return
end
puts "#{results.size} record(s) found:"
results.each do |result|
puts '=' * 40
puts result.as_text
end
end
def search_term(menu)
puts 'Enter search term (press Tab for autocomplete):'
init_autocomplete(menu)
select_from_menu(menu)
end
def search_value(suffix)
suffix = '.' + suffix if suffix
puts 'Enter search value:'
print "#{@path}#{suffix}> "
gets.chomp.strip
end
end