Command-line interface helpers? - ruby

I am working on a command-line interface to make my code more user-friendly. It currently looks like this:
loop do
print "> "
cmd = gets.chomp
break if cmd == "quit"
run_command(cmd)
puts
end
I would like to extend it a little bit to save typing. For example, I'd like to allow using the "Up Arrow" key to repeat the last command, and the "Tab" key to auto-match command etc.
Is there any tool to ease the job?

You're probably looking for readline, here's an example:
require "readline"
while cmd = Readline.readline("> ", true)
break if cmd == "quit"
run_command(cmd)
puts
end
Tab-completion is a little trickier, though. Have a look at the example on their documentation page.

The library you are looking for is readline

Related

How to use a conditional within a Ruby expect script

I'm playing with expect in Ruby but I'm a little lost as to how I can branch my code based on the behavior of a device I am logging into. How could I do say foo.run if I get the correct prompt below > but run foo.fail if I do not? Even further, how can I evaluate all of the text that comes back between entering the password and receiving the > prompt? Is there a way to look at all text that the device prints somehow?
def device_test(password)
$expect_verbose = true
PTY.spawn("ssh my-router") do |reader, writer, pid|
reader.expect("password:")
writer.puts(password)
reader.expect(">")
puts "logged in"
sleep(15)
end
end
It appears that the expect method can only look for a single pattern (unlike the Tcl expect library where you can look for multiple patterns simultaneously).
It looks like you'll have to pass a "timeout" parameter and check the return value:
if reader.expect(">", 2)
puts "foo.run"
else
# did not see ">" within 2 seconds
puts "foo.fail
end

Change Bash terminal output color while running a Ruby script

I'd like to briefly change my terminal output color, run a Ruby script so that standard output prints in that changed color, 'sleep' for a second, and then change it back. I know how to set colors, like for the prompt:
PS1="\e[0;36m[\w] \e[m "
I imagine I need to write a Bash function to do this. What would that look like?
Here is a Ruby script to show all the terminal colors. Download it or run the code below.
def color(index)
normal = "\e[#{index}m#{index}\e[0m"
bold = "\e[#{index}m\e[1m#{index}\e[0m"
"#{normal} #{bold} "
end
8.times do|index|
line = color(index + 1)
line += color(index + 30)
line += color(index + 90)
line += color(index + 40)
line += color(index + 100)
puts line
end
You can do it within Ruby (assuming you're on Linux; Windows requires a library/gem whose name I can't remember at the moment) using the normal codes you would use in bash, e.g.
puts "\e[31m etc Your text here."
To reset to normal display:
puts "\e[0m"
Adjust to taste.
You can also use the Term Ansicolor gem to change it from inside a running script.
http://flori.github.io/term-ansicolor/
One may also use the Colorize gem.
Installation:
sudo gem install colorize
Usage:
require 'colorize'
puts "I am now red.".red
puts "I am now blue.".green
puts "I am a super coder".yellow
This answer is copied from How can I use Ruby to colorize the text output to a terminal?.

Creating interactive ruby console application

I want make interactive application where user launches it and can do various task by typing commands (some kind of shell)
example:
./myapp.rb
App says Hi
Commands:
help - display help about command
open - open task
do - do action
Start>help open
open <TaskName>
opens specified task
Start>open Something
Something>do SomeAction
Success!
Something> (blinking cursor here)
I searched but couldn't find any ruby gems that I could use specially for console interaction, so I'm about to my make my own...
I looked at Thor, but that's not exactly as I want, maybe I could use it, but not sure...
it could look something like:
class Tasks
attr_reader :opened_task
desc "open <TaskName>", "opens specified task"
def open(params)
end
desc "do <ActionName>", "do specified action"
def do(params)
end
end
tasks = Tasks.new
# theoretical Console class
console = Console.new
console.addCommand("open",tasks.method(:open),"open task")
console.addCommand("do",tasks.method(:do),"do action")
console.start("%s>",[*tasks.opened_task])
so my question is, what gems I could use to make such console class? maybe someone have already made something similar?
I plan using HighLine for input/output, but any other suggestion what could I use?
What you want is a REPL – Read → Evaluate → Print Loop.
IRB, for example, implements a REPL for the Ruby language.
Here's a very simple implementation of your application's REPL:
loop do
Application::Console.prompt.display
input = gets.chomp
command, *params = input.split /\s/
case command
when /\Ahelp\z/i
puts Application::Console.help_text
when /\Aopen\z/i
Application::Task.open params.first
when /\Ado\z/i
Application::Action.perform *params
else puts 'Invalid command'
end
end
\A and \z match the start of the string and the end of the string, respectively.
You could also try ripl. (from the documentation):
Creating and starting a custom shell is as simple as:
require 'ripl'
# Define plugins, load files, etc...
Ripl.start
There is a comprehensive list of plugins for ripl as well as list of console applications using ripl on the projects website.
ok, so I made this library for creating console applications in ruby. Actually it was some while ago, but only just decided to release it. It does support auto-completion if used with HighLine and Readline.
When I wrote it there wasn't any documentation nor tests/specs, but now I made some. Still not much but for beginning should be ok.
So gem cli-console and
code is at GitHub, here's usage example
TTY is a really good gem for easily doing this sort of things. You have plenty of tools which can work alone or with the full toolKit. You can use colors, prompts, execute shell natives, interact with the screen, print tables, progressbars and many other useful elements of command lines whith the easy of a goop api.
Particularly tty-prompt is really useful for asking for user input.
A brief example for the case you proposed:
require 'tty-prompt'
require 'pastel'
prompt = TTY::Prompt.new
loop do
cmd, parms* = prompt.ask('user#machine$ ').split /\s/
case cmd
when "hola"
puts "Hola amigo " parms
when "exit"
break if prompt.yes?('Do you really want to exit?')
end
end
Take a look at cliqr ruby gem. It looks like exactly what you need. Here is the github link with a descriptive readme: https://github.com/anshulverma/cliqr
It can execute the commands directly or within a inbuilt shell.
Here is a test case from its git repo:
it 'can execute a sub action from shell' do
cli = Cliqr.interface do
name 'my-command'
handler do
puts 'base command executed'
end
action :foo do
handler do
puts 'foo executed'
end
action :bar do
handler do
puts 'bar executed'
end
end
end
end
with_input(['', 'my-command', 'foo', 'foo bar', 'foo bar help']) do
result = cli.execute %w(my-command shell), output: :buffer
expect(result[:stdout]).to eq <<-EOS
Starting shell for command "my-command"
my-command > .
base command executed
my-command > my-command.
base command executed
my-command > foo.
foo executed
my-command > foo bar.
bar executed
my-command > foo bar help.
my-command foo bar
USAGE:
my-command foo bar [actions] [options] [arguments]
Available options:
--help, -h : Get helpful information for action "my-command foo bar" along with its usage information.
Available actions:
[ Type "my-command foo bar help [action-name]" to get more information about that action ]
help -- The help action for command "my-command foo bar" which provides details and usage information on how to use the command.
my-command > exit.
shell exited with code 0
EOS
end
end
class MyAPI
def self.__is__(text)
#__is__ = text
end
def self.method_added(method)
#__help__ ||= {}
#__help__[method.to_s] = #__is__
#__is__ = nil
end
def self.help(of)
#__help__[of]
end
__is__ "open file <file>"
def open(file)
#...
end
__is__ "do X"
def do(*params)
#...
end
__is__ "calls help, use help <command>"
def help(*args, &block)
self.class.help(*args, &block)
end
end
MyAPI.new(...).pry
Or you could use pry commands, but that defeats the
turing-completeness. Help might be implemented using commands, as I'm
not sure how well my approach works out. Those methods need to be
coded defensive. I can't remember how to use class variables :-/

How to make a ruby command line application with pager?

I'm making a command line tool using Ruby. It will print a lot of text on screen. Currently, I'm using shell pipeline (may_app | more) to do so. But I think it's better to has a default pager.
It's just like what you see when execute git log . One can disable pager by using git --nopager log.
I've done quite much google work and find one gem: hirb , but it seems a little overkill.
After many tries, I'm current using shell wrapper to do so:
#!/bin/bash
# xray.rb is the core script
# doing the main logic and will
# output many rows of text on
# screen
XRAY=$HOME/fdev-xray/xray.rb
if [ "--nopager" == "$1" ]; then
shift
$XRAY $*
else
$XRAY $* | more
fi
It works. But is there a better way?
You are doing it right. But instead using more you'd better get a pager from $PAGER environment variable, if any.
Some people prefer less to more for example, and others have their favorite parser options set in this var.
You can use the pipe in Ruby via a call to system and provide the options (along with a nice help interface) like so:
require 'optparse'
pager = ENV['PAGER'] || 'more'
option_parser = OptionParser.new do |opts|
opts.on("--[no-]pager",
"[don't] page output using #{pager} (default on)") do |use_pager|
pager = nil unless use_pager
end
end
option_parser.parse!
command = "cat #{ARGV[0]}"
command += " | #{pager}" unless pager.nil?
unless system(command)
STDERR.puts "Problem running #{command}"
exit 1
end
Now, you support --pager and --no-pager on the command line, which is nice to do.

How to view/save/load work space in ruby's interactive mode

I need an interactive environment to play with some algorithm stuff. I want to be able to view what's been defined (data, function) so far and be able save/load so I can continue from a previous saved snapshot if something went wrong. Since I chose ruby as my main scripting language, I hope it had these features built in.
If ruby interactive mode does not provide these functionality, what else you recommend for that?
Thanks
So here’s a technique that will append commands entered in your IRB session to a file in your home directory (idea from ruby-talk:58931). Put the following in your .irbrc:
module Readline
module History
LOG = "#{ENV['HOME']}/.irb-history"
def self.write_log(line)
File.open(LOG, 'ab') {|f| f << "#{line}
"}
end
def self.start_session_log
write_log("
# session start: #{Time.now}
")
at_exit { write_log("
# session stop: #{Time.now}
") }
end
end
alias :old_readline :readline
def readline(*args)
ln = old_readline(*args)
begin
History.write_log(ln)
rescue
end
ln
end
end
Readline::History.start_session_log
You should check out the sketches gem which let's you prototype code in a temporary file in your preferred editor. I don't think it supports snapshots.
In irb I would use it as follows:
>> sketch
# Write some code in an editor ...
# Lists sketches and their code
>> sketches
# Reopens the first sketch from above
>> sketch 1
If you want a more powerful interactive prototyping environment, see boson.

Resources