How do I set a "gets" call with default input value? - ruby

If I have a gets.chomp statement, how do I set it such that the default input is a custom message?
favorite_ice_cream = gets.chomp(default_message) #I know this isn't valid Ruby syntax
=> Chocolate
I want to have the ability to edit the input string "chocolate" in the terminal before I enter it as user input.

There is no built in way to do this. You'll have to implement a thread to wait a fraction of a second to write to the STDIO (input) with your gets command in place and running. Other then that you'll just have to print it to the screen and have the person retype it.
I recommend the gem highline for user input. Instead of gets you can use ask and provide a default: ask("Company? ") { |q| q.default = "none" } which outputs Company? |none|. That lets you just hit the ENTER key for the default none to be used, or you can type (but not edit) a new entry.
With highline you won't have to use chomp.
But the answer to your question is to use threads to have an IO stream write to the input while gets is waiting for the input.

I found prompt.ask from tty-prompt fulfilled my need better than highline because it displays an editable default value:
$ gem install tty-prompt
$ irb
irb(main):001:0> require "tty-prompt"
=> true
irb(main):002:0> prompt = TTY::Prompt.new
=> #<TTY::Prompt prefix="" quiet=false enabled_color=nil active_color=:green
error_color=:red help_color=:bright_black input=#<IO:<ST...
irb(main):003:0> prompt.ask("What is your name?", default: ENV["USER"])
What is your name? xxx
=> "xxx"
irb(main):004:0> prompt.ask("What is your name?", value: "Mike")
What is your name? Michael
=> "Michael"

Related

How to allow users to edit given string via $stdin in ruby

I'm searching to allows users to edit an existing string.
Edit the following string: Edit me
# After user delete and add characters
Edit the following string: Edit you
I thought to prepend some data to the $stdin but seems like it's not possible and anyway IMHO it's a too radical solution.
Someone told me to use GNU Readline's Ruby wrapper so I've taken a quick look and I found Readline#pre_input_hook which acts before Readline start taking the input.
I tried:
require 'readline'
Readline.pre_input_hook = -> { "Edit me" }
result = Readline.readline("Edit the following string: ")
puts result
But seems not work.
begin
system("stty raw -echo")
print (acc = "Edit me: ")
loop.each_with_object(acc) do |_,acc|
sym = $stdin.getc
case sym.ord
when 13 # carriage return
break acc
when 127 # backspace
print "\e[1D \e[1D"
acc.slice!(acc.length - 1) if acc.length > 0
else # regular symbol
print sym
acc << sym
end
end
ensure
system("stty -raw echo")
puts
puts "\e[0mEntered: |#{acc}|"
end
Here you go. More info on terminal control sequences. Also, ANSI terminal codes.
I found prompt.ask from tty-prompt fulfilled my need:
$ gem install tty-prompt
$ irb
irb(main):001:0> require "tty-prompt"
=> true
irb(main):002:0> prompt = TTY::Prompt.new
=> #<TTY::Prompt prefix="" quiet=false enabled_color=nil active_color=:green
error_color=:red help_color=:bright_black input=#<IO:<ST...
irb(main):003:0> prompt.ask("What is your name?", default: ENV["USER"])
What is your name? xxx
=> "xxx"
irb(main):004:0> prompt.ask("What is your name?", value: "Mike")
What is your name? Michael
=> "Michael"

Programmatically Loading Libraries with a Ruby REPL

I've been trying to get load project libraries in a script, then start either IRB or ripl to allow the user to have quick interaction with project libraries. I've succeeded in doing this.
My issue is programmatically turning off command-line echo.
Manually, this is easy with a call to irb_context.echo = false, but this doesn't work programmatically since control is handed over to IRB at IRB.start and irb_context isn't available before the call to IRB.start
If you want IRB to write nothing when the user gives input, you can set the info manually:
IRB.conf[:PROMPT][:NO_REPLY] = {
:PROMPT_I => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "\n" # used to printf
}
IRB.conf[:PROMPT_MODE] = :NO_REPLY
This way, the return value will be ignored by the REPL, that will print just a newline. For more info, see the official docs.

Ruby: gets.chomp with default value

Is there some simple way how to ask for a user input in Ruby WHILE providing a default value?
Consider this code in bash:
function ask_q {
local PROMPT="$1"
local DEF_V="$2"
read -e -p "$PROMPT" -i "$DEF_V" REPLY
echo $REPLY
}
TEST=$(ask_q "Are you hungry?" "Yes")
echo "Answer was \"$TEST\"."
Can you achieve similar behaviour with Ruby's gets.chomp?
function ask_q(prompt, default="")
puts prompt
reply = gets.chomp() # ???
return reply
def
reply = ask_q("Are you hungry?", "Yes")
I understand I can sort replicate the functionality in Ruby this way ...
def ask_q(prompt, default="")
default_msg = (default.to_s.empty?) ? "" : "[default: \"#{default}\"]"
puts "${prompt} ${default}"
reply = gets.chomp()
reply = (default.to_s.empty?) ? default : reply
return reply
end
... but it does not seem very pretty. I also need to show the default value manually and the user needs to retype it in the prompt line, if he wants to use modified version of it (say yes! instead of yes).
I'm starting with Ruby now, so there may be a lot of syntax mistakes and I also may be missing something obvious ... Also, I googled a lot but surprisingly found no clue.
TL; DR
To make the question clearer, this is what you should see in terminal and what I am able to achieve in bash (and not in Ruby, so far):
### Terminal output of `reply=ask_q("Are you hungry?" "Yes")`
$ Are you hungry?
$ Yes # default editable value
### Terminal output of `reply=ask_q("What do you want to eat?")`
$ What do you want to eat?
$ # blank line waiting for user input, since there is no second parameter
And the actual situation: I am building bootstrap script for my web apps. I need to provide users with existing configuration data, that they can change if needed.
### Terminal output of `reply=ask_q("Define name of database." "CURR_DB_NAME")`
I don't think it's that fancy functionality, that would require switch to GUI app world.
And as I've said before, this is quite easily achievable in bash. Problem is, that other things are pure pain (associative arrays, no return values from functions, passing parameters, ...). I guess I just need to decide what sucks the least in my case ...
You need to do one of two things:
1) Create a gui program.
2) Use curses.
Personally, I think it's a waste of time to spend any time learning curses. Curses has even been removed from the Ruby Standard Library.
A GUI program:
Here is what a gui app looks like using the Tkinter GUI Framework:
def ask_q(prompt, default="")
require 'tk'
root = TkRoot.new
root.title = "Your Info"
#Display the prompt:
TkLabel.new(root) do
text "#{prompt}: "
pack("side" => "left")
end
#Create a textbox that displays the default value:
results_var = TkVariable.new
results_var.value = default
TkEntry.new(root) do
textvariable results_var
pack("side" => "left")
end
user_input = nil
#Create a button for the user to click to send the input to your program:
TkButton.new(root) do
text "OK"
command(Proc.new do
user_input = results_var.value
root.destroy
end)
pack("side" => "right", "padx"=> "50", "pady"=> "10")
end
Tk.mainloop
user_input
end
puts ask_q("What is your name", "Petr Cibulka")
Calling a function in a bash script from ruby:
.../bash_programs/ask_q.sh:
#!/usr/bin/env bash
function ask_q {
local QUESTION="$1"
local DEFAULT_ANSWER="$2"
local PROMPT="$QUESTION"
read -p "$PROMPT $DEFAULT_ANSWER" USERS_ANSWER #I left out the -i stuff, because it doesn't work for my version of bash
echo $USERS_ANSWER
}
ruby_prog.rb:
answer = %x{
source ../bash_programs/ask_q.sh; #When ask_q.sh is not in a directory in your $PATH, this allows the file to be seen.
ask_q 'Are you Hungry?' 'Yes' #Now you can call functions defined inside ask_q.sh
}
p answer.chomp #=> "Maybe"
Using curses:
require 'rbcurse/core/util/app'
def help_text
<<-eos
Enter as much help text
here as you want
eos
end
user_answer = "error"
App.new do #Ctrl+Q to terminate curses, or F10(some terminals don't process function keys)
#form.help_manager.help_text = help_text() #User can hit F1 to get help text (some terminals do not process function keys)
question = "Are You Hungry?"
default_answer = "Yes"
row_position = 1
column_position = 10
text_field = Field.new(#form).
name("textfield1").
label(question).
text(default_answer).
display_length(20).
bgcolor(:white).
color(:black).
row(row_position).
col(column_position)
text_field.cursor_end
text_field.bind_key(13, 'return') do
user_answer = text_field.text
throw :close
end
end
puts user_answer

Is it possible to configure the IRB prompt to change dynamically?

I'd like to navigate around the filesystem in IRB and have the prompt change to reflect the current working directory, but I can't figure out how to make the prompt update after each command. Ultimately I'd like to use IRB in day to day work a lot more and let bash slip away. I tried this in my .irbrc:
require 'fileutils'
include FileUtils
IRB.conf[:PROMPT][:CUSTOM] = {
:PROMPT_N => "\e[1m:\e[m ",
:PROMPT_I => "\e[1m#{pwd} >\e[m ",
:PROMPT_S => "FOO",
:PROMPT_C => "\e[1m#{pwd} >\e[m ",
:RETURN => ""
}
IRB.conf[:PROMPT_MODE] = :CUSTOM
But the IRB prompt is not updated:
julianmann#mango:~ > irb
/users/julianmann > puts pwd
/users/julianmann
/users/julianmann > cd 'dev'
/users/julianmann > puts pwd
/users/julianmann/dev
/users/julianmann >
I'd really like the prompt to change.
Here's a quick hack to get the working dir. It's sort of fragile, but it worked on ruby 1.8.7 and 1.9.2.
Set your prompt string to something like this:
"%N(%m):%03n:%i %~> ".tap {|s| def s.dup; gsub('%~', Dir.pwd); end }
The "%~" directive is not understood by irb itself, so I used it to do the replacement. This hack relies on the fact that irb calls dup to generate the prompt.
Another option is to use fresh. It's based on the irb alternative ripl and also shows the current directory as its prompt :]
You have to run(alias) irb like so
irb --prompt custom
Or alternatively add IRB.conf[:PROMPT_MODE] = :CUSTOM to your .irbrc
P.S. This isn't an EXACT answer to your question. But you might try using RUSH.
It doesn't have the concept of a current working directory, but it is easily configurable.
Its kind of static though
but have a look, it may help you
IN Linux ( Ubuntu 14.04)
You can change the irritating prompt of the irb console just by following some simple steps
Open your terminal
goto the location /home/leapfrog/.rvm/scripts
$ cd ~/.rvm/scripts
Open the file ‘irbrc.rb’, use superuser power to over-write the
$ sudo gedit irbrc.rb
You can see a portion of code like this. Replace the former with latter codes
# Set up the prompt to be RVM specific.
##prompt = {
# :PROMPT_I => "#{rvm_ruby_string} :%03n > ", # default prompt
# :PROMPT_S => "#{rvm_ruby_string} :%03n%l> ", # known continuation
# :PROMPT_C => "#{rvm_ruby_string} :%03n > ",
# :PROMPT_N => "#{rvm_ruby_string} :%03n?> ", # unknown continuation
# :RETURN => " => %s \n",
# :AUTO_INDENT => true
#}
#prompt = {
:PROMPT_I => "ROR: %03n > ", # default prompt
:PROMPT_S => "%03n%l> ", # known continuation
:PROMPT_C => "%03n > ",
:PROMPT_N => "%03n?> ", # unknown continuation
:RETURN => " O/P => %s \n",
:AUTO_INDENT => true
}
Just save the file and restart the irb console
Further mode you can see this link
https://cbabhusal.wordpress.com/2014/12/22/ruby-rvm-change-prompt-of-irb/
If it may serve to contribute to the discussion, albeit belatedly: It may be possible to change the prompt after the IRB environment is initialized, such as via some values on IRB.conf[:MAIN_CONTEXT]
For a binding of c = IRB.conf[:MAIN_CONTEXT] the fields affecting prompt formatting may include the following
c.prompt_c
c.prompt_i
c.prompt_n
c.prompt_s
c.return_format
c.auto_indent_mode
c.prompt_mode
An example in updating the prompt_i field directly:
irb(main):009:0> IRB.conf[:MAIN_CONTEXT].prompt_i="%N %m %i >>"
=> "%N %m %i >>"
irb main 0 >>
Outside of the set of formatting specifiers documented in the IRB module documentation (3.0.0) it may not be supported - at present - to use an expression that would be evaluated when the prompt is displayed, in IRB. Each of the prompt strings may be used as simply a literal format string.
With some limitations albeit, but it may be possible to update the IRB prompt after IRB is initialized.
Disclaimer: This is not guaranteed to update all state values related to the prompt, under IRB.conf[:MAIN_CONTEXT]

What's the difference between the ruby irb prompt modes?

I can change the irb prompt mode with
irb --prompt prompt-mode
I can see what null and simple does, but I can't tell the difference between null and xmp and the difference between default/classic/inf-ruby. Can someone explain to me what these other modes do? It seems pointless to have multiple modes doing the same thing.
Once you read the article cldwalker posted above, you may want to design a custom prompt, here's mine for example:
IRB.conf[:PROMPT][:CUSTOM] = {
:PROMPT_I => ">> ",
:PROMPT_S => "%l>> ",
:PROMPT_C => ".. ",
:PROMPT_N => ".. ",
:RETURN => "=> %s\n"
}
IRB.conf[:PROMPT_MODE] = :CUSTOM
IRB.conf[:AUTO_INDENT] = true
The answer to those questions lie in IRB.conf[:PROMPT] which is a hash whose keys are the different prompts and whose values are the configurations for each prompt. Read this to a understand a prompt's configuration.
The difference between null and xmp is that xmp displays a result indented with an arrow:
$ irb --prompt xmp -f
2**10
==>1024
while null doesn't indent or display the arrow:
$ irb --prompt null -f
2**10
1024
You should be able to answer your second question once you read the above link and understand that prompts have different modes and different configurations for them.

Resources