require "readline" require "yaml" command_tree = {"pet"=> {"buy"=>{"dog"=>nil, "cat"=>nil}, "sell"=>{"bird"=>nil, "fox"=>nil}, "sellGroup"=>{"pig"=>nil, "kingfisher"=>nil}, "list"=>{"all"=>nil, "filter_by"=>nil}}, "store"=> {"find"=>{"by_name"=>nil, "by_tag"=>nil, "by_address"=>nil}, "list"=>nil}, "user"=>{"login"=>nil, "logout"=>nil, "sign_up"=>nil}, "petGroup"=>{"login"=>nil, "loout"=>nil, "sign_up"=>nil}, } pp command_tree def get_current_option(command_tree, line_buffer) current_option = command_tree.keys commands = line_buffer.split commands.each_with_index do |command, i| # Don't go down to the lower level(and return current_option) in case current command matches two candidates such as "pet" and "petGroup" return current_option if i == commands.size-1 and !line_buffer.end_with?("\s") # Go down if command_tree.has_key?(command) if command_tree[command].nil? # invalid command or key at leaf current_option = [] else command_tree = command_tree[command] current_option = command_tree.keys end end end current_option end # Evaluate the proc when pressing comp = proc do |input| get_current_option(command_tree, Readline.line_buffer).select { |name| name.to_s.start_with?(input) } end Readline.completion_proc = comp #Readline.completion_append_character = " " while input = Readline.readline("$ ", true) break if input == "q" p Readline.line_buffer.split if !input.empty? end